mtu.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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 || len(routes) == 0 {
  22. // During system boot or temporary network disconnection, route may not be present yet.
  23. // Fallback gracefully to requested MTU if valid, or default 1360.
  24. if requested >= 576 {
  25. return requested, nil
  26. }
  27. return 1360, nil
  28. }
  29. link, err := netlink.LinkByIndex(routes[0].LinkIndex)
  30. if err != nil {
  31. if requested >= 576 {
  32. return requested, nil
  33. }
  34. return 1360, nil
  35. }
  36. limit := link.Attrs().MTU
  37. if routes[0].MTU > 0 && routes[0].MTU < limit {
  38. limit = routes[0].MTU
  39. }
  40. overhead := header + 16 + 8 + 20
  41. if remote.To4() == nil {
  42. overhead += 20
  43. }
  44. limit -= overhead
  45. if limit < 576 {
  46. return 0, fmt.Errorf("underlay MTU too small for AeroTUN")
  47. }
  48. if requested > limit {
  49. return limit, nil
  50. }
  51. return requested, nil
  52. }
  53. func (t *TunnelRunner) adjustMTU(remote net.IP, peerMTU int) error {
  54. mtu, err := underlayMTUForHeader(int(t.effectiveMTU.Load()), remote, packetHeaderSize(t.cfg.Protocol))
  55. if err != nil {
  56. return err
  57. }
  58. if peerMTU < mtu {
  59. mtu = peerMTU
  60. }
  61. if mtu == int(t.effectiveMTU.Load()) {
  62. return nil
  63. }
  64. ip, _, _ := net.ParseCIDR(t.cfg.LocalAddress)
  65. if ip.To4() == nil && mtu < 1280 {
  66. return fmt.Errorf("underlay cannot carry IPv6 tunnel MTU 1280")
  67. }
  68. names := []string{t.dev.Name()}
  69. if v, ok := t.dev.(*vethTun); ok {
  70. names = append(names, v.epName)
  71. }
  72. for _, name := range names {
  73. if _, err := runIP("link", "set", name, "mtu", fmt.Sprint(mtu)); err != nil {
  74. return err
  75. }
  76. }
  77. t.effectiveMTU.Store(int64(mtu))
  78. return nil
  79. }