Allocate small iovec arrays on the stack

This commit is contained in:
wwqgtxx
2025-07-18 11:28:55 +08:00
parent c15253c79d
commit bfa768693d
4 changed files with 50 additions and 39 deletions

View File

@@ -25,21 +25,20 @@ var _ DarwinTUN = (*NativeTun)(nil)
const PacketOffset = 4
type NativeTun struct {
tunFd int
tunFile *os.File
batchSize int
iovecs []iovecBuffer
iovecsOutput []iovecBuffer
iovecsOutputDefault []unix.Iovec
msgHdrs []rawfile.MsgHdrX
msgHdrsOutput []rawfile.MsgHdrX
buffers []*buf.Buffer
stopFd stopfd.StopFD
options Options
inet4Address [4]byte
inet6Address [16]byte
routeSet bool
writeMsgX bool
tunFd int
tunFile *os.File
batchSize int
iovecs []iovecBuffer
iovecsOutput []iovecBuffer
msgHdrs []rawfile.MsgHdrX
msgHdrsOutput []rawfile.MsgHdrX
buffers []*buf.Buffer
stopFd stopfd.StopFD
options Options
inet4Address [4]byte
inet6Address [16]byte
routeSet bool
writeMsgX bool
}
type iovecBuffer struct {

View File

@@ -15,14 +15,24 @@ import (
var _ GVisorTun = (*NativeTun)(nil)
func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) {
iovecs := t.iovecsOutputDefault
views := pkt.AsSlices()
numIovecs := len(views)
numIovecs++ // for packetHeaderVec4/6
// Allocate small iovec arrays on the stack.
var iovecsArr [8]unix.Iovec
iovecs := iovecsArr[:0]
if numIovecs > len(iovecsArr) {
iovecs = make([]unix.Iovec, 0, numIovecs)
}
if pkt.NetworkProtocolNumber == header.IPv4ProtocolNumber {
iovecs = append(iovecs, packetHeaderVec4)
} else {
iovecs = append(iovecs, packetHeaderVec6)
}
var dataLen int
for _, packetSlice := range pkt.AsSlices() {
for _, packetSlice := range views {
dataLen += len(packetSlice)
iovec := unix.Iovec{
Base: &packetSlice[0],
@@ -30,9 +40,6 @@ func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) {
iovec.SetLen(len(packetSlice))
iovecs = append(iovecs, iovec)
}
if cap(iovecs) > cap(t.iovecsOutputDefault) {
t.iovecsOutputDefault = iovecs[:0]
}
errno := rawfile.NonBlockingWriteIovec(t.tunFd, iovecs)
if errno == 0 {
return dataLen, nil

View File

@@ -25,20 +25,19 @@ import (
var _ LinuxTUN = (*NativeTun)(nil)
type NativeTun struct {
tunFd int
tunFile *os.File
iovecsOutputDefault []unix.Iovec
interfaceCallback *list.Element[DefaultInterfaceUpdateCallback]
options Options
ruleIndex6 []int
gsoEnabled bool
gsoBuffer []byte
gsoToWrite []int
gsoReadAccess sync.Mutex
tcpGROAccess sync.Mutex
tcp4GROTable *tcpGROTable
tcp6GROTable *tcpGROTable
txChecksumOffload bool
tunFd int
tunFile *os.File
interfaceCallback *list.Element[DefaultInterfaceUpdateCallback]
options Options
ruleIndex6 []int
gsoEnabled bool
gsoBuffer []byte
gsoToWrite []int
gsoReadAccess sync.Mutex
tcpGROAccess sync.Mutex
tcp4GROTable *tcpGROTable
tcp6GROTable *tcpGROTable
txChecksumOffload bool
}
func New(options Options) (Tun, error) {

View File

@@ -17,9 +17,18 @@ func init() {
var _ GVisorTun = (*NativeTun)(nil)
func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) {
iovecs := t.iovecsOutputDefault
views := pkt.AsSlices()
numIovecs := len(views)
// Allocate small iovec arrays on the stack.
var iovecsArr [8]unix.Iovec
iovecs := iovecsArr[:0]
if numIovecs > len(iovecsArr) {
iovecs = make([]unix.Iovec, 0, numIovecs)
}
var dataLen int
for _, packetSlice := range pkt.AsSlices() {
for _, packetSlice := range views {
dataLen += len(packetSlice)
iovec := unix.Iovec{
Base: &packetSlice[0],
@@ -27,9 +36,6 @@ func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) {
iovec.SetLen(len(packetSlice))
iovecs = append(iovecs, iovec)
}
if cap(iovecs) > cap(t.iovecsOutputDefault) {
t.iovecsOutputDefault = iovecs[:0]
}
errno := rawfile.NonBlockingWriteIovec(t.tunFd, iovecs)
if errno == 0 {
return dataLen, nil