diff --git a/internal/fdbased_darwin/endpoint.go b/internal/fdbased_darwin/endpoint.go index 91a33aa..f26bfe3 100644 --- a/internal/fdbased_darwin/endpoint.go +++ b/internal/fdbased_darwin/endpoint.go @@ -168,6 +168,7 @@ type endpoint struct { mtu uint32 batchSize int + sendMsgX bool } // Options specify the details about the fd-based endpoint to be created. @@ -223,6 +224,9 @@ type Options struct { // ProcessorsPerChannel is the number of goroutines used to handle packets // from each FD. ProcessorsPerChannel int + + MultiPendingPackets bool + SendMsgX bool } // New creates a new fd-based endpoint. @@ -261,6 +265,12 @@ func New(opts *Options) (stack.LinkEndpoint, error) { if opts.MaxSyscallHeaderBytes < 0 { return nil, fmt.Errorf("opts.MaxSyscallHeaderBytes is negative") } + var batchSize int + if opts.MultiPendingPackets { + batchSize = int((512*1024)/(opts.MTU)) + 1 + } else { + batchSize = 1 + } e := &endpoint{ mtu: opts.MTU, @@ -271,7 +281,8 @@ func New(opts *Options) (stack.LinkEndpoint, error) { packetDispatchMode: opts.PacketDispatchMode, maxSyscallHeaderBytes: uintptr(opts.MaxSyscallHeaderBytes), writevMaxIovs: rawfile.MaxIovs, - batchSize: int((512*1024)/(opts.MTU)) + 1, + batchSize: batchSize, + sendMsgX: opts.SendMsgX, } if e.maxSyscallHeaderBytes != 0 { if max := int(e.maxSyscallHeaderBytes / rawfile.SizeofIovec); max < e.writevMaxIovs { @@ -478,7 +489,7 @@ func (e *endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error { func (e *endpoint) sendBatch(batchFDInfo fdInfo, pkts []*stack.PacketBuffer) (int, tcpip.Error) { // Degrade to writePacket if underlying fd is not a socket. - if !batchFDInfo.isSocket { + if !batchFDInfo.isSocket || !e.sendMsgX { var written int var err tcpip.Error for written < len(pkts) { diff --git a/internal/fdbased_darwin/packet_dispatchers.go b/internal/fdbased_darwin/packet_dispatchers.go index f66c438..a006d41 100644 --- a/internal/fdbased_darwin/packet_dispatchers.go +++ b/internal/fdbased_darwin/packet_dispatchers.go @@ -116,7 +116,7 @@ func newRecvMMsgDispatcher(fd int, e *endpoint, opts *Options) (linkDispatcher, return nil, err } var batchSize int - if opts.MTU < 49152 { + if opts.MultiPendingPackets { batchSize = int((512*1024)/(opts.MTU)) + 1 } else { batchSize = 1 diff --git a/stack_gvisor.go b/stack_gvisor.go index 5e03cc6..0dc995b 100644 --- a/stack_gvisor.go +++ b/stack_gvisor.go @@ -40,6 +40,7 @@ type GVisor struct { type GVisorTun interface { Tun + WritePacket(pkt *stack.PacketBuffer) (int, error) NewEndpoint() (stack.LinkEndpoint, stack.NICOptions, error) } diff --git a/stack_gvisor_filter.go b/stack_gvisor_filter.go index fc6319e..18e46e8 100644 --- a/stack_gvisor_filter.go +++ b/stack_gvisor_filter.go @@ -8,8 +8,6 @@ import ( "github.com/sagernet/gvisor/pkg/tcpip" "github.com/sagernet/gvisor/pkg/tcpip/header" "github.com/sagernet/gvisor/pkg/tcpip/stack" - "github.com/sagernet/sing/common/bufio" - N "github.com/sagernet/sing/common/network" ) var _ stack.LinkEndpoint = (*LinkEndpointFilter)(nil) @@ -17,7 +15,7 @@ var _ stack.LinkEndpoint = (*LinkEndpointFilter)(nil) type LinkEndpointFilter struct { stack.LinkEndpoint BroadcastAddress netip.Addr - Writer N.VectorisedWriter + Writer GVisorTun } func (w *LinkEndpointFilter) Attach(dispatcher stack.NetworkDispatcher) { @@ -29,7 +27,7 @@ var _ stack.NetworkDispatcher = (*networkDispatcherFilter)(nil) type networkDispatcherFilter struct { stack.NetworkDispatcher broadcastAddress netip.Addr - writer N.VectorisedWriter + writer GVisorTun } func (w *networkDispatcherFilter) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { @@ -49,7 +47,7 @@ func (w *networkDispatcherFilter) DeliverNetworkPacket(protocol tcpip.NetworkPro } destination := AddrFromAddress(network.DestinationAddress()) if destination == w.broadcastAddress || !destination.IsGlobalUnicast() { - _, _ = bufio.WriteVectorised(w.writer, pkt.AsSlices()) + w.writer.WritePacket(pkt) return } w.NetworkDispatcher.DeliverNetworkPacket(protocol, pkt) diff --git a/stack_gvisor_tcp.go b/stack_gvisor_tcp.go index cd39778..aad97cf 100644 --- a/stack_gvisor_tcp.go +++ b/stack_gvisor_tcp.go @@ -13,7 +13,6 @@ import ( "github.com/sagernet/gvisor/pkg/tcpip/transport/tcp" "github.com/sagernet/sing-tun/internal/gtcpip/checksum" "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) @@ -56,7 +55,7 @@ func (f *TCPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pac tcpHdr.SetChecksum(^checksum.Checksum(tcpHdr.Payload(), tcpHdr.CalculateChecksum( header.PseudoHeaderChecksum(header.TCPProtocolNumber, ipHdr.SourceAddress(), ipHdr.DestinationAddress(), ipHdr.PayloadLength()), ))) - bufio.WriteVectorised(f.tun, pkt.AsSlices()) + f.tun.WritePacket(pkt) return true } } @@ -70,7 +69,7 @@ func (f *TCPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.Pac tcpHdr.SetChecksum(^checksum.Checksum(tcpHdr.Payload(), tcpHdr.CalculateChecksum( header.PseudoHeaderChecksum(header.TCPProtocolNumber, ipHdr.SourceAddress(), ipHdr.DestinationAddress(), ipHdr.PayloadLength()), ))) - bufio.WriteVectorised(f.tun, pkt.AsSlices()) + f.tun.WritePacket(pkt) return true } } diff --git a/stack_mixed.go b/stack_mixed.go index ffab459..a48639d 100644 --- a/stack_mixed.go +++ b/stack_mixed.go @@ -11,12 +11,12 @@ import ( "github.com/sagernet/gvisor/pkg/tcpip/transport/udp" "github.com/sagernet/sing-tun/internal/gtcpip/header" "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" ) type Mixed struct { *System + tun GVisorTun stack *stack.Stack endpoint *channel.Endpoint } @@ -30,6 +30,7 @@ func NewMixed( } return &Mixed{ System: system.(*System), + tun: system.(*System).tun.(GVisorTun), }, nil } @@ -77,7 +78,7 @@ func (m *Mixed) tunLoop() { return } } - if darwinTUN, isDarwinTUN := m.tun.(DarwinTUN); isDarwinTUN && m.mtu < 49152 { + if darwinTUN, isDarwinTUN := m.tun.(DarwinTUN); isDarwinTUN && m.multiPendingPackets { m.batchLoopDarwin(darwinTUN) return } @@ -265,11 +266,11 @@ func (m *Mixed) processIPv6(ipHdr header.IPv6) (writeBack bool, err error) { func (m *Mixed) packetLoop() { for { - packet := m.endpoint.ReadContext(m.ctx) - if packet == nil { + pkt := m.endpoint.ReadContext(m.ctx) + if pkt == nil { break } - bufio.WriteVectorised(m.tun, packet.AsSlices()) - packet.DecRef() + m.tun.WritePacket(pkt) + pkt.DecRef() } } diff --git a/stack_system.go b/stack_system.go index 1feba5a..d549ed3 100644 --- a/stack_system.go +++ b/stack_system.go @@ -49,6 +49,7 @@ type System struct { interfaceFinder control.InterfaceFinder frontHeadroom int txChecksumOffload bool + multiPendingPackets bool } type Session struct { @@ -74,6 +75,7 @@ func NewSystem(options StackOptions) (Stack, error) { broadcastAddr: BroadcastAddr(options.TunOptions.Inet4Address), bindInterface: options.ForwarderBindInterface, interfaceFinder: options.InterfaceFinder, + multiPendingPackets: options.TunOptions.EXP_MultiPendingPackets, } if len(options.TunOptions.Inet4Address) > 0 { if !HasNextAddress(options.TunOptions.Inet4Address[0], 1) { @@ -174,7 +176,7 @@ func (s *System) tunLoop() { return } } - if darwinTUN, isDarwinTUN := s.tun.(DarwinTUN); isDarwinTUN && s.mtu < 49152 { + if darwinTUN, isDarwinTUN := s.tun.(DarwinTUN); isDarwinTUN && s.multiPendingPackets { s.batchLoopDarwin(darwinTUN) return } @@ -320,6 +322,13 @@ func (s *System) acceptLoop(listener net.Listener) { if err != nil { return } + err = acceptConn(conn) + if err != nil { + s.logger.Error("set buffer for conn: ", err) + _ = conn.Close() + listener.Close() + return + } connPort := M.SocksaddrFromNet(conn.RemoteAddr()).Port session := s.tcpNat.LookupBack(connPort) if session == nil { diff --git a/stack_system_unix.go b/stack_system_unix.go new file mode 100644 index 0000000..0f10042 --- /dev/null +++ b/stack_system_unix.go @@ -0,0 +1,26 @@ +//go:build !windows + +package tun + +import ( + "net" + + "github.com/sagernet/sing/common/control" + + "golang.org/x/sys/unix" +) + +func acceptConn(conn net.Conn) error { + return control.Conn(conn.(*net.TCPConn), func(fd uintptr) error { + const bufferSize = 1024 * 1024 + oErr := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, bufferSize) + if oErr != nil { + return oErr + } + oErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, bufferSize) + if oErr != nil { + return oErr + } + return nil + }) +} diff --git a/stack_system_windows.go b/stack_system_windows.go index f6c66d0..ed76d57 100644 --- a/stack_system_windows.go +++ b/stack_system_windows.go @@ -2,6 +2,7 @@ package tun import ( "errors" + "net" "os" "path/filepath" @@ -31,3 +32,7 @@ func fixWindowsFirewall() error { func retryableListenError(err error) bool { return errors.Is(err, windows.WSAEADDRNOTAVAIL) } + +func acceptConn(conn net.Conn) error { + return nil +} diff --git a/tun.go b/tun.go index 03ded6a..92eab64 100644 --- a/tun.go +++ b/tun.go @@ -25,7 +25,6 @@ type Handler interface { type Tun interface { io.ReadWriter - N.VectorisedWriter Name() (string, error) Start() error Close() error @@ -97,6 +96,13 @@ type Options struct { // For library usages. EXP_DisableDNSHijack bool + + // For gvisor stack, it should be enabled when MTU is less than 32768; otherwise it should be less than or equal to 8192. + // The above condition is just an estimate and not exact, calculated on M4 pro. + EXP_MultiPendingPackets bool + + // Will cause the darwin network to die, do not use. + EXP_SendMsgX bool } func (o *Options) Inet4GatewayAddr() netip.Addr { diff --git a/tun_darwin.go b/tun_darwin.go index 53950a6..e8d019b 100644 --- a/tun_darwin.go +++ b/tun_darwin.go @@ -14,9 +14,7 @@ import ( "github.com/sagernet/sing-tun/internal/stopfd_darwin" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" - N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/shell" "golang.org/x/net/route" @@ -28,20 +26,21 @@ var _ DarwinTUN = (*NativeTun)(nil) const PacketOffset = 4 type NativeTun struct { - tunFd int - tunFile *os.File - batchSize int - iovecs []iovecBuffer - iovecsOutput []iovecBuffer - msgHdrs []rawfile.MsgHdrX - msgHdrsOutput []rawfile.MsgHdrX - buffers []*buf.Buffer - stopFd stopfd.StopFD - tunWriter N.VectorisedWriter - options Options - inet4Address [4]byte - inet6Address [16]byte - routeSet bool + 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 } type iovecBuffer struct { @@ -111,14 +110,14 @@ func New(options Options) (Tun, error) { unix.Close(tunFd) return nil, err } - err = configure(tunFd, options.MTU, batchSize) + err = configure(tunFd, options.EXP_MultiPendingPackets, batchSize) if err != nil { unix.Close(tunFd) return nil, err } } else { tunFd = options.FileDescriptor - err := configure(tunFd, options.MTU, batchSize) + err := configure(tunFd, options.EXP_MultiPendingPackets, batchSize) if err != nil { return nil, err } @@ -133,6 +132,7 @@ func New(options Options) (Tun, error) { msgHdrs: make([]rawfile.MsgHdrX, batchSize), msgHdrsOutput: make([]rawfile.MsgHdrX, batchSize), stopFd: common.Must1(stopfd.New()), + writeMsgX: options.EXP_SendMsgX, } for i := 0; i < batchSize; i++ { nativeTun.iovecs[i] = newIovecBuffer(int(options.MTU)) @@ -144,11 +144,6 @@ func New(options Options) (Tun, error) { if len(options.Inet6Address) > 0 { nativeTun.inet6Address = options.Inet6Address[0].Addr().As16() } - var ok bool - nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile) - if !ok { - panic("create vectorised writer") - } return nativeTun, nil } @@ -182,17 +177,6 @@ func init() { packetHeaderVec6.SetLen(4) } -func (t *NativeTun) WriteVectorised(buffers []*buf.Buffer) error { - var packetHeader []byte - switch header.IPVersion(buffers[0].Bytes()) { - case header.IPv4Version: - packetHeader = packetHeader4[:] - case header.IPv6Version: - packetHeader = packetHeader6[:] - } - return t.tunWriter.WriteVectorised(append([]*buf.Buffer{buf.As(packetHeader)}, buffers...)) -} - const utunControlName = "com.apple.net.utun_control" const ( @@ -332,12 +316,12 @@ func create(tunFd int, ifIndex int, name string, options Options) error { return nil } -func configure(tunFd int, tunMTU uint32, batchSize int) error { +func configure(tunFd int, multiPendingPackets bool, batchSize int) error { err := unix.SetNonblock(tunFd, true) if err != nil { return os.NewSyscallError("SetNonblock", err) } - if tunMTU < 49152 { + if multiPendingPackets { const UTUN_OPT_MAX_PENDING_PACKETS = 16 err = unix.SetsockoptInt(tunFd, 2, UTUN_OPT_MAX_PENDING_PACKETS, batchSize) if err != nil { @@ -347,10 +331,6 @@ func configure(tunFd int, tunMTU uint32, batchSize int) error { return nil } -func (t *NativeTun) BatchSize() int { - return t.batchSize -} - func (t *NativeTun) BatchRead() ([]*buf.Buffer, error) { for i := 0; i < t.batchSize; i++ { iovecs := t.iovecs[i].nextIovecs() @@ -384,15 +364,27 @@ func (t *NativeTun) BatchRead() ([]*buf.Buffer, error) { } func (t *NativeTun) BatchWrite(buffers []*buf.Buffer) error { - for i, buffer := range buffers { - iovecs := t.iovecsOutput[i].nextIovecsOutput(buffer) - t.msgHdrsOutput[i] = rawfile.MsgHdrX{} - t.msgHdrsOutput[i].Msg.Iov = &iovecs[0] - t.msgHdrsOutput[i].Msg.Iovlen = 2 - } - _, errno := rawfile.NonBlockingSendMMsg(t.tunFd, t.msgHdrsOutput[:len(buffers)]) - if errno != 0 { - return errno + if !t.writeMsgX { + for i, buffer := range buffers { + t.iovecsOutput[i].nextIovecsOutput(buffer) + } + for i := range buffers { + errno := rawfile.NonBlockingWriteIovec(t.tunFd, t.iovecsOutput[i].iovecs) + if errno != 0 { + return errno + } + } + } else { + for i, buffer := range buffers { + iovecs := t.iovecsOutput[i].nextIovecsOutput(buffer) + t.msgHdrsOutput[i] = rawfile.MsgHdrX{} + t.msgHdrsOutput[i].Msg.Iov = &iovecs[0] + t.msgHdrsOutput[i].Msg.Iovlen = 2 + } + _, errno := rawfile.NonBlockingSendMMsg(t.tunFd, t.msgHdrsOutput[:len(buffers)]) + if errno != 0 { + return errno + } } return nil } diff --git a/tun_darwin_gvisor.go b/tun_darwin_gvisor.go index cae8678..7879bb5 100644 --- a/tun_darwin_gvisor.go +++ b/tun_darwin_gvisor.go @@ -6,16 +6,43 @@ import ( "github.com/sagernet/gvisor/pkg/tcpip/link/qdisc/fifo" "github.com/sagernet/gvisor/pkg/tcpip/stack" "github.com/sagernet/sing-tun/internal/fdbased_darwin" + "github.com/sagernet/sing-tun/internal/rawfile_darwin" + + "golang.org/x/sys/unix" ) var _ GVisorTun = (*NativeTun)(nil) +func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) { + iovecs := t.iovecsOutputDefault + var dataLen int + for _, packetSlice := range pkt.AsSlices() { + dataLen += len(packetSlice) + iovec := unix.Iovec{ + Base: &packetSlice[0], + } + 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 + } else { + return 0, errno + } +} + func (t *NativeTun) NewEndpoint() (stack.LinkEndpoint, stack.NICOptions, error) { ep, err := fdbased.New(&fdbased.Options{ - FDs: []int{t.tunFd}, - MTU: t.options.MTU, - RXChecksumOffload: true, - PacketDispatchMode: fdbased.RecvMMsg, + FDs: []int{t.tunFd}, + MTU: t.options.MTU, + RXChecksumOffload: true, + PacketDispatchMode: fdbased.RecvMMsg, + MultiPendingPackets: t.options.EXP_MultiPendingPackets, + SendMsgX: t.options.EXP_SendMsgX, }) if err != nil { return nil, stack.NICOptions{}, err diff --git a/tun_linux.go b/tun_linux.go index 9c28377..6d7dfed 100644 --- a/tun_linux.go +++ b/tun_linux.go @@ -18,10 +18,8 @@ import ( "github.com/sagernet/sing-tun/internal/gtcpip/header" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" - N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/rw" "github.com/sagernet/sing/common/shell" "github.com/sagernet/sing/common/x/list" @@ -32,22 +30,22 @@ import ( var _ LinuxTUN = (*NativeTun)(nil) type NativeTun struct { - tunFd int - tunFile *os.File - tunWriter N.VectorisedWriter - interfaceCallback *list.Element[DefaultInterfaceUpdateCallback] - options Options - ruleIndex6 []int - readAccess sync.Mutex - writeAccess sync.Mutex - vnetHdr bool - writeBuffer []byte - gsoToWrite []int - tcpGROTable *tcpGROTable - udpGroAccess sync.Mutex - udpGROTable *udpGROTable - gro groDisablementFlags - txChecksumOffload bool + tunFd int + tunFile *os.File + iovecsOutputDefault []unix.Iovec + interfaceCallback *list.Element[DefaultInterfaceUpdateCallback] + options Options + ruleIndex6 []int + readAccess sync.Mutex + writeAccess sync.Mutex + vnetHdr bool + writeBuffer []byte + gsoToWrite []int + tcpGROTable *tcpGROTable + udpGroAccess sync.Mutex + udpGROTable *udpGROTable + gro groDisablementFlags + txChecksumOffload bool } func New(options Options) (Tun, error) { @@ -77,11 +75,6 @@ func New(options Options) (Tun, error) { options: options, } } - var ok bool - nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile) - if !ok { - panic("create vectorised writer") - } return nativeTun, nil } @@ -402,20 +395,6 @@ func (t *NativeTun) Write(p []byte) (n int, err error) { return t.tunFile.Write(p) } -func (t *NativeTun) WriteVectorised(buffers []*buf.Buffer) error { - if t.vnetHdr { - n := buf.LenMulti(buffers) - buffer := buf.NewSize(virtioNetHdrLen + n) - buffer.Truncate(virtioNetHdrLen) - buf.CopyMulti(buffer.Extend(n), buffers) - _, err := t.tunFile.Write(buffer.Bytes()) - buffer.Release() - return err - } else { - return t.tunWriter.WriteVectorised(buffers) - } -} - func (t *NativeTun) FrontHeadroom() int { if t.vnetHdr { return virtioNetHdrLen diff --git a/tun_linux_gvisor.go b/tun_linux_gvisor.go index 3e26e18..cb0561b 100644 --- a/tun_linux_gvisor.go +++ b/tun_linux_gvisor.go @@ -3,8 +3,11 @@ package tun import ( + "github.com/sagernet/gvisor/pkg/rawfile" "github.com/sagernet/gvisor/pkg/tcpip/link/fdbased" "github.com/sagernet/gvisor/pkg/tcpip/stack" + + "golang.org/x/sys/unix" ) func init() { @@ -13,6 +16,28 @@ func init() { var _ GVisorTun = (*NativeTun)(nil) +func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) { + iovecs := t.iovecsOutputDefault + var dataLen int + for _, packetSlice := range pkt.AsSlices() { + dataLen += len(packetSlice) + iovec := unix.Iovec{ + Base: &packetSlice[0], + } + 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 + } else { + return 0, errno + } +} + func (t *NativeTun) NewEndpoint() (stack.LinkEndpoint, stack.NICOptions, error) { if t.vnetHdr { ep, err := fdbased.New(&fdbased.Options{ diff --git a/tun_windows.go b/tun_windows.go index dde6199..66fb13d 100644 --- a/tun_windows.go +++ b/tun_windows.go @@ -17,7 +17,6 @@ import ( "github.com/sagernet/sing-tun/internal/wintun" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/atomic" - "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/windnsapi" @@ -517,11 +516,6 @@ func (t *NativeTun) write(packetElementList [][]byte) (n int, err error) { return 0, fmt.Errorf("write failed: %w", err) } -func (t *NativeTun) WriteVectorised(buffers []*buf.Buffer) error { - defer buf.ReleaseMulti(buffers) - return common.Error(t.write(buf.ToSliceMulti(buffers))) -} - func (t *NativeTun) Close() error { var err error t.closeOnce.Do(func() { diff --git a/tun_windows_gvisor.go b/tun_windows_gvisor.go index 463a88b..2ead278 100644 --- a/tun_windows_gvisor.go +++ b/tun_windows_gvisor.go @@ -11,6 +11,10 @@ import ( var _ GVisorTun = (*NativeTun)(nil) +func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) { + return t.write(pkt.AsSlices()) +} + func (t *NativeTun) NewEndpoint() (stack.LinkEndpoint, stack.NICOptions, error) { return &WintunEndpoint{tun: t}, stack.NICOptions{}, nil }