44 lines
1.6 KiB
Go
44 lines
1.6 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build !ios
|
|
|
|
package wgcfg
|
|
|
|
import (
|
|
"runtime"
|
|
|
|
"github.com/tailscale/wireguard-go/device"
|
|
)
|
|
|
|
func getMemoryOptions() []device.Option {
|
|
// wireguard-go is a packet pipeline:
|
|
//
|
|
// TUN read -> encrypt -> ordered network write
|
|
// network read -> decrypt -> ordered TUN write
|
|
//
|
|
// The queues that we are sizing in this function sit between head I/O
|
|
// goroutines and downstream functions. They are buffered channels.
|
|
//
|
|
// The head I/O ops tend to "run ahead" the downstream functions, especially
|
|
// when head I/O ops utilize segmentation offloading, where a single head I/O
|
|
// op can contain about 45 packets at a typical MTU, which is equivalent to
|
|
// 45 crypto ops.
|
|
//
|
|
// Small queues park I/O goroutines and hurt throughput; large queues allow
|
|
// more packet batches and their associated memory to remain outstanding. We
|
|
// have to find a balance. Crypto goroutines are sized to [runtime.NumCPU]
|
|
// in wireguard-go, so we start there, and apply a benchmark-backed scaling
|
|
// factor to reduce head I/O goroutines parking around bursts.
|
|
const cpuScalingFactor = 4
|
|
// maxQueueSize was the previous static default, prior to creation of the
|
|
// [device.Option].
|
|
const maxQueueSize = 1024
|
|
return []device.Option{
|
|
// TODO: make cgroup-aware with runtime.GOMAXPROCS(0).
|
|
// See tailscale/corp#47966.
|
|
device.WithQueueInboundSize(min(maxQueueSize, runtime.NumCPU()*cpuScalingFactor)),
|
|
device.WithQueueOutboundSize(min(maxQueueSize, runtime.NumCPU()*cpuScalingFactor)),
|
|
}
|
|
}
|