Skip to content

Commit d4c1ce7

Browse files
nekohasekaiwwqgtxx
authored andcommitted
Improve darwin tun performance
1 parent 7812930 commit d4c1ce7

16 files changed

+188
-115
lines changed

internal/fdbased_darwin/endpoint.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ type endpoint struct {
168168
mtu uint32
169169

170170
batchSize int
171+
writeMsgX bool
171172
}
172173

173174
// Options specify the details about the fd-based endpoint to be created.
@@ -223,6 +224,9 @@ type Options struct {
223224
// ProcessorsPerChannel is the number of goroutines used to handle packets
224225
// from each FD.
225226
ProcessorsPerChannel int
227+
228+
MultiPendingPackets bool
229+
WriteMsgX bool
226230
}
227231

228232
// New creates a new fd-based endpoint.
@@ -261,6 +265,12 @@ func New(opts *Options) (stack.LinkEndpoint, error) {
261265
if opts.MaxSyscallHeaderBytes < 0 {
262266
return nil, fmt.Errorf("opts.MaxSyscallHeaderBytes is negative")
263267
}
268+
var batchSize int
269+
if opts.MultiPendingPackets {
270+
batchSize = int((512*1024)/(opts.MTU)) + 1
271+
} else {
272+
batchSize = 1
273+
}
264274

265275
e := &endpoint{
266276
mtu: opts.MTU,
@@ -271,7 +281,8 @@ func New(opts *Options) (stack.LinkEndpoint, error) {
271281
packetDispatchMode: opts.PacketDispatchMode,
272282
maxSyscallHeaderBytes: uintptr(opts.MaxSyscallHeaderBytes),
273283
writevMaxIovs: rawfile.MaxIovs,
274-
batchSize: int((512*1024)/(opts.MTU)) + 1,
284+
batchSize: batchSize,
285+
writeMsgX: opts.WriteMsgX,
275286
}
276287
if e.maxSyscallHeaderBytes != 0 {
277288
if max := int(e.maxSyscallHeaderBytes / rawfile.SizeofIovec); max < e.writevMaxIovs {
@@ -478,7 +489,7 @@ func (e *endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error {
478489

479490
func (e *endpoint) sendBatch(batchFDInfo fdInfo, pkts []*stack.PacketBuffer) (int, tcpip.Error) {
480491
// Degrade to writePacket if underlying fd is not a socket.
481-
if !batchFDInfo.isSocket {
492+
if !batchFDInfo.isSocket || !e.writeMsgX {
482493
var written int
483494
var err tcpip.Error
484495
for written < len(pkts) {

internal/fdbased_darwin/packet_dispatchers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func newRecvMMsgDispatcher(fd int, e *endpoint, opts *Options) (linkDispatcher,
116116
return nil, err
117117
}
118118
var batchSize int
119-
if opts.MTU < 49152 {
119+
if opts.MultiPendingPackets {
120120
batchSize = int((512*1024)/(opts.MTU)) + 1
121121
} else {
122122
batchSize = 1

stack_gvisor.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type GVisor struct {
4040

4141
type GVisorTun interface {
4242
Tun
43+
WritePacket(pkt *stack.PacketBuffer) (int, error)
4344
NewEndpoint() (stack.LinkEndpoint, stack.NICOptions, error)
4445
}
4546

stack_gvisor_filter.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@ import (
88
"github.com/sagernet/gvisor/pkg/tcpip"
99
"github.com/sagernet/gvisor/pkg/tcpip/header"
1010
"github.com/sagernet/gvisor/pkg/tcpip/stack"
11-
"github.com/sagernet/sing/common/bufio"
12-
N "github.com/sagernet/sing/common/network"
1311
)
1412

1513
var _ stack.LinkEndpoint = (*LinkEndpointFilter)(nil)
1614

1715
type LinkEndpointFilter struct {
1816
stack.LinkEndpoint
1917
BroadcastAddress netip.Addr
20-
Writer N.VectorisedWriter
18+
Writer GVisorTun
2119
}
2220

2321
func (w *LinkEndpointFilter) Attach(dispatcher stack.NetworkDispatcher) {
@@ -29,7 +27,7 @@ var _ stack.NetworkDispatcher = (*networkDispatcherFilter)(nil)
2927
type networkDispatcherFilter struct {
3028
stack.NetworkDispatcher
3129
broadcastAddress netip.Addr
32-
writer N.VectorisedWriter
30+
writer GVisorTun
3331
}
3432

3533
func (w *networkDispatcherFilter) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
@@ -49,7 +47,7 @@ func (w *networkDispatcherFilter) DeliverNetworkPacket(protocol tcpip.NetworkPro
4947
}
5048
destination := AddrFromAddress(network.DestinationAddress())
5149
if destination == w.broadcastAddress || !destination.IsGlobalUnicast() {
52-
_, _ = bufio.WriteVectorised(w.writer, pkt.AsSlices())
50+
w.writer.WritePacket(pkt)
5351
return
5452
}
5553
w.NetworkDispatcher.DeliverNetworkPacket(protocol, pkt)

stack_gvisor_tcp.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
1414
"github.com/sagernet/sing-tun/internal/gtcpip/checksum"
1515
"github.com/sagernet/sing/common"
16-
"github.com/sagernet/sing/common/bufio"
1716
M "github.com/sagernet/sing/common/metadata"
1817
N "github.com/sagernet/sing/common/network"
1918
)
@@ -56,7 +55,7 @@ func (f *TCPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pac
5655
tcpHdr.SetChecksum(^checksum.Checksum(tcpHdr.Payload(), tcpHdr.CalculateChecksum(
5756
header.PseudoHeaderChecksum(header.TCPProtocolNumber, ipHdr.SourceAddress(), ipHdr.DestinationAddress(), ipHdr.PayloadLength()),
5857
)))
59-
bufio.WriteVectorised(f.tun, pkt.AsSlices())
58+
f.tun.WritePacket(pkt)
6059
return true
6160
}
6261
}
@@ -70,7 +69,7 @@ func (f *TCPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pac
7069
tcpHdr.SetChecksum(^checksum.Checksum(tcpHdr.Payload(), tcpHdr.CalculateChecksum(
7170
header.PseudoHeaderChecksum(header.TCPProtocolNumber, ipHdr.SourceAddress(), ipHdr.DestinationAddress(), ipHdr.PayloadLength()),
7271
)))
73-
bufio.WriteVectorised(f.tun, pkt.AsSlices())
72+
f.tun.WritePacket(pkt)
7473
return true
7574
}
7675
}

stack_mixed.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import (
1111
"github.com/sagernet/gvisor/pkg/tcpip/transport/udp"
1212
"github.com/sagernet/sing-tun/internal/gtcpip/header"
1313
"github.com/sagernet/sing/common/buf"
14-
"github.com/sagernet/sing/common/bufio"
1514
E "github.com/sagernet/sing/common/exceptions"
1615
)
1716

1817
type Mixed struct {
1918
*System
19+
tun GVisorTun
2020
stack *stack.Stack
2121
endpoint *channel.Endpoint
2222
}
@@ -30,6 +30,7 @@ func NewMixed(
3030
}
3131
return &Mixed{
3232
System: system.(*System),
33+
tun: system.(*System).tun.(GVisorTun),
3334
}, nil
3435
}
3536

@@ -77,7 +78,7 @@ func (m *Mixed) tunLoop() {
7778
return
7879
}
7980
}
80-
if darwinTUN, isDarwinTUN := m.tun.(DarwinTUN); isDarwinTUN && m.mtu < 49152 {
81+
if darwinTUN, isDarwinTUN := m.tun.(DarwinTUN); isDarwinTUN && m.multiPendingPackets {
8182
m.batchLoopDarwin(darwinTUN)
8283
return
8384
}
@@ -265,11 +266,11 @@ func (m *Mixed) processIPv6(ipHdr header.IPv6) (writeBack bool, err error) {
265266

266267
func (m *Mixed) packetLoop() {
267268
for {
268-
packet := m.endpoint.ReadContext(m.ctx)
269-
if packet == nil {
269+
pkt := m.endpoint.ReadContext(m.ctx)
270+
if pkt == nil {
270271
break
271272
}
272-
bufio.WriteVectorised(m.tun, packet.AsSlices())
273-
packet.DecRef()
273+
m.tun.WritePacket(pkt)
274+
pkt.DecRef()
274275
}
275276
}

stack_system.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type System struct {
4949
interfaceFinder control.InterfaceFinder
5050
frontHeadroom int
5151
txChecksumOffload bool
52+
multiPendingPackets bool
5253
}
5354

5455
type Session struct {
@@ -74,6 +75,7 @@ func NewSystem(options StackOptions) (Stack, error) {
7475
broadcastAddr: BroadcastAddr(options.TunOptions.Inet4Address),
7576
bindInterface: options.ForwarderBindInterface,
7677
interfaceFinder: options.InterfaceFinder,
78+
multiPendingPackets: options.TunOptions.EXP_MultiPendingPackets,
7779
}
7880
if len(options.TunOptions.Inet4Address) > 0 {
7981
if !HasNextAddress(options.TunOptions.Inet4Address[0], 1) {
@@ -174,7 +176,7 @@ func (s *System) tunLoop() {
174176
return
175177
}
176178
}
177-
if darwinTUN, isDarwinTUN := s.tun.(DarwinTUN); isDarwinTUN && s.mtu < 49152 {
179+
if darwinTUN, isDarwinTUN := s.tun.(DarwinTUN); isDarwinTUN && s.multiPendingPackets {
178180
s.batchLoopDarwin(darwinTUN)
179181
return
180182
}
@@ -320,6 +322,13 @@ func (s *System) acceptLoop(listener net.Listener) {
320322
if err != nil {
321323
return
322324
}
325+
err = acceptConn(conn)
326+
if err != nil {
327+
s.logger.Error("set buffer for conn: ", err)
328+
_ = conn.Close()
329+
listener.Close()
330+
return
331+
}
323332
connPort := M.SocksaddrFromNet(conn.RemoteAddr()).Port
324333
session := s.tcpNat.LookupBack(connPort)
325334
if session == nil {

stack_system_unix.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build !windows
2+
3+
package tun
4+
5+
import (
6+
"net"
7+
8+
"github.com/sagernet/sing/common/control"
9+
10+
"golang.org/x/sys/unix"
11+
)
12+
13+
func acceptConn(conn net.Conn) error {
14+
return control.Conn(conn.(*net.TCPConn), func(fd uintptr) error {
15+
const bufferSize = 1024 * 1024
16+
oErr := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, bufferSize)
17+
if oErr != nil {
18+
return oErr
19+
}
20+
oErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, bufferSize)
21+
if oErr != nil {
22+
return oErr
23+
}
24+
return nil
25+
})
26+
}

stack_system_windows.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package tun
22

33
import (
44
"errors"
5+
"net"
56
"os"
67
"path/filepath"
78

@@ -31,3 +32,7 @@ func fixWindowsFirewall() error {
3132
func retryableListenError(err error) bool {
3233
return errors.Is(err, windows.WSAEADDRNOTAVAIL)
3334
}
35+
36+
func acceptConn(conn net.Conn) error {
37+
return nil
38+
}

tun.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ type Handler interface {
2525

2626
type Tun interface {
2727
io.ReadWriter
28-
N.VectorisedWriter
2928
Name() (string, error)
3029
Start() error
3130
Close() error
@@ -97,6 +96,9 @@ type Options struct {
9796

9897
// For library usages.
9998
EXP_DisableDNSHijack bool
99+
100+
EXP_MultiPendingPackets bool
101+
EXP_WriteMsgX bool
100102
}
101103

102104
func (o *Options) Inet4GatewayAddr() netip.Addr {

0 commit comments

Comments
 (0)