conn: separate gso and sticky control
Android wants GSO but not sticky. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									24ea13351e
								
							
						
					
					
						commit
						5d37bd24e1
					
				@ -65,7 +65,7 @@ func NewStdNetBind() Bind {
 | 
			
		||||
				msgs := make([]ipv6.Message, IdealBatchSize)
 | 
			
		||||
				for i := range msgs {
 | 
			
		||||
					msgs[i].Buffers = make(net.Buffers, 1)
 | 
			
		||||
					msgs[i].OOB = make([]byte, controlSize)
 | 
			
		||||
					msgs[i].OOB = make([]byte, stickyControlSize+gsoControlSize)
 | 
			
		||||
				}
 | 
			
		||||
				return &msgs
 | 
			
		||||
			},
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								conn/gso_default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								conn/gso_default.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
//go:build !linux
 | 
			
		||||
 | 
			
		||||
/* SPDX-License-Identifier: MIT
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package conn
 | 
			
		||||
 | 
			
		||||
// getGSOSize parses control for UDP_GRO and if found returns its GSO size data.
 | 
			
		||||
func getGSOSize(control []byte) (int, error) {
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setGSOSize sets a UDP_SEGMENT in control based on gsoSize.
 | 
			
		||||
func setGSOSize(control *[]byte, gsoSize uint16) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gsoControlSize returns the recommended buffer size for pooling sticky and UDP
 | 
			
		||||
// offloading control data.
 | 
			
		||||
const gsoControlSize = 0
 | 
			
		||||
							
								
								
									
										65
									
								
								conn/gso_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								conn/gso_linux.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
//go:build linux
 | 
			
		||||
 | 
			
		||||
/* SPDX-License-Identifier: MIT
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package conn
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	sizeOfGSOData = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// getGSOSize parses control for UDP_GRO and if found returns its GSO size data.
 | 
			
		||||
func getGSOSize(control []byte) (int, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		hdr  unix.Cmsghdr
 | 
			
		||||
		data []byte
 | 
			
		||||
		rem  = control
 | 
			
		||||
		err  error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for len(rem) > unix.SizeofCmsghdr {
 | 
			
		||||
		hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, fmt.Errorf("error parsing socket control message: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
		if hdr.Level == unix.SOL_UDP && hdr.Type == unix.UDP_GRO && len(data) >= sizeOfGSOData {
 | 
			
		||||
			var gso uint16
 | 
			
		||||
			copy(unsafe.Slice((*byte)(unsafe.Pointer(&gso)), sizeOfGSOData), data[:sizeOfGSOData])
 | 
			
		||||
			return int(gso), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setGSOSize sets a UDP_SEGMENT in control based on gsoSize. It leaves existing
 | 
			
		||||
// data in control untouched.
 | 
			
		||||
func setGSOSize(control *[]byte, gsoSize uint16) {
 | 
			
		||||
	existingLen := len(*control)
 | 
			
		||||
	avail := cap(*control) - existingLen
 | 
			
		||||
	space := unix.CmsgSpace(sizeOfGSOData)
 | 
			
		||||
	if avail < space {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	*control = (*control)[:cap(*control)]
 | 
			
		||||
	gsoControl := (*control)[existingLen:]
 | 
			
		||||
	hdr := (*unix.Cmsghdr)(unsafe.Pointer(&(gsoControl)[0]))
 | 
			
		||||
	hdr.Level = unix.SOL_UDP
 | 
			
		||||
	hdr.Type = unix.UDP_SEGMENT
 | 
			
		||||
	hdr.SetLen(unix.CmsgLen(sizeOfGSOData))
 | 
			
		||||
	copy((gsoControl)[unix.SizeofCmsghdr:], unsafe.Slice((*byte)(unsafe.Pointer(&gsoSize)), sizeOfGSOData))
 | 
			
		||||
	*control = (*control)[:existingLen+space]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gsoControlSize returns the recommended buffer size for pooling UDP
 | 
			
		||||
// offloading control data.
 | 
			
		||||
var gsoControlSize = unix.CmsgSpace(sizeOfGSOData)
 | 
			
		||||
@ -35,17 +35,8 @@ func getSrcFromControl(control []byte, ep *StdNetEndpoint) {
 | 
			
		||||
func setSrcControl(control *[]byte, ep *StdNetEndpoint) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getGSOSize parses control for UDP_GRO and if found returns its GSO size data.
 | 
			
		||||
func getGSOSize(control []byte) (int, error) {
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setGSOSize sets a UDP_SEGMENT in control based on gsoSize.
 | 
			
		||||
func setGSOSize(control *[]byte, gsoSize uint16) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// controlSize returns the recommended buffer size for pooling sticky and UDP
 | 
			
		||||
// stickyControlSize returns the recommended buffer size for pooling sticky
 | 
			
		||||
// offloading control data.
 | 
			
		||||
const controlSize = 0
 | 
			
		||||
const stickyControlSize = 0
 | 
			
		||||
 | 
			
		||||
const StdNetSupportsStickySockets = false
 | 
			
		||||
@ -8,7 +8,6 @@
 | 
			
		||||
package conn
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/netip"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
@ -106,54 +105,8 @@ func setSrcControl(control *[]byte, ep *StdNetEndpoint) {
 | 
			
		||||
	*control = append(*control, ep.src...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	sizeOfGSOData = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// getGSOSize parses control for UDP_GRO and if found returns its GSO size data.
 | 
			
		||||
func getGSOSize(control []byte) (int, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		hdr  unix.Cmsghdr
 | 
			
		||||
		data []byte
 | 
			
		||||
		rem  = control
 | 
			
		||||
		err  error
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for len(rem) > unix.SizeofCmsghdr {
 | 
			
		||||
		hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, fmt.Errorf("error parsing socket control message: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
		if hdr.Level == unix.SOL_UDP && hdr.Type == unix.UDP_GRO && len(data) >= sizeOfGSOData {
 | 
			
		||||
			var gso uint16
 | 
			
		||||
			copy(unsafe.Slice((*byte)(unsafe.Pointer(&gso)), sizeOfGSOData), data[:sizeOfGSOData])
 | 
			
		||||
			return int(gso), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setGSOSize sets a UDP_SEGMENT in control based on gsoSize. It leaves existing
 | 
			
		||||
// data in control untouched.
 | 
			
		||||
func setGSOSize(control *[]byte, gsoSize uint16) {
 | 
			
		||||
	existingLen := len(*control)
 | 
			
		||||
	avail := cap(*control) - existingLen
 | 
			
		||||
	space := unix.CmsgSpace(sizeOfGSOData)
 | 
			
		||||
	if avail < space {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	*control = (*control)[:cap(*control)]
 | 
			
		||||
	gsoControl := (*control)[existingLen:]
 | 
			
		||||
	hdr := (*unix.Cmsghdr)(unsafe.Pointer(&(gsoControl)[0]))
 | 
			
		||||
	hdr.Level = unix.SOL_UDP
 | 
			
		||||
	hdr.Type = unix.UDP_SEGMENT
 | 
			
		||||
	hdr.SetLen(unix.CmsgLen(sizeOfGSOData))
 | 
			
		||||
	copy((gsoControl)[unix.SizeofCmsghdr:], unsafe.Slice((*byte)(unsafe.Pointer(&gsoSize)), sizeOfGSOData))
 | 
			
		||||
	*control = (*control)[:existingLen+space]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// controlSize returns the recommended buffer size for pooling sticky and UDP
 | 
			
		||||
// stickyControlSize returns the recommended buffer size for pooling sticky
 | 
			
		||||
// offloading control data.
 | 
			
		||||
var controlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo) + unix.CmsgSpace(sizeOfGSOData)
 | 
			
		||||
var stickyControlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo)
 | 
			
		||||
 | 
			
		||||
const StdNetSupportsStickySockets = true
 | 
			
		||||
@ -60,7 +60,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
		setSrc(ep, netip.MustParseAddr("127.0.0.1"), 5)
 | 
			
		||||
 | 
			
		||||
		control := make([]byte, controlSize)
 | 
			
		||||
		control := make([]byte, stickyControlSize)
 | 
			
		||||
 | 
			
		||||
		setSrcControl(&control, ep)
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
		setSrc(ep, netip.MustParseAddr("::1"), 5)
 | 
			
		||||
 | 
			
		||||
		control := make([]byte, controlSize)
 | 
			
		||||
		control := make([]byte, stickyControlSize)
 | 
			
		||||
 | 
			
		||||
		setSrcControl(&control, ep)
 | 
			
		||||
 | 
			
		||||
@ -113,7 +113,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("ClearOnNoSrc", func(t *testing.T) {
 | 
			
		||||
		control := make([]byte, controlSize)
 | 
			
		||||
		control := make([]byte, stickyControlSize)
 | 
			
		||||
		hdr := (*unix.Cmsghdr)(unsafe.Pointer(&control[0]))
 | 
			
		||||
		hdr.Level = 1
 | 
			
		||||
		hdr.Type = 2
 | 
			
		||||
@ -129,7 +129,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func Test_getSrcFromControl(t *testing.T) {
 | 
			
		||||
	t.Run("IPv4", func(t *testing.T) {
 | 
			
		||||
		control := make([]byte, controlSize)
 | 
			
		||||
		control := make([]byte, stickyControlSize)
 | 
			
		||||
		hdr := (*unix.Cmsghdr)(unsafe.Pointer(&control[0]))
 | 
			
		||||
		hdr.Level = unix.IPPROTO_IP
 | 
			
		||||
		hdr.Type = unix.IP_PKTINFO
 | 
			
		||||
@ -149,7 +149,7 @@ func Test_getSrcFromControl(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("IPv6", func(t *testing.T) {
 | 
			
		||||
		control := make([]byte, controlSize)
 | 
			
		||||
		control := make([]byte, stickyControlSize)
 | 
			
		||||
		hdr := (*unix.Cmsghdr)(unsafe.Pointer(&control[0]))
 | 
			
		||||
		hdr.Level = unix.IPPROTO_IPV6
 | 
			
		||||
		hdr.Type = unix.IPV6_PKTINFO
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user