netstack_test.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package netstack
  5. import (
  6. "runtime"
  7. "testing"
  8. "gvisor.dev/gvisor/pkg/refs"
  9. "inet.af/netaddr"
  10. "tailscale.com/net/packet"
  11. "tailscale.com/net/tsdial"
  12. "tailscale.com/net/tstun"
  13. "tailscale.com/wgengine"
  14. "tailscale.com/wgengine/filter"
  15. )
  16. // TestInjectInboundLeak tests that injectInbound doesn't leak memory.
  17. // See https://github.com/tailscale/tailscale/issues/3762
  18. func TestInjectInboundLeak(t *testing.T) {
  19. tunDev := tstun.NewFake()
  20. dialer := new(tsdial.Dialer)
  21. logf := func(format string, args ...any) {
  22. if !t.Failed() {
  23. t.Logf(format, args...)
  24. }
  25. }
  26. eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
  27. Tun: tunDev,
  28. Dialer: dialer,
  29. })
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. defer eng.Close()
  34. ig, ok := eng.(wgengine.InternalsGetter)
  35. if !ok {
  36. t.Fatal("not an InternalsGetter")
  37. }
  38. tunWrap, magicSock, d, ok := ig.GetInternals()
  39. if !ok {
  40. t.Fatal("failed to get internals")
  41. }
  42. ns, err := Create(logf, tunWrap, eng, magicSock, dialer, d)
  43. if err != nil {
  44. t.Fatal(err)
  45. }
  46. defer ns.Close()
  47. ns.ProcessLocalIPs = true
  48. if err := ns.Start(); err != nil {
  49. t.Fatalf("Start: %v", err)
  50. }
  51. ns.atomicIsLocalIPFunc.Store(func(netaddr.IP) bool { return true })
  52. pkt := &packet.Parsed{}
  53. const N = 10_000
  54. ms0 := getMemStats()
  55. for i := 0; i < N; i++ {
  56. outcome := ns.injectInbound(pkt, tunWrap)
  57. if outcome != filter.DropSilently {
  58. t.Fatalf("got outcome %v; want DropSilently", outcome)
  59. }
  60. }
  61. ms1 := getMemStats()
  62. if grew := int64(ms1.HeapObjects) - int64(ms0.HeapObjects); grew >= N {
  63. t.Fatalf("grew by %v (which is too much and >= the %v packets we sent)", grew, N)
  64. }
  65. }
  66. func getMemStats() (ms runtime.MemStats) {
  67. runtime.GC()
  68. runtime.ReadMemStats(&ms)
  69. return
  70. }
  71. func TestNetstackLeakMode(t *testing.T) {
  72. // See the comments in init(), and/or in issue #4309.
  73. // Influenced by an envknob that may be useful in tests, so just check that
  74. // it's not the oddly behaving zero value.
  75. if refs.GetLeakMode() == 0 {
  76. t.Fatalf("refs.leakMode is 0, want a non-zero value")
  77. }
  78. }