diff --git a/net/rioconn/config.go b/net/rioconn/config.go index 8ccc88306..359e33457 100644 --- a/net/rioconn/config.go +++ b/net/rioconn/config.go @@ -4,13 +4,24 @@ package rioconn import ( + "cmp" "errors" + "math" "syscall" ) +const ( + // TODO(nickkhyl): Determine defaults automatically based on NIC and link properties. + + defaultRXMemoryLimit = 2 << 20 // 2 MiB + defaultTXMemoryLimit = 2 << 20 // 2 MiB +) + // Config holds configuration for a RIO connection, independent of the transport protocol. type Config struct { control []func(network, address string, c syscall.RawConn) error + rx RxConfig + tx TxConfig } // Control invokes all control functions in the Config with the given @@ -26,3 +37,56 @@ func (c Config) Control(network string, address string, conn syscall.RawConn) er } return errors.Join(err...) } + +// Rx returns the receive path configuration. +func (c Config) Rx() *RxConfig { + return &c.rx +} + +// Tx returns the transmit path configuration. +func (c Config) Tx() *TxConfig { + return &c.tx +} + +// RxConfig holds configuration for the receive path of a RIO connection. +type RxConfig struct { + memoryLimit uintptr // 0 means default + maxPayloadLen uint16 // 0 means default +} + +// MemoryLimit returns the maximum memory allowed for the receive path. +func (o RxConfig) MemoryLimit() uintptr { + return cmp.Or(o.memoryLimit, defaultRXMemoryLimit) +} + +// MaxPayloadLen returns the maximum number of bytes allowed in a +// single packet. Packets larger than this limit may be dropped. +// It returns [math.MaxUint16] if no limit is applied other than the +// maximum packet size supported by the connection's transport protocol. +func (o RxConfig) MaxPayloadLen() uint16 { + return cmp.Or(o.maxPayloadLen, math.MaxUint16) +} + +// TxConfig holds configuration for the transmit path of a RIO connection. +type TxConfig struct { + memoryLimit uintptr // 0 means default + maxPayloadLen uint16 // 0 means default +} + +// MemoryLimit returns the maximum memory allowed for the transmit path. +func (o TxConfig) MemoryLimit() uintptr { + return cmp.Or(o.memoryLimit, defaultTXMemoryLimit) +} + +// MaxPayloadLen returns the maximum number of bytes that may be sent +// in a single packet. Sending packets larger than this limit may fail. +// It returns [math.MaxUint16] if no limit is applied other than the +// maximum packet size supported by the connection's transport protocol. +func (o TxConfig) MaxPayloadLen() uint16 { + return cmp.Or(o.maxPayloadLen, math.MaxUint16) +} + +// UDPConfig holds configuration for a [UDPConn]. +type UDPConfig struct { + Config +} diff --git a/net/rioconn/options.go b/net/rioconn/options.go new file mode 100644 index 000000000..5e915a89b --- /dev/null +++ b/net/rioconn/options.go @@ -0,0 +1,78 @@ +// Copyright (c) Tailscale Inc & contributors +// SPDX-License-Identifier: BSD-3-Clause + +//go:build windows + +package rioconn + +import ( + "syscall" +) + +// Option is any option that can be applied to a RIO connection, +// independent of the transport protocol. +type Option interface { + UDPOption +} + +// UDPOption is any option that can be applied to a [UDPConn]. +type UDPOption interface { + applyUDP(*UDPConfig) +} + +type option func(*Config) + +func (o option) applyUDP(opts *UDPConfig) { + o(&opts.Config) +} + +// Control specifies an optional function that will be called after creating +// the network connection but before binding it to the operating system. +func Control(control func(network, address string, c syscall.RawConn) error) Option { + return option(func(opts *Config) { + if control != nil { + opts.control = append(opts.control, control) + } + }) +} + +// RxMemoryLimit specifies the maximum memory to use for the receive path. +func RxMemoryLimit(bytes uintptr) Option { + return option(func(opts *Config) { + opts.rx.memoryLimit = bytes + }) +} + +// RxMaxPayloadLen specifies the maximum payload size, in bytes, accepted +// for a single received packet. Packets exceeding this limit may be dropped. +// If unset or set to zero, no limit is applied other than the maximum packet +// size supported by the connection's transport protocol. +func RxMaxPayloadLen(bytes uintptr) Option { + return option(func(opts *Config) { + opts.rx.maxPayloadLen = uint16(bytes) + }) +} + +// TxMemoryLimit specifies the maximum memory to use for the transmit path. +func TxMemoryLimit(bytes uintptr) Option { + return option(func(opts *Config) { + opts.tx.memoryLimit = bytes + }) +} + +// TxMaxPayloadLen specifies the maximum payload size, in bytes, accepted +// for transmission in a single packet. Attempting to send packets exceeding +// this limit may fail. If unset or set to zero, no limit is applied other than +// the maximum packet size supported by the connection's transport protocol +// and underlying link or hardware capabilities. +func TxMaxPayloadLen(bytes uintptr) Option { + return option(func(opts *Config) { + opts.tx.maxPayloadLen = uint16(bytes) + }) +} + +type udpOption func(*UDPConfig) + +func (o udpOption) applyUDP(opts *UDPConfig) { + o(opts) +}