aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/mdlayher/netlink/conn_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mdlayher/netlink/conn_linux.go')
-rw-r--r--vendor/github.com/mdlayher/netlink/conn_linux.go57
1 files changed, 44 insertions, 13 deletions
diff --git a/vendor/github.com/mdlayher/netlink/conn_linux.go b/vendor/github.com/mdlayher/netlink/conn_linux.go
index 7ac144c..61af3a2 100644
--- a/vendor/github.com/mdlayher/netlink/conn_linux.go
+++ b/vendor/github.com/mdlayher/netlink/conn_linux.go
@@ -3,6 +3,7 @@
3package netlink 3package netlink
4 4
5import ( 5import (
6 "errors"
6 "math" 7 "math"
7 "os" 8 "os"
8 "runtime" 9 "runtime"
@@ -339,7 +340,7 @@ type sysSocket struct {
339// to a single thread. 340// to a single thread.
340func newSysSocket(config *Config) (*sysSocket, error) { 341func newSysSocket(config *Config) (*sysSocket, error) {
341 // Determine network namespaces using the threadNetNS function. 342 // Determine network namespaces using the threadNetNS function.
342 g, err := newLockedNetNSGoroutine(config.NetNS, threadNetNS) 343 g, err := newLockedNetNSGoroutine(config.NetNS, threadNetNS, !config.DisableNSLockThread)
343 if err != nil { 344 if err != nil {
344 return nil, err 345 return nil, err
345 } 346 }
@@ -542,13 +543,8 @@ func (s *sysSocket) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Socka
542 doErr := s.read(func(fd int) bool { 543 doErr := s.read(func(fd int) bool {
543 n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags) 544 n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags)
544 545
545 // When the socket is in non-blocking mode, we might see 546 // Check for readiness.
546 // EAGAIN and end up here. In that case, return false to 547 return ready(err)
547 // let the poller wait for readiness. See the source code
548 // for internal/poll.FD.RawRead for more details.
549 //
550 // If the socket is in blocking mode, EAGAIN should never occur.
551 return err != syscall.EAGAIN
552 }) 548 })
553 if doErr != nil { 549 if doErr != nil {
554 return 0, 0, 0, nil, doErr 550 return 0, 0, 0, nil, doErr
@@ -562,8 +558,8 @@ func (s *sysSocket) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error {
562 doErr := s.write(func(fd int) bool { 558 doErr := s.write(func(fd int) bool {
563 err = unix.Sendmsg(fd, p, oob, to, flags) 559 err = unix.Sendmsg(fd, p, oob, to, flags)
564 560
565 // Analogous to Recvmsg. See the comments there. 561 // Check for readiness.
566 return err != syscall.EAGAIN 562 return ready(err)
567 }) 563 })
568 if doErr != nil { 564 if doErr != nil {
569 return doErr 565 return doErr
@@ -613,6 +609,28 @@ func (s *sysSocket) SetSockoptSockFprog(level, opt int, fprog *unix.SockFprog) e
613 return err 609 return err
614} 610}
615 611
612// ready indicates readiness based on the value of err.
613func ready(err error) bool {
614 // When a socket is in non-blocking mode, we might see
615 // EAGAIN. In that case, return false to let the poller wait for readiness.
616 // See the source code for internal/poll.FD.RawRead for more details.
617 //
618 // Starting in Go 1.14, goroutines are asynchronously preemptible. The 1.14
619 // release notes indicate that applications should expect to see EINTR more
620 // often on slow system calls (like recvmsg while waiting for input), so
621 // we must handle that case as well.
622 //
623 // If the socket is in blocking mode, EAGAIN should never occur.
624 switch err {
625 case syscall.EAGAIN, syscall.EINTR:
626 // Not ready.
627 return false
628 default:
629 // Ready whether there was error or no error.
630 return true
631 }
632}
633
616// lockedNetNSGoroutine is a worker goroutine locked to an operating system 634// lockedNetNSGoroutine is a worker goroutine locked to an operating system
617// thread, optionally configured to run in a non-default network namespace. 635// thread, optionally configured to run in a non-default network namespace.
618type lockedNetNSGoroutine struct { 636type lockedNetNSGoroutine struct {
@@ -624,10 +642,16 @@ type lockedNetNSGoroutine struct {
624// newLockedNetNSGoroutine creates a lockedNetNSGoroutine that will enter the 642// newLockedNetNSGoroutine creates a lockedNetNSGoroutine that will enter the
625// specified network namespace netNS (by file descriptor), and will use the 643// specified network namespace netNS (by file descriptor), and will use the
626// getNS function to produce netNS handles. 644// getNS function to produce netNS handles.
627func newLockedNetNSGoroutine(netNS int, getNS func() (*netNS, error)) (*lockedNetNSGoroutine, error) { 645func newLockedNetNSGoroutine(netNS int, getNS func() (*netNS, error), lockThread bool) (*lockedNetNSGoroutine, error) {
628 // Any bare syscall errors (e.g. setns) should be wrapped with 646 // Any bare syscall errors (e.g. setns) should be wrapped with
629 // os.NewSyscallError for the remainder of this function. 647 // os.NewSyscallError for the remainder of this function.
630 648
649 // If the caller has instructed us to not lock OS thread but also attempts
650 // to set a namespace, return an error.
651 if !lockThread && netNS != 0 {
652 return nil, errors.New("netlink Conn attempted to set a namespace with OS thread locking disabled")
653 }
654
631 callerNS, err := getNS() 655 callerNS, err := getNS()
632 if err != nil { 656 if err != nil {
633 return nil, err 657 return nil, err
@@ -660,9 +684,16 @@ func newLockedNetNSGoroutine(netNS int, getNS func() (*netNS, error)) (*lockedNe
660 // with the Go runtime for threads which are not unlocked, we have 684 // with the Go runtime for threads which are not unlocked, we have
661 // elected to temporarily unlock the thread when the goroutine terminates: 685 // elected to temporarily unlock the thread when the goroutine terminates:
662 // https://github.com/golang/go/issues/25128#issuecomment-410764489. 686 // https://github.com/golang/go/issues/25128#issuecomment-410764489.
687 //
688 // Locking the thread is not implemented if the caller explicitly asks
689 // for an unlocked thread.
690
691 // Only lock the tread, if the lockThread is set.
692 if lockThread {
693 runtime.LockOSThread()
694 defer runtime.UnlockOSThread()
695 }
663 696
664 runtime.LockOSThread()
665 defer runtime.UnlockOSThread()
666 defer g.wg.Done() 697 defer g.wg.Done()
667 698
668 // Get the current namespace of the thread the goroutine is locked to. 699 // Get the current namespace of the thread the goroutine is locked to.