JackDoan hace 3 meses
padre
commit
c8bad57943
Se han modificado 2 ficheros con 19 adiciones y 108 borrados
  1. 0 62
      udp/raw_sendmmsg_linux.go
  2. 19 46
      udp/udp_linux.go

+ 0 - 62
udp/raw_sendmmsg_linux.go

@@ -1,62 +0,0 @@
-//go:build !android && !e2e_testing
-// +build !android,!e2e_testing
-
-package udp
-
-import (
-	"net"
-	"syscall"
-	"unsafe"
-
-	"golang.org/x/sys/unix"
-)
-
-// rawSendmmsg performs sendmmsg(2) over a syscall.RawConn without
-// allocating a closure per call. The struct holds preallocated in/out
-// scratch (chunk/sent/errno) and a method-value bound at construction so
-// rawConn.Write receives a stable function pointer instead of a fresh
-// closure on every send.
-type rawSendmmsg struct {
-	msgs     []rawMessage
-	chunk    int
-	sent     int
-	errno    syscall.Errno
-	callback func(fd uintptr) bool
-}
-
-// bind wires r.callback to r.run. Must be called once after r.msgs is set;
-// subsequent send calls invoke r.callback without rebinding.
-func (r *rawSendmmsg) bind() { r.callback = r.run }
-
-// run is the preallocated callback rawConn.Write invokes. It reads its
-// input (r.chunk) and writes its outputs (r.sent, r.errno) through the
-// rawSendmmsg fields so the method value does not capture per-call locals
-// and therefore does not heap-allocate.
-func (r *rawSendmmsg) run(fd uintptr) bool {
-	r1, _, errno := unix.Syscall6(unix.SYS_SENDMMSG, fd,
-		uintptr(unsafe.Pointer(&r.msgs[0])), uintptr(r.chunk),
-		0, 0, 0,
-	)
-	if errno == syscall.EAGAIN || errno == syscall.EWOULDBLOCK {
-		return false
-	}
-	r.sent = int(r1)
-	r.errno = errno
-	return true
-}
-
-// send issues sendmmsg over rc against the first n entries of r.msgs.
-// Returns the number of entries the kernel processed and any error;
-// matches the original sendmmsg helper's contract.
-func (r *rawSendmmsg) send(rc syscall.RawConn, n int) (int, error) {
-	r.chunk = n
-	r.sent = 0
-	r.errno = 0
-	if err := rc.Write(r.callback); err != nil {
-		return r.sent, err
-	}
-	if r.errno != 0 {
-		return r.sent, &net.OpError{Op: "sendmmsg", Err: r.errno}
-	}
-	return r.sent, nil
-}

+ 19 - 46
udp/udp_linux.go

