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)