1
0

tun_linux_test.go 3.5 KB

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