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)
 | 
									msgs := make([]ipv6.Message, IdealBatchSize)
 | 
				
			||||||
				for i := range msgs {
 | 
									for i := range msgs {
 | 
				
			||||||
					msgs[i].Buffers = make(net.Buffers, 1)
 | 
										msgs[i].Buffers = make(net.Buffers, 1)
 | 
				
			||||||
					msgs[i].OOB = make([]byte, controlSize)
 | 
										msgs[i].OOB = make([]byte, stickyControlSize+gsoControlSize)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return &msgs
 | 
									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) {
 | 
					func setSrcControl(control *[]byte, ep *StdNetEndpoint) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getGSOSize parses control for UDP_GRO and if found returns its GSO size data.
 | 
					// stickyControlSize returns the recommended buffer size for pooling sticky
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
// offloading control data.
 | 
					// offloading control data.
 | 
				
			||||||
const controlSize = 0
 | 
					const stickyControlSize = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StdNetSupportsStickySockets = false
 | 
					const StdNetSupportsStickySockets = false
 | 
				
			||||||
@ -8,7 +8,6 @@
 | 
				
			|||||||
package conn
 | 
					package conn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"net/netip"
 | 
						"net/netip"
 | 
				
			||||||
	"unsafe"
 | 
						"unsafe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -106,54 +105,8 @@ func setSrcControl(control *[]byte, ep *StdNetEndpoint) {
 | 
				
			|||||||
	*control = append(*control, ep.src...)
 | 
						*control = append(*control, ep.src...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					// stickyControlSize returns the recommended buffer size for pooling sticky
 | 
				
			||||||
	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
 | 
					 | 
				
			||||||
// offloading control data.
 | 
					// offloading control data.
 | 
				
			||||||
var controlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo) + unix.CmsgSpace(sizeOfGSOData)
 | 
					var stickyControlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StdNetSupportsStickySockets = true
 | 
					const StdNetSupportsStickySockets = true
 | 
				
			||||||
@ -60,7 +60,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		setSrc(ep, netip.MustParseAddr("127.0.0.1"), 5)
 | 
							setSrc(ep, netip.MustParseAddr("127.0.0.1"), 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		control := make([]byte, controlSize)
 | 
							control := make([]byte, stickyControlSize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		setSrcControl(&control, ep)
 | 
							setSrcControl(&control, ep)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,7 +89,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		setSrc(ep, netip.MustParseAddr("::1"), 5)
 | 
							setSrc(ep, netip.MustParseAddr("::1"), 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		control := make([]byte, controlSize)
 | 
							control := make([]byte, stickyControlSize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		setSrcControl(&control, ep)
 | 
							setSrcControl(&control, ep)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -113,7 +113,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("ClearOnNoSrc", func(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 := (*unix.Cmsghdr)(unsafe.Pointer(&control[0]))
 | 
				
			||||||
		hdr.Level = 1
 | 
							hdr.Level = 1
 | 
				
			||||||
		hdr.Type = 2
 | 
							hdr.Type = 2
 | 
				
			||||||
@ -129,7 +129,7 @@ func Test_setSrcControl(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func Test_getSrcFromControl(t *testing.T) {
 | 
					func Test_getSrcFromControl(t *testing.T) {
 | 
				
			||||||
	t.Run("IPv4", func(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 := (*unix.Cmsghdr)(unsafe.Pointer(&control[0]))
 | 
				
			||||||
		hdr.Level = unix.IPPROTO_IP
 | 
							hdr.Level = unix.IPPROTO_IP
 | 
				
			||||||
		hdr.Type = unix.IP_PKTINFO
 | 
							hdr.Type = unix.IP_PKTINFO
 | 
				
			||||||
@ -149,7 +149,7 @@ func Test_getSrcFromControl(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	t.Run("IPv6", func(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 := (*unix.Cmsghdr)(unsafe.Pointer(&control[0]))
 | 
				
			||||||
		hdr.Level = unix.IPPROTO_IPV6
 | 
							hdr.Level = unix.IPPROTO_IPV6
 | 
				
			||||||
		hdr.Type = unix.IPV6_PKTINFO
 | 
							hdr.Type = unix.IPV6_PKTINFO
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user