gso_linux.go 1.7 KB

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