2023-10-21 18:41:27 +02:00
|
|
|
//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))
|
2023-10-21 19:06:38 +02:00
|
|
|
copy((gsoControl)[unix.CmsgLen(0):], unsafe.Slice((*byte)(unsafe.Pointer(&gsoSize)), sizeOfGSOData))
|
2023-10-21 18:41:27 +02:00
|
|
|
*control = (*control)[:existingLen+space]
|
|
|
|
}
|
|
|
|
|
|
|
|
// gsoControlSize returns the recommended buffer size for pooling UDP
|
|
|
|
// offloading control data.
|
|
|
|
var gsoControlSize = unix.CmsgSpace(sizeOfGSOData)
|