diff options
Diffstat (limited to 'vendor/github.com/mdlayher/netlink/conn_linux.go')
-rw-r--r-- | vendor/github.com/mdlayher/netlink/conn_linux.go | 57 |
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 @@ | |||
3 | package netlink | 3 | package netlink |
4 | 4 | ||
5 | import ( | 5 | import ( |
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. |
340 | func newSysSocket(config *Config) (*sysSocket, error) { | 341 | func 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. | ||
613 | func 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. |
618 | type lockedNetNSGoroutine struct { | 636 | type 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. |
627 | func newLockedNetNSGoroutine(netNS int, getNS func() (*netNS, error)) (*lockedNetNSGoroutine, error) { | 645 | func 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. |