@@ -50,10 +50,6 @@ type StdConn struct {
 	// into mmsghdr entry e. Used to rewind `i` on partial sendmmsg success.
 	writeEntryEnd []int
 
-	// rawSend wraps the sendmmsg(2) callback in a closure-free helper so
-	// the hot path doesn't heap-allocate a fresh closure per call.
-	rawSend rawSendmmsg
-
 	// UDP GSO (sendmsg with UDP_SEGMENT cmsg) support. gsoSupported is
 	// probed once at socket creation. When true, WriteBatch packs same-
 	// destination consecutive packets into a single sendmmsg entry with a
@@ -115,8 +111,6 @@ func NewListener(l *slog.Logger, ip netip.Addr, port int, multi bool, batch int)
 	out := &StdConn{sysFd: fd, isV4: ip.Is4(), l: l, batch: batch}
 
 	out.prepareWriteMessages(MaxWriteBatch)
-	out.rawSend.msgs = out.writeMsgs
-	out.rawSend.bind()
 
 	out.prepareGSO()
 	// GRO delivers coalesced superpackets that need a cmsg to split back
@@ -203,19 +197,11 @@ const maxGSOBytes = 65000
 func (u *StdConn) prepareGSO() {
 	u.maxGSOSegments = 63 //gotta be one less than the max so we can still attach a header
 
-	var probeErr error
-	if err := u.rawConn.Control(func(fd uintptr) {
-		probeErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_SEGMENT, 0)
-	}); err != nil {
+	if err := unix.SetsockoptInt(u.sysFd, unix.IPPROTO_UDP, unix.UDP_SEGMENT, 0); err != nil {
 		u.l.Info("udp: GSO disabled", "reason", "rawconn control failed", "error", err)
 		recordCapability("udp.gso.enabled", false)
 		return
 	}
-	if probeErr != nil {
-		u.l.Info("udp: GSO disabled", "reason", "kernel rejected probe", "error", probeErr)
-		recordCapability("udp.gso.enabled", false)
-		return
-	}
 
 	var un unix.Utsname
 	if err := unix.Uname(&un); err != nil {
@@ -262,16 +248,9 @@ const udpGROCmsgPayload = 4
 // datagrams into one recvmmsg entry, with a cmsg carrying the gso_size used
 // to split them back apart on the application side.
 func (u *StdConn) prepareGRO() {
-	var probeErr error
-	if err := u.rawConn.Control(func(fd uintptr) {
-		probeErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_GRO, 1)
-	}); err != nil {
-		u.l.Info("udp: GRO disabled", "reason", "rawconn control failed", "error", err)
-		recordCapability("udp.gro.enabled", false)
-		return
-	}
-	if probeErr != nil {
-		u.l.Info("udp: GRO disabled", "reason", "kernel rejected probe", "error", probeErr)
+	err := unix.SetsockoptInt(u.sysFd, unix.IPPROTO_UDP, unix.UDP_GRO, 1)
+	if err != nil {
+		u.l.Info("udp: GRO disabled", "reason", "kernel rejected probe", "error", err)
 		recordCapability("udp.gro.enabled", false)
 		return
 	}
@@ -287,15 +266,10 @@ func (u *StdConn) prepareGRO() {
 // Best-effort: we keep going on failure.
 func (u *StdConn) prepareECNRecv() {
 	var v4err, v6err error
-	if err := u.rawConn.Control(func(fd uintptr) {
-		v4err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_RECVTOS, 1)
-		if !u.isV4 {
-			v6err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
-		}
-	}); err != nil {
-		u.l.Info("udp: outer-ECN RX disabled", "reason", "rawconn control failed", "error", err)
-		recordCapability("udp.ecn_rx.enabled", false)
-		return
+
+	v4err = unix.SetsockoptInt(u.sysFd, unix.IPPROTO_IP, unix.IP_RECVTOS, 1)
+	if !u.isV4 {
+		v6err = unix.SetsockoptInt(u.sysFd, unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
 	}
 	if u.isV4 { //only check the V4 attempt
 		if v4err != nil {
@@ -507,15 +481,6 @@ func (u *StdConn) ListenOut(r EncReader, flush func()) error {
 	}
 }
 
-// headerCounter returns the big-endian uint64 message counter at bytes
-// [8:16] of a nebula packet, or 0 if the buffer is too short.
-func headerCounter(buf []byte) uint64 {
-	if len(buf) < 16 {
-		return 0
-	}
-	return binary.BigEndian.Uint64(buf[8:16])
-}
-
 // parseRecvCmsg walks the per-slot ancillary buffer once and extracts up to
 // two values of interest in a single pass: the UDP_GRO gso_size (when
 // wantGRO is true) and the outer IP-level ECN codepoint stamped on the
@@ -873,10 +838,18 @@ func (u *StdConn) writeEntryCmsg(entry, runLen, segSize int, ecn byte, dstIsV4 b
 }
 
 // sendmmsg issues sendmmsg(2) over u.rawConn against the first n entries
-// of u.writeMsgs. Routes through u.rawSend so the per-call kernel callback
-// stays alloc-free.
+// of u.writeMsgs.
 func (u *StdConn) sendmmsg(n int) (int, error) {
-	return u.rawSend.send(u.rawConn, n)
+	r1, _, errno := unix.Syscall6(unix.SYS_SENDMMSG, uintptr(u.sysFd),
+		uintptr(unsafe.Pointer(&u.writeMsgs[0])), uintptr(n),
+		0, 0, 0,
+	)
+	sent := int(r1)
+
+	if errno != 0 {
+		return sent, &net.OpError{Op: "sendmmsg", Err: errno}
+	}
+	return sent, nil
 }
 
 // writeSockaddr encodes addr into buf (which must be at least