mtu.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package aerotun
  2. import (
  3. "fmt"
  4. "net"
  5. "github.com/vishvananda/netlink"
  6. )
  7. // Account for our authenticated header/tag plus UDP and the outer IP header.
  8. // Route MTU and link MTU are local upper bounds; a smaller remote path MTU can
  9. // still require an explicitly lower configured MTU.
  10. func packetHeaderSize(version int) int {
  11. if version == 3 {
  12. return secureHeaderSize
  13. }
  14. return headerSize
  15. }
  16. func underlayMTU(requested int, remote net.IP) (int, error) {
  17. return underlayMTUForHeader(requested, remote, headerSize)
  18. }
  19. func underlayMTUForHeader(requested int, remote net.IP, header int) (int, error) {
  20. routes, err := netlink.RouteGet(remote)
  21. if err != nil {
  22. return 0, fmt.Errorf("remote underlay route: %w", err)
  23. }
  24. if len(routes) == 0 {
  25. return 0, fmt.Errorf("no underlay route to %s", remote)
  26. }
  27. link, err := netlink.LinkByIndex(routes[0].LinkIndex)
  28. if err != nil {
  29. return 0, err
  30. }
  31. limit := link.Attrs().MTU
  32. if routes[0].MTU > 0 && routes[0].MTU < limit {
  33. limit = routes[0].MTU
  34. }
  35. overhead := header + 16 + 8 + 20
  36. if remote.To4() == nil {
  37. overhead += 20
  38. }
  39. limit -= overhead
  40. if limit < 576 {
  41. return 0, fmt.Errorf("underlay MTU too small for AeroTUN")
  42. }
  43. if requested > limit {
  44. return limit, nil
  45. }
  46. return requested, nil
  47. }
  48. func (t *TunnelRunner) adjustMTU(remote net.IP, peerMTU int) error {
  49. mtu, err := underlayMTUForHeader(int(t.effectiveMTU.Load()), remote, packetHeaderSize(t.cfg.Protocol))
  50. if err != nil {
  51. return err
  52. }
  53. if peerMTU < mtu {
  54. mtu = peerMTU
  55. }
  56. if mtu == int(t.effectiveMTU.Load()) {
  57. return nil
  58. }
  59. ip, _, _ := net.ParseCIDR(t.cfg.LocalAddress)
  60. if ip.To4() == nil && mtu < 1280 {
  61. return fmt.Errorf("underlay cannot carry IPv6 tunnel MTU 1280")
  62. }
  63. names := []string{t.dev.Name()}
  64. if v, ok := t.dev.(*vethTun); ok {
  65. names = append(names, v.epName)
  66. }
  67. for _, name := range names {
  68. if _, err := runIP("link", "set", name, "mtu", fmt.Sprint(mtu)); err != nil {
  69. return err
  70. }
  71. }
  72. t.effectiveMTU.Store(int64(mtu))
  73. return nil
  74. }