diff options
Diffstat (limited to 'pkg/tcpip/link/fdbased')
-rw-r--r-- | pkg/tcpip/link/fdbased/endpoint.go | 57 | ||||
-rw-r--r-- | pkg/tcpip/link/fdbased/endpoint_test.go | 6 |
2 files changed, 36 insertions, 27 deletions
diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index 84439a9ed..6354688e2 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -136,10 +136,9 @@ type Options struct { // // Makes fd non-blocking, but does not take ownership of fd, which must remain // open for the lifetime of the returned endpoint. -func New(opts *Options) tcpip.LinkEndpointID { +func New(opts *Options) (tcpip.LinkEndpointID, error) { if err := syscall.SetNonblock(opts.FD, true); err != nil { - // TODO : replace panic with an error return. - panic(fmt.Sprintf("syscall.SetNonblock(%v) failed: %v", opts.FD, err)) + return 0, fmt.Errorf("syscall.SetNonblock(%v) failed: %v", opts.FD, err) } caps := stack.LinkEndpointCapabilities(0) @@ -175,27 +174,34 @@ func New(opts *Options) tcpip.LinkEndpointID { packetDispatchMode: opts.PacketDispatchMode, } - if opts.GSOMaxSize != 0 && isSocketFD(opts.FD) { - e.caps |= stack.CapabilityGSO - e.gsoMaxSize = opts.GSOMaxSize + // For non-socket FDs we read one packet a time (e.g. TAP devices). + msgsPerRecv := 1 + e.inboundDispatcher = e.dispatch + + isSocket, err := isSocketFD(opts.FD) + if err != nil { + return 0, err } - if isSocketFD(opts.FD) && e.packetDispatchMode == PacketMMap { - if err := e.setupPacketRXRing(); err != nil { - // TODO: replace panic with an error return. - panic(fmt.Sprintf("e.setupPacketRXRing failed: %v", err)) + if isSocket { + if opts.GSOMaxSize != 0 { + e.caps |= stack.CapabilityGSO + e.gsoMaxSize = opts.GSOMaxSize } - e.inboundDispatcher = e.packetMMapDispatch - return stack.RegisterLinkEndpoint(e) - } - // For non-socket FDs we read one packet a time (e.g. TAP devices) - msgsPerRecv := 1 - e.inboundDispatcher = e.dispatch - // If the provided FD is a socket then we optimize packet reads by - // using recvmmsg() instead of read() to read packets in a batch. - if isSocketFD(opts.FD) && e.packetDispatchMode == RecvMMsg { - e.inboundDispatcher = e.recvMMsgDispatch - msgsPerRecv = MaxMsgsPerRecv + switch e.packetDispatchMode { + case PacketMMap: + if err := e.setupPacketRXRing(); err != nil { + return 0, fmt.Errorf("e.setupPacketRXRing failed: %v", err) + } + e.inboundDispatcher = e.packetMMapDispatch + return stack.RegisterLinkEndpoint(e), nil + + case RecvMMsg: + // If the provided FD is a socket then we optimize packet reads by + // using recvmmsg() instead of read() to read packets in a batch. + e.inboundDispatcher = e.recvMMsgDispatch + msgsPerRecv = MaxMsgsPerRecv + } } e.views = make([][]buffer.View, msgsPerRecv) @@ -217,16 +223,15 @@ func New(opts *Options) tcpip.LinkEndpointID { e.msgHdrs[i].Msg.Iovlen = uint64(iovLen) } - return stack.RegisterLinkEndpoint(e) + return stack.RegisterLinkEndpoint(e), nil } -func isSocketFD(fd int) bool { +func isSocketFD(fd int) (bool, error) { var stat syscall.Stat_t if err := syscall.Fstat(fd, &stat); err != nil { - // TODO : replace panic with an error return. - panic(fmt.Sprintf("syscall.Fstat(%v,...) failed: %v", fd, err)) + return false, fmt.Errorf("syscall.Fstat(%v,...) failed: %v", fd, err) } - return (stat.Mode & syscall.S_IFSOCK) == syscall.S_IFSOCK + return (stat.Mode & syscall.S_IFSOCK) == syscall.S_IFSOCK, nil } // Attach launches the goroutine that reads packets from the file descriptor and diff --git a/pkg/tcpip/link/fdbased/endpoint_test.go b/pkg/tcpip/link/fdbased/endpoint_test.go index ecc5b73f3..5a06c6387 100644 --- a/pkg/tcpip/link/fdbased/endpoint_test.go +++ b/pkg/tcpip/link/fdbased/endpoint_test.go @@ -68,7 +68,11 @@ func newContext(t *testing.T, opt *Options) *context { } opt.FD = fds[1] - ep := stack.FindLinkEndpoint(New(opt)).(*endpoint) + epID, err := New(opt) + if err != nil { + t.Fatalf("Failed to create FD endpoint: %v", err) + } + ep := stack.FindLinkEndpoint(epID).(*endpoint) c := &context{ t: t, |