Skip to content

Commit

Permalink
Fix GSO write
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Dec 13, 2023
1 parent 6a1419a commit 80a0549
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 271 deletions.
10 changes: 5 additions & 5 deletions stack_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,13 @@ func (s *System) wintunLoop(winTun WinTun) {
}
}

func (m *System) batchLoop(linuxTUN BatchTUN, batchSize int) {
frontHeadroom := m.tun.FrontHeadroom()
func (s *System) batchLoop(linuxTUN BatchTUN, batchSize int) {
frontHeadroom := s.tun.FrontHeadroom()
packetBuffers := make([][]byte, batchSize)
readBuffers := make([][]byte, batchSize)
packetSizes := make([]int, batchSize)
for i := range packetBuffers {
packetBuffers[i] = make([]byte, m.mtu+frontHeadroom+PacketOffset)
packetBuffers[i] = make([]byte, s.mtu+frontHeadroom+PacketOffset)
readBuffers[i] = packetBuffers[i][frontHeadroom:]
}
for {
Expand All @@ -201,7 +201,7 @@ func (m *System) batchLoop(linuxTUN BatchTUN, batchSize int) {
if E.IsClosed(err) {
return
}
m.logger.Error(E.Cause(err, "batch read packet"))
s.logger.Error(E.Cause(err, "batch read packet"))
}
if n == 0 {
continue
Expand All @@ -214,7 +214,7 @@ func (m *System) batchLoop(linuxTUN BatchTUN, batchSize int) {
packetBuffer := packetBuffers[i]
rawPacket := packetBuffer[:frontHeadroom+packetSize]
packet := packetBuffer[frontHeadroom+PacketOffset : frontHeadroom+packetSize]
m.processPacket(rawPacket, packet)
s.processPacket(rawPacket, packet)
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tun.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Handler interface {

type Tun interface {
io.ReadWriter
N.VectorisedWriter
N.FrontHeadroom
Close() error
}
Expand All @@ -33,6 +34,7 @@ type WinTun interface {
}

type BatchTUN interface {
Tun
BatchSize() int
BatchRead(buffers [][]byte, readN []int) (n int, err error)
}
Expand Down
53 changes: 22 additions & 31 deletions tun_linux.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package tun

import (
"io"
"math/rand"
"net"
"net/netip"
Expand All @@ -13,7 +12,10 @@ import (

"github.com/sagernet/netlink"
"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/rw"
"github.com/sagernet/sing/common/shell"
"github.com/sagernet/sing/common/x/list"
Expand All @@ -26,16 +28,16 @@ var _ BatchTUN = (*NativeTun)(nil)
type NativeTun struct {
tunFd int
tunFile *os.File
tunWriter N.VectorisedWriter
interfaceCallback *list.Element[DefaultInterfaceUpdateCallback]
options Options
ruleIndex6 []int
gsoEnabled bool
gsoBuffer []byte
tcp4GROTable *tcpGROTable
tcp6GROTable *tcpGROTable
}

func New(options Options) (Tun, error) {
var nativeTun *NativeTun
if options.FileDescriptor == 0 {
tunFd, err := open(options.Name, options.GSO)
if err != nil {
Expand All @@ -45,26 +47,28 @@ func New(options Options) (Tun, error) {
if err != nil {
return nil, E.Errors(err, unix.Close(tunFd))
}
nativeTun := &NativeTun{
nativeTun = &NativeTun{
tunFd: tunFd,
tunFile: os.NewFile(uintptr(tunFd), "tun"),
options: options,
}
runtime.SetFinalizer(nativeTun.tunFile, nil)
err = nativeTun.configure(tunLink)
if err != nil {
return nil, E.Errors(err, unix.Close(tunFd))
}
return nativeTun, nil
} else {
nativeTun := &NativeTun{
nativeTun = &NativeTun{
tunFd: options.FileDescriptor,
tunFile: os.NewFile(uintptr(options.FileDescriptor), "tun"),
options: options,
}
runtime.SetFinalizer(nativeTun.tunFile, nil)
return nativeTun, nil
}
var ok bool
nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile)
if !ok {
panic("create vectorised writer")
}
return nativeTun, nil
}

func (t *NativeTun) FrontHeadroom() int {
Expand All @@ -74,14 +78,6 @@ func (t *NativeTun) FrontHeadroom() int {
return 0
}

func (t *NativeTun) UpstreamWriter() io.Writer {
return t.tunFile
}

func (t *NativeTun) WriterReplaceable() bool {
return !t.gsoEnabled
}

func (t *NativeTun) Read(p []byte) (n int, err error) {
if t.gsoEnabled {
n, err = t.tunFile.Read(t.gsoBuffer)
Expand All @@ -105,22 +101,19 @@ func (t *NativeTun) Read(p []byte) (n int, err error) {

func (t *NativeTun) Write(p []byte) (n int, err error) {
if t.gsoEnabled {
defer func() {
t.tcp4GROTable.reset()
t.tcp6GROTable.reset()
}()
var toWrite []int
err = handleGRO([][]byte{p}, virtioNetHdrLen, t.tcp4GROTable, t.tcp6GROTable, &toWrite)
if err != nil {
return
}
if len(toWrite) == 0 {
return
}
common.ClearArray(p[:virtioNetHdrLen])
}
return t.tunFile.Write(p)
}

func (t *NativeTun) WriteVectorised(buffers []*buf.Buffer) error {
if t.gsoEnabled {
return t.WriteVectorised(append([]*buf.Buffer{buf.As(rw.ZeroBytes[:virtioNetHdrLen])}, buffers...))
} else {
return t.WriteVectorised(buffers)
}
}

func (t *NativeTun) BatchSize() int {
if !t.gsoEnabled {
return 1
Expand Down Expand Up @@ -233,8 +226,6 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
}
t.gsoEnabled = true
t.gsoBuffer = make([]byte, virtioNetHdrLen+int(t.options.GSOMaxSize))
t.tcp4GROTable = newTCPGROTable()
t.tcp6GROTable = newTCPGROTable()
}

err = netlink.LinkSetUp(tunLink)
Expand Down
Loading

0 comments on commit 80a0549

Please sign in to comment.