Fix android GSO

This commit is contained in:
世界 2026-07-08 11:14:28 +08:00
parent ebd569670d
commit 5bb0784f61
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
2 changed files with 45 additions and 26 deletions

View file

@ -76,6 +76,14 @@ func New(options Options) (Tun, error) {
tunFile: os.NewFile(uintptr(options.FileDescriptor), "tun"), tunFile: os.NewFile(uintptr(options.FileDescriptor), "tun"),
options: options, options: options,
} }
if options.GSO {
err := nativeTun.enableGSO()
if err != nil {
if options.Logger != nil {
options.Logger.Warn(err)
}
}
}
} }
return nativeTun, nil return nativeTun, nil
} }
@ -189,28 +197,38 @@ func (t *NativeTun) enableGSO() error {
if !vnetHdrEnabled { if !vnetHdrEnabled {
return E.Cause(err, "enable offload: IFF_VNET_HDR not enabled") return E.Cause(err, "enable offload: IFF_VNET_HDR not enabled")
} }
t.vnetHdr = true
t.writeBuffer = make([]byte, virtioNetHdrLen+gsoMaxSize)
t.pendingBuffer = make([]byte, virtioNetHdrLen+gsoMaxSize)
t.tcpGROTable = newTCPGROTable()
t.udpGROTable = newUDPGROTable()
err = setTCPOffload(t.tunFd) err = setTCPOffload(t.tunFd)
if err != nil { if err != nil {
return E.Cause(err, "enable TCP offload") if !(errors.Is(err, unix.EPERM) && t.options.FileDescriptor != 0) {
t.options.Logger.Warn(E.Cause(err, "enable offload: set tcp offload"))
t.gro.disableTCPGRO()
t.gro.disableUDPGRO()
}
} else {
err = setUDPOffload(t.tunFd)
if err != nil {
t.options.Logger.Warn(E.Cause(err, "enable offload: set udp offload"))
t.gro.disableUDPGRO()
}
} }
t.vnetHdr = true
t.writeBuffer = make([]byte, virtioNetHdrLen+int(gsoMaxSize))
t.pendingBuffer = make([]byte, virtioNetHdrLen+int(gsoMaxSize))
t.readRawConn, err = t.tunFile.SyscallConn() t.readRawConn, err = t.tunFile.SyscallConn()
if err != nil { if err != nil {
return E.Cause(err, "enable offload: get raw conn") return E.Cause(err, "enable offload: get raw conn")
} }
t.tcpGROTable = newTCPGROTable()
t.udpGROTable = newUDPGROTable()
err = setUDPOffload(t.tunFd)
if err != nil {
t.gro.disableUDPGRO()
}
return nil return nil
} }
func (t *NativeTun) probeTCPGRO() error { func (t *NativeTun) probeTCPGRO() error {
ipPort := netip.AddrPortFrom(t.options.Inet4Address[0].Addr(), 0) probeAddr := netip.AddrFrom4([4]byte{127, 0, 0, 1})
if len(t.options.Inet4Address) > 0 {
probeAddr = t.options.Inet4Address[0].Addr()
}
ipPort := netip.AddrPortFrom(probeAddr, 0)
fingerprint := []byte("sing-tun-probe-tun-gro") fingerprint := []byte("sing-tun-probe-tun-gro")
segmentSize := len(fingerprint) segmentSize := len(fingerprint)
iphLen := 20 iphLen := 20
@ -267,6 +285,16 @@ func (t *NativeTun) Name() (string, error) {
} }
func (t *NativeTun) Start() error { func (t *NativeTun) Start() error {
if t.vnetHdr && t.gro.canTCPGRO() {
err := t.probeTCPGRO()
if err != nil {
t.gro.disableTCPGRO()
t.gro.disableUDPGRO()
if t.options.Logger != nil {
t.options.Logger.Warn(E.Cause(err, "disabled TUN TCP & UDP GRO due to GRO probe error"))
}
}
}
if t.options.FileDescriptor != 0 { if t.options.FileDescriptor != 0 {
return nil return nil
} }
@ -283,17 +311,6 @@ func (t *NativeTun) Start() error {
return E.Cause(err, "set tun up") return E.Cause(err, "set tun up")
} }
if t.vnetHdr && len(t.options.Inet4Address) > 0 {
err = t.probeTCPGRO()
if err != nil {
t.gro.disableTCPGRO()
t.gro.disableUDPGRO()
if t.options.Logger != nil {
t.options.Logger.Warn(E.Cause(err, "disabled TUN TCP & UDP GRO due to GRO probe error"))
}
}
}
if t.options.EXP_ExternalConfiguration { if t.options.EXP_ExternalConfiguration {
return nil return nil
} }

View file

@ -7,8 +7,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
E "github.com/sagernet/sing/common/exceptions"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -33,13 +31,17 @@ func checkVNETHDREnabled(fd int, name string) (bool, error) {
func setTCPOffload(fd int) error { func setTCPOffload(fd int) error {
err := unix.IoctlSetInt(fd, unix.TUNSETOFFLOAD, tunTCPOffloads) err := unix.IoctlSetInt(fd, unix.TUNSETOFFLOAD, tunTCPOffloads)
if err != nil { if err != nil {
return E.Cause(os.NewSyscallError("TUNSETOFFLOAD", err), "enable offload") return os.NewSyscallError("TUNSETOFFLOAD", err)
} }
return nil return nil
} }
func setUDPOffload(fd int) error { func setUDPOffload(fd int) error {
return unix.IoctlSetInt(fd, unix.TUNSETOFFLOAD, tunTCPOffloads|tunUDPOffloads) err := unix.IoctlSetInt(fd, unix.TUNSETOFFLOAD, tunTCPOffloads|tunUDPOffloads)
if err != nil {
return os.NewSyscallError("TUNSETOFFLOAD", err)
}
return nil
} }
type ifreqData struct { type ifreqData struct {