gso_linux.go raw

   1  //go:build linux
   2  
   3  /* SPDX-License-Identifier: MIT
   4   *
   5   * Copyright (C) 2017-2025 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)
  66