diff --git a/interface.go b/interface.go index 01efd82b..df615617 100644 --- a/interface.go +++ b/interface.go @@ -353,8 +353,7 @@ func (f *Interface) listenOut(i int) { nb := make([]byte, 12, 12) listener := func(fromUdpAddr netip.AddrPort, payload []byte, meta udp.RxMeta) { - plaintext := f.batchers[i].Reserve(len(payload)) - f.readOutsidePackets(ViaSender{UdpAddr: fromUdpAddr}, plaintext[:0], payload, h, fwPacket, lhh, nb, i, ctCache.Get(), meta) + f.readOutsidePackets(ViaSender{UdpAddr: fromUdpAddr}, payload, h, fwPacket, lhh, nb, i, ctCache.Get(), meta) } flusher := func() { diff --git a/overlay/tio/queueset_poll_linux.go b/overlay/tio/queueset_poll_linux.go index ab967df4..016baf6d 100644 --- a/overlay/tio/queueset_poll_linux.go +++ b/overlay/tio/queueset_poll_linux.go @@ -48,11 +48,15 @@ func (c *pollQueueSet) Add(fd int) error { func (c *pollQueueSet) wakeForShutdown() error { var buf [8]byte binary.NativeEndian.PutUint64(buf[:], 1) - _, err := unix.Write(int(c.shutdownFd), buf[:]) + _, err := unix.Write(c.shutdownFd, buf[:]) return err } func (c *pollQueueSet) Close() error { + if c.shutdownFd < 0 { + return nil + } + errs := []error{} if err := c.wakeForShutdown(); err != nil { @@ -65,5 +69,12 @@ func (c *pollQueueSet) Close() error { } } + // All Polls reference shutdownFd in their pollfd arrays, so close it + // only after every Poll.Close has returned. + if err := unix.Close(c.shutdownFd); err != nil { + errs = append(errs, err) + } + c.shutdownFd = -1 + return errors.Join(errs...) } diff --git a/overlay/tio/tio.go b/overlay/tio/tio.go index 2d94c764..c25ab059 100644 --- a/overlay/tio/tio.go +++ b/overlay/tio/tio.go @@ -117,7 +117,8 @@ func QueueCapabilities(q Queue) Capabilities { type GSOProto uint8 const ( - GSOProtoTCP GSOProto = iota + GSOProtoNone GSOProto = iota + GSOProtoTCP GSOProtoUDP ) diff --git a/overlay/tio/tun_file_linux_test.go b/overlay/tio/tun_file_linux_test.go index f92f58ec..41fe32e5 100644 --- a/overlay/tio/tun_file_linux_test.go +++ b/overlay/tio/tun_file_linux_test.go @@ -80,3 +80,24 @@ func TestPoll_Close_Idempotent(t *testing.T) { t.Fatalf("second Close should be a no-op, got %v", err) } } + +func TestPollQueueSet_Close_ClosesEventfd(t *testing.T) { + qs, err := NewPollQueueSet() + require.NoError(t, err) + require.NoError(t, qs.Add(newReadPipe(t))) + + fd := qs.(*pollQueueSet).shutdownFd + require.NoError(t, qs.Close()) + + // Closing the eventfd again should fail with EBADF, proving Close + // actually released it. + if err := unix.Close(fd); err == nil { + t.Fatalf("eventfd %d still open after QueueSet.Close", fd) + } + + // Second Close must be a no-op (and must not double-close the eventfd + // in case the kernel handed it out to another caller in the meantime). + if err := qs.Close(); err != nil { + t.Fatalf("second Close: %v", err) + } +}