github.com/sagernet/wireguard-go@v0.0.0-20231215174105-89dec3b2f3e8/conn/gso_linux.go (about) 1 //go:build linux 2 3 /* SPDX-License-Identifier: MIT 4 * 5 * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 */ 7 8 package conn 9 10 import ( 11 "fmt" 12 "unsafe" 13 14 "golang.org/x/sys/unix" 15 ) 16 17 const ( 18 sizeOfGSOData = 2 19 ) 20 21 // getGSOSize parses control for UDP_GRO and if found returns its GSO size data. 22 func getGSOSize(control []byte) (int, error) { 23 var ( 24 hdr unix.Cmsghdr 25 data []byte 26 rem = control 27 err error 28 ) 29 30 for len(rem) > unix.SizeofCmsghdr { 31 hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem) 32 if err != nil { 33 return 0, fmt.Errorf("error parsing socket control message: %w", err) 34 } 35 if hdr.Level == unix.SOL_UDP && hdr.Type == unix.UDP_GRO && len(data) >= sizeOfGSOData { 36 var gso uint16 37 copy(unsafe.Slice((*byte)(unsafe.Pointer(&gso)), sizeOfGSOData), data[:sizeOfGSOData]) 38 return int(gso), nil 39 } 40 } 41 return 0, nil 42 } 43 44 // setGSOSize sets a UDP_SEGMENT in control based on gsoSize. It leaves existing 45 // data in control untouched. 46 func setGSOSize(control *[]byte, gsoSize uint16) { 47 existingLen := len(*control) 48 avail := cap(*control) - existingLen 49 space := unix.CmsgSpace(sizeOfGSOData) 50 if avail < space { 51 return 52 } 53 *control = (*control)[:cap(*control)] 54 gsoControl := (*control)[existingLen:] 55 hdr := (*unix.Cmsghdr)(unsafe.Pointer(&(gsoControl)[0])) 56 hdr.Level = unix.SOL_UDP 57 hdr.Type = unix.UDP_SEGMENT 58 hdr.SetLen(unix.CmsgLen(sizeOfGSOData)) 59 copy((gsoControl)[unix.CmsgLen(0):], unsafe.Slice((*byte)(unsafe.Pointer(&gsoSize)), sizeOfGSOData)) 60 *control = (*control)[:existingLen+space] 61 } 62 63 // gsoControlSize returns the recommended buffer size for pooling UDP 64 // offloading control data. 65 var gsoControlSize = unix.CmsgSpace(sizeOfGSOData)