tun_linux_test.go 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. //go:build !e2e_testing
  2. // +build !e2e_testing
  3. package overlay
  4. import (
  5. "testing"
  6. )
  7. var runAdvMSSTests = []struct {
  8. name string
  9. tun *tun
  10. r Route
  11. expected int
  12. }{
  13. // Standard case, default MTU is the device max MTU
  14. {"default", &tun{DefaultMTU: 1440, MaxMTU: 1440}, Route{}, 0},
  15. {"default-min", &tun{DefaultMTU: 1440, MaxMTU: 1440}, Route{MTU: 1440}, 0},
  16. {"default-low", &tun{DefaultMTU: 1440, MaxMTU: 1440}, Route{MTU: 1200}, 1160},
  17. // Case where we have a route MTU set higher than the default
  18. {"route", &tun{DefaultMTU: 1440, MaxMTU: 8941}, Route{}, 1400},
  19. {"route-min", &tun{DefaultMTU: 1440, MaxMTU: 8941}, Route{MTU: 1440}, 1400},
  20. {"route-high", &tun{DefaultMTU: 1440, MaxMTU: 8941}, Route{MTU: 8941}, 0},
  21. }
  22. func TestTunAdvMSS(t *testing.T) {
  23. for _, tt := range runAdvMSSTests {
  24. t.Run(tt.name, func(t *testing.T) {
  25. o := tt.tun.advMSS(tt.r)
  26. if o != tt.expected {
  27. t.Errorf("got %d, want %d", o, tt.expected)
  28. }
  29. })
  30. }
  31. }
  32. // TestOffloadUSOEnabled pins the single source of truth for the per-queue USO
  33. // capability: it is derived from the negotiated offload mask, so the mask
  34. // stored on the tun and the capability reported to coalescers cannot drift.
  35. func TestOffloadUSOEnabled(t *testing.T) {
  36. // usoAndTSOOffloadFlags must be a strict superset of tsoOffloadFlags. Otherwise
  37. // the TSO-only fallback (and the historic hardcoded-mask bug in
  38. // addQueue) would not actually be a downgrade.
  39. if usoAndTSOOffloadFlags&tsoOffloadFlags != tsoOffloadFlags {
  40. t.Fatalf("usoAndTSOOffloadFlags (%#x) is not a superset of tsoOffloadFlags (%#x)", usoAndTSOOffloadFlags, tsoOffloadFlags)
  41. }
  42. if usoAndTSOOffloadFlags == tsoOffloadFlags {
  43. t.Fatal("usoAndTSOOffloadFlags must add bits beyond tsoOffloadFlags")
  44. }
  45. cases := []struct {
  46. name string
  47. offloadFlags uint
  48. wantUSO bool
  49. }{
  50. {"uso-negotiated", usoAndTSOOffloadFlags, true},
  51. {"tso-fallback", tsoOffloadFlags, false},
  52. {"no-vnet-hdr", 0, false},
  53. }
  54. for _, tc := range cases {
  55. t.Run(tc.name, func(t *testing.T) {
  56. if got := offloadUSOEnabled(tc.offloadFlags); got != tc.wantUSO {
  57. t.Fatalf("offloadUSOEnabled(%#x) = %v, want %v", tc.offloadFlags, got, tc.wantUSO)
  58. }
  59. })
  60. }
  61. }
  62. // TestAddQueueReplaysNegotiatedMask guards the device-wide TUNSETOFFLOAD
  63. // downgrade bug: addQueue must issue the exact mask newTun negotiated
  64. // (t.offloadFlags), not a hardcoded TSO-only mask. Because TUNSETOFFLOAD is
  65. // per-netdev, a narrower mask on an added queue silently disables USO for
  66. // every queue on a USO-capable kernel while the queues keep advertising it.
  67. //
  68. // A full multi-queue exercise needs /dev/net/tun and CAP_NET_ADMIN, which are
  69. // not available in CI/sandbox, so this asserts on the struct field that the
  70. // TUNSETOFFLOAD argument is read from.
  71. func TestAddQueueReplaysNegotiatedMask(t *testing.T) {
  72. t.Run("uso-negotiated", func(t *testing.T) {
  73. tn := &tun{vnetHdr: true, offloadFlags: usoAndTSOOffloadFlags}
  74. // The ioctl argument in addQueue is uintptr(t.offloadFlags);
  75. // it must equal the negotiated USO mask, and must NOT be the TSO-only
  76. // mask (the original bug).
  77. if tn.offloadFlags != usoAndTSOOffloadFlags {
  78. t.Fatalf("offloadFlags = %#x, want %#x", tn.offloadFlags, usoAndTSOOffloadFlags)
  79. }
  80. if tn.offloadFlags == tsoOffloadFlags {
  81. t.Fatal("added queue would downgrade USO: offloadFlags must not be the TSO-only mask when USO was negotiated")
  82. }
  83. })
  84. t.Run("tso-fallback", func(t *testing.T) {
  85. tn := &tun{vnetHdr: true, offloadFlags: tsoOffloadFlags}
  86. if tn.offloadFlags != tsoOffloadFlags {
  87. t.Fatalf("offloadFlags = %#x, want %#x", tn.offloadFlags, tsoOffloadFlags)
  88. }
  89. })
  90. }