net/batching: clarify & simplify single packet read limitations

ReadFromUDPAddrPort worked if UDP GRO was unsupported, but we don't
actually want attempted usage, nor does any exist today. Future work
on tailscale/corp#37679 would have required more complexity in this
method, vs clarifying the API intents.

Updates tailscale/corp#37679

Signed-off-by: Jordan Whited <jordan@tailscale.com>
main
Jordan Whited 1 month ago committed by Jordan Whited
parent 70de111394
commit 607d01cdae
  1. 12
      net/batching/conn.go
  2. 11
      net/batching/conn_linux.go

@ -19,14 +19,24 @@ var (
_ ipv6.Message = ipv4.Message{}
)
// Conn is a nettype.PacketConn that provides batched i/o using
// Conn is a [nettype.PacketConn] that provides batched i/o using
// platform-specific optimizations, e.g. {recv,send}mmsg & UDP GSO/GRO.
//
// Conn does not support single packet reads (see ReadFromUDPAddrPort docs). It
// is the caller's responsibility to use the appropriate read API where a
// [nettype.PacketConn] has been upgraded to support batched i/o.
//
// Conn originated from (and is still used by) magicsock where its API was
// strongly influenced by [wireguard-go/conn.Bind] constraints, namely
// wireguard-go's ownership of packet memory.
type Conn interface {
nettype.PacketConn
// ReadFromUDPAddrPort always returns an error, as UDP GRO is incompatible
// with single packet reads. A single datagram may be multiple, coalesced
// datagrams, and this API lacks the ability to pass that context.
//
// TODO: consider detaching Conn from [nettype.PacketConn]
ReadFromUDPAddrPort([]byte) (int, netip.AddrPort, error)
// ReadBatch reads messages from [Conn] into msgs. It returns the number of
// messages the caller should evaluate for nonzero len, as a zero len
// message may fall on either side of a nonzero.

@ -61,16 +61,7 @@ type linuxBatchingConn struct {
}
func (c *linuxBatchingConn) ReadFromUDPAddrPort(p []byte) (n int, addr netip.AddrPort, err error) {
if c.rxOffload {
// UDP_GRO is opt-in on Linux via setsockopt(). Once enabled you may
// receive a "monster datagram" from any read call. The ReadFrom() API
// does not support passing the GSO size and is unsafe to use in such a
// case. Other platforms may vary in behavior, but we go with the most
// conservative approach to prevent this from becoming a footgun in the
// future.
return 0, netip.AddrPort{}, errors.New("rx UDP offload is enabled on this socket, single packet reads are unavailable")
}
return c.pc.ReadFromUDPAddrPort(p)
return 0, netip.AddrPort{}, errors.New("single packet reads are unsupported")
}
func (c *linuxBatchingConn) SetDeadline(t time.Time) error {

Loading…
Cancel
Save