config tweaks for batching

This commit is contained in:
Ryan
2025-11-06 10:01:20 -05:00
parent ad37749c5e
commit 2c6f81c224
3 changed files with 63 additions and 17 deletions

View File

@@ -132,6 +132,13 @@ listen:
# Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg) # Sets the max number of packets to pull from the kernel for each syscall (under systems that support recvmmsg)
# default is 64, does not support reload # default is 64, does not support reload
#batch: 64 #batch: 64
# Control batching between UDP and TUN pipelines
#batch:
# inbound_size: 32 # packets to queue from UDP before handing to workers
# outbound_size: 32 # packets to queue from TUN before handing to workers
# flush_interval: 50us # flush partially filled batches after this duration
# max_outstanding: 1028 # batches buffered per routine on each channel
# Configure socket buffers for the udp side (outside), leave unset to use the system defaults. Values will be doubled by the kernel # Configure socket buffers for the udp side (outside), leave unset to use the system defaults. Values will be doubled by the kernel
# Default is net.core.rmem_default and net.core.wmem_default (/proc/sys/net/core/rmem_default and /proc/sys/net/core/rmem_default) # Default is net.core.rmem_default and net.core.wmem_default (/proc/sys/net/core/rmem_default and /proc/sys/net/core/rmem_default)
# Maximum is limited by memory in the system, SO_RCVBUFFORCE and SO_SNDBUFFORCE is used to avoid having to raise the system wide # Maximum is limited by memory in the system, SO_RCVBUFFORCE and SO_SNDBUFFORCE is used to avoid having to raise the system wide

View File

@@ -25,10 +25,10 @@ import (
const ( const (
mtu = 9001 mtu = 9001
inboundBatchSize = 32 inboundBatchSizeDefault = 32
outboundBatchSize = 32 outboundBatchSizeDefault = 32
batchFlushInterval = 50 * time.Microsecond batchFlushIntervalDefault = 50 * time.Microsecond
maxOutstandingBatches = 1028 maxOutstandingBatchesDefault = 1028
) )
type InterfaceConfig struct { type InterfaceConfig struct {
@@ -55,9 +55,17 @@ type InterfaceConfig struct {
reQueryWait time.Duration reQueryWait time.Duration
ConntrackCacheTimeout time.Duration ConntrackCacheTimeout time.Duration
BatchConfig BatchConfig
l *logrus.Logger l *logrus.Logger
} }
type BatchConfig struct {
InboundBatchSize int
OutboundBatchSize int
FlushInterval time.Duration
MaxOutstandingPerChan int
}
type Interface struct { type Interface struct {
hostMap *HostMap hostMap *HostMap
outside udp.Conn outside udp.Conn
@@ -111,15 +119,20 @@ type Interface struct {
packetBatchPool sync.Pool packetBatchPool sync.Pool
outboundBatchPool sync.Pool outboundBatchPool sync.Pool
inboundBatchSize int
outboundBatchSize int
batchFlushInterval time.Duration
maxOutstandingPerChan int
} }
type packetBatch struct { type packetBatch struct {
packets []*packet.Packet packets []*packet.Packet
} }
func newPacketBatch() *packetBatch { func newPacketBatch(capacity int) *packetBatch {
return &packetBatch{ return &packetBatch{
packets: make([]*packet.Packet, 0, inboundBatchSize), packets: make([]*packet.Packet, 0, capacity),
} }
} }
@@ -140,7 +153,7 @@ func (f *Interface) getPacketBatch() *packetBatch {
b.reset() b.reset()
return b return b
} }
return newPacketBatch() return newPacketBatch(f.inboundBatchSize)
} }
func (f *Interface) releasePacketBatch(b *packetBatch) { func (f *Interface) releasePacketBatch(b *packetBatch) {
@@ -152,8 +165,8 @@ type outboundBatch struct {
payloads []*[]byte payloads []*[]byte
} }
func newOutboundBatch() *outboundBatch { func newOutboundBatch(capacity int) *outboundBatch {
return &outboundBatch{payloads: make([]*[]byte, 0, outboundBatchSize)} return &outboundBatch{payloads: make([]*[]byte, 0, capacity)}
} }
func (b *outboundBatch) add(buf *[]byte) { func (b *outboundBatch) add(buf *[]byte) {
@@ -173,7 +186,7 @@ func (f *Interface) getOutboundBatch() *outboundBatch {
b.reset() b.reset()
return b return b
} }
return newOutboundBatch() return newOutboundBatch(f.outboundBatchSize)
} }
func (f *Interface) releaseOutboundBatch(b *outboundBatch) { func (f *Interface) releaseOutboundBatch(b *outboundBatch) {
@@ -248,6 +261,20 @@ func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
} }
cs := c.pki.getCertState() cs := c.pki.getCertState()
bc := c.BatchConfig
if bc.InboundBatchSize <= 0 {
bc.InboundBatchSize = inboundBatchSizeDefault
}
if bc.OutboundBatchSize <= 0 {
bc.OutboundBatchSize = outboundBatchSizeDefault
}
if bc.FlushInterval <= 0 {
bc.FlushInterval = batchFlushIntervalDefault
}
if bc.MaxOutstandingPerChan <= 0 {
bc.MaxOutstandingPerChan = maxOutstandingBatchesDefault
}
ifce := &Interface{ ifce := &Interface{
pki: c.pki, pki: c.pki,
hostMap: c.HostMap, hostMap: c.HostMap,
@@ -280,16 +307,20 @@ func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
dropped: metrics.GetOrRegisterCounter("hostinfo.cached_packets.dropped", nil), dropped: metrics.GetOrRegisterCounter("hostinfo.cached_packets.dropped", nil),
}, },
//TODO: configurable size
inbound: make([]chan *packetBatch, c.routines), inbound: make([]chan *packetBatch, c.routines),
outbound: make([]chan *outboundBatch, c.routines), outbound: make([]chan *outboundBatch, c.routines),
l: c.l, l: c.l,
inboundBatchSize: bc.InboundBatchSize,
outboundBatchSize: bc.OutboundBatchSize,
batchFlushInterval: bc.FlushInterval,
maxOutstandingPerChan: bc.MaxOutstandingPerChan,
} }
for i := 0; i < c.routines; i++ { for i := 0; i < c.routines; i++ {
ifce.inbound[i] = make(chan *packetBatch, maxOutstandingBatches) ifce.inbound[i] = make(chan *packetBatch, ifce.maxOutstandingPerChan)
ifce.outbound[i] = make(chan *outboundBatch, maxOutstandingBatches) ifce.outbound[i] = make(chan *outboundBatch, ifce.maxOutstandingPerChan)
} }
ifce.inPool = sync.Pool{New: func() any { ifce.inPool = sync.Pool{New: func() any {
@@ -302,11 +333,11 @@ func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
}} }}
ifce.packetBatchPool = sync.Pool{New: func() any { ifce.packetBatchPool = sync.Pool{New: func() any {
return newPacketBatch() return newPacketBatch(ifce.inboundBatchSize)
}} }}
ifce.outboundBatchPool = sync.Pool{New: func() any { ifce.outboundBatchPool = sync.Pool{New: func() any {
return newOutboundBatch() return newOutboundBatch(ifce.outboundBatchSize)
}} }}
ifce.tryPromoteEvery.Store(c.tryPromoteEvery) ifce.tryPromoteEvery.Store(c.tryPromoteEvery)
@@ -411,7 +442,7 @@ func (f *Interface) listenOut(i int) {
p.Addr = fromUdpAddr p.Addr = fromUdpAddr
batch.add(p) batch.add(p)
if len(batch.packets) >= inboundBatchSize || time.Since(lastFlush) >= batchFlushInterval { if len(batch.packets) >= f.inboundBatchSize || time.Since(lastFlush) >= f.batchFlushInterval {
flush(false) flush(false)
} }
}) })
@@ -465,7 +496,7 @@ func (f *Interface) listenIn(reader io.ReadWriteCloser, i int) {
*p = (*p)[:n] *p = (*p)[:n]
batch.add(p) batch.add(p)
if len(batch.payloads) >= outboundBatchSize || time.Since(lastFlush) >= batchFlushInterval { if len(batch.payloads) >= f.outboundBatchSize || time.Since(lastFlush) >= f.batchFlushInterval {
flush(false) flush(false)
} }
} }

View File

@@ -221,6 +221,13 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
} }
} }
batchCfg := BatchConfig{
InboundBatchSize: c.GetInt("batch.inbound_size", inboundBatchSizeDefault),
OutboundBatchSize: c.GetInt("batch.outbound_size", outboundBatchSizeDefault),
FlushInterval: c.GetDuration("batch.flush_interval", batchFlushIntervalDefault),
MaxOutstandingPerChan: c.GetInt("batch.max_outstanding", maxOutstandingBatchesDefault),
}
ifConfig := &InterfaceConfig{ ifConfig := &InterfaceConfig{
HostMap: hostMap, HostMap: hostMap,
Inside: tun, Inside: tun,
@@ -242,6 +249,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg
relayManager: NewRelayManager(ctx, l, hostMap, c), relayManager: NewRelayManager(ctx, l, hostMap, c),
punchy: punchy, punchy: punchy,
ConntrackCacheTimeout: conntrackCacheTimeout, ConntrackCacheTimeout: conntrackCacheTimeout,
BatchConfig: batchCfg,
l: l, l: l,
} }