userspace_test.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package wgengine
  4. import (
  5. "fmt"
  6. "net/netip"
  7. "os"
  8. "reflect"
  9. "runtime"
  10. "testing"
  11. "go4.org/mem"
  12. "tailscale.com/cmd/testwrapper/flakytest"
  13. "tailscale.com/control/controlknobs"
  14. "tailscale.com/envknob"
  15. "tailscale.com/health"
  16. "tailscale.com/net/dns"
  17. "tailscale.com/net/netaddr"
  18. "tailscale.com/net/tstun"
  19. "tailscale.com/tailcfg"
  20. "tailscale.com/tstest"
  21. "tailscale.com/tstime/mono"
  22. "tailscale.com/types/key"
  23. "tailscale.com/types/netmap"
  24. "tailscale.com/types/opt"
  25. "tailscale.com/util/usermetric"
  26. "tailscale.com/wgengine/router"
  27. "tailscale.com/wgengine/wgcfg"
  28. )
  29. func TestNoteReceiveActivity(t *testing.T) {
  30. now := mono.Time(123456)
  31. var logBuf tstest.MemLogger
  32. confc := make(chan bool, 1)
  33. gotConf := func() bool {
  34. select {
  35. case <-confc:
  36. return true
  37. default:
  38. return false
  39. }
  40. }
  41. e := &userspaceEngine{
  42. timeNow: func() mono.Time { return now },
  43. recvActivityAt: map[key.NodePublic]mono.Time{},
  44. logf: logBuf.Logf,
  45. tundev: new(tstun.Wrapper),
  46. testMaybeReconfigHook: func() { confc <- true },
  47. trimmedNodes: map[key.NodePublic]bool{},
  48. }
  49. ra := e.recvActivityAt
  50. nk := key.NewNode().Public()
  51. // Activity on an untracked key should do nothing.
  52. e.noteRecvActivity(nk)
  53. if len(ra) != 0 {
  54. t.Fatalf("unexpected growth in map: now has %d keys; want 0", len(ra))
  55. }
  56. if logBuf.Len() != 0 {
  57. t.Fatalf("unexpected log write (and thus activity): %s", logBuf.Bytes())
  58. }
  59. // Now track it, but don't mark it trimmed, so shouldn't update.
  60. ra[nk] = 0
  61. e.noteRecvActivity(nk)
  62. if len(ra) != 1 {
  63. t.Fatalf("unexpected growth in map: now has %d keys; want 1", len(ra))
  64. }
  65. if got := ra[nk]; got != now {
  66. t.Fatalf("time in map = %v; want %v", got, now)
  67. }
  68. if gotConf() {
  69. t.Fatalf("unexpected reconfig")
  70. }
  71. // Now mark it trimmed and expect an update.
  72. e.trimmedNodes[nk] = true
  73. e.noteRecvActivity(nk)
  74. if len(ra) != 1 {
  75. t.Fatalf("unexpected growth in map: now has %d keys; want 1", len(ra))
  76. }
  77. if got := ra[nk]; got != now {
  78. t.Fatalf("time in map = %v; want %v", got, now)
  79. }
  80. if !gotConf() {
  81. t.Fatalf("didn't get expected reconfig")
  82. }
  83. }
  84. func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
  85. nv := make([]tailcfg.NodeView, len(v))
  86. for i, n := range v {
  87. nv[i] = n.View()
  88. }
  89. return nv
  90. }
  91. func TestUserspaceEngineReconfig(t *testing.T) {
  92. ht := new(health.Tracker)
  93. reg := new(usermetric.Registry)
  94. e, err := NewFakeUserspaceEngine(t.Logf, 0, ht, reg)
  95. if err != nil {
  96. t.Fatal(err)
  97. }
  98. t.Cleanup(e.Close)
  99. ue := e.(*userspaceEngine)
  100. routerCfg := &router.Config{}
  101. for _, nodeHex := range []string{
  102. "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  103. "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  104. } {
  105. nm := &netmap.NetworkMap{
  106. Peers: nodeViews([]*tailcfg.Node{
  107. {
  108. ID: 1,
  109. Key: nkFromHex(nodeHex),
  110. },
  111. }),
  112. }
  113. nk, err := key.ParseNodePublicUntyped(mem.S(nodeHex))
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. cfg := &wgcfg.Config{
  118. Peers: []wgcfg.Peer{
  119. {
  120. PublicKey: nk,
  121. AllowedIPs: []netip.Prefix{
  122. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  123. },
  124. },
  125. },
  126. }
  127. e.SetNetworkMap(nm)
  128. err = e.Reconfig(cfg, routerCfg, &dns.Config{})
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. wantRecvAt := map[key.NodePublic]mono.Time{
  133. nkFromHex(nodeHex): 0,
  134. }
  135. if got := ue.recvActivityAt; !reflect.DeepEqual(got, wantRecvAt) {
  136. t.Errorf("wrong recvActivityAt\n got: %v\nwant: %v\n", got, wantRecvAt)
  137. }
  138. wantTrimmedNodes := map[key.NodePublic]bool{
  139. nkFromHex(nodeHex): true,
  140. }
  141. if got := ue.trimmedNodes; !reflect.DeepEqual(got, wantTrimmedNodes) {
  142. t.Errorf("wrong wantTrimmedNodes\n got: %v\nwant: %v\n", got, wantTrimmedNodes)
  143. }
  144. }
  145. }
  146. func TestUserspaceEnginePortReconfig(t *testing.T) {
  147. flakytest.Mark(t, "https://github.com/tailscale/tailscale/issues/2855")
  148. const defaultPort = 49983
  149. var knobs controlknobs.Knobs
  150. // Keep making a wgengine until we find an unused port
  151. var ue *userspaceEngine
  152. ht := new(health.Tracker)
  153. reg := new(usermetric.Registry)
  154. for i := range 100 {
  155. attempt := uint16(defaultPort + i)
  156. e, err := NewFakeUserspaceEngine(t.Logf, attempt, &knobs, ht, reg)
  157. if err != nil {
  158. t.Fatal(err)
  159. }
  160. ue = e.(*userspaceEngine)
  161. if ue.magicConn.LocalPort() == attempt {
  162. break
  163. }
  164. ue.Close()
  165. ue = nil
  166. }
  167. if ue == nil {
  168. t.Fatal("could not create a wgengine with a specific port")
  169. }
  170. t.Cleanup(ue.Close)
  171. startingPort := ue.magicConn.LocalPort()
  172. nodeKey, err := key.ParseNodePublicUntyped(mem.S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
  173. if err != nil {
  174. t.Fatal(err)
  175. }
  176. cfg := &wgcfg.Config{
  177. Peers: []wgcfg.Peer{
  178. {
  179. PublicKey: nodeKey,
  180. AllowedIPs: []netip.Prefix{
  181. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  182. },
  183. },
  184. },
  185. }
  186. routerCfg := &router.Config{}
  187. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  188. t.Fatal(err)
  189. }
  190. if got := ue.magicConn.LocalPort(); got != startingPort {
  191. t.Errorf("no debug setting changed local port to %d from %d", got, startingPort)
  192. }
  193. knobs.RandomizeClientPort.Store(true)
  194. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  195. t.Fatal(err)
  196. }
  197. if got := ue.magicConn.LocalPort(); got == startingPort {
  198. t.Errorf("debug setting did not change local port from %d", startingPort)
  199. }
  200. lastPort := ue.magicConn.LocalPort()
  201. knobs.RandomizeClientPort.Store(false)
  202. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  203. t.Fatal(err)
  204. }
  205. if startingPort == defaultPort {
  206. // Only try this if we managed to bind defaultPort the first time.
  207. // Otherwise, assume someone else on the computer is using defaultPort
  208. // and so Reconfig would have caused magicSockt to bind some other port.
  209. if got := ue.magicConn.LocalPort(); got != defaultPort {
  210. t.Errorf("debug setting did not change local port from %d to %d", startingPort, defaultPort)
  211. }
  212. }
  213. if got := ue.magicConn.LocalPort(); got == lastPort {
  214. t.Errorf("Reconfig did not change local port from %d", lastPort)
  215. }
  216. }
  217. // Test that enabling and disabling peer path MTU discovery works correctly.
  218. func TestUserspaceEnginePeerMTUReconfig(t *testing.T) {
  219. if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
  220. t.Skipf("skipping on %q; peer MTU not supported", runtime.GOOS)
  221. }
  222. defer os.Setenv("TS_DEBUG_ENABLE_PMTUD", os.Getenv("TS_DEBUG_ENABLE_PMTUD"))
  223. envknob.Setenv("TS_DEBUG_ENABLE_PMTUD", "")
  224. // Turn on debugging to help diagnose problems.
  225. defer os.Setenv("TS_DEBUG_PMTUD", os.Getenv("TS_DEBUG_PMTUD"))
  226. envknob.Setenv("TS_DEBUG_PMTUD", "true")
  227. var knobs controlknobs.Knobs
  228. ht := new(health.Tracker)
  229. reg := new(usermetric.Registry)
  230. e, err := NewFakeUserspaceEngine(t.Logf, 0, &knobs, ht, reg)
  231. if err != nil {
  232. t.Fatal(err)
  233. }
  234. t.Cleanup(e.Close)
  235. ue := e.(*userspaceEngine)
  236. if ue.magicConn.PeerMTUEnabled() != false {
  237. t.Error("peer MTU enabled by default, should not be")
  238. }
  239. osDefaultDF, err := ue.magicConn.DontFragSetting()
  240. if err != nil {
  241. t.Errorf("get don't fragment bit failed: %v", err)
  242. }
  243. t.Logf("Info: OS default don't fragment bit(s) setting: %v", osDefaultDF)
  244. // Build a set of configs to use as we change the peer MTU settings.
  245. nodeKey, err := key.ParseNodePublicUntyped(mem.S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
  246. if err != nil {
  247. t.Fatal(err)
  248. }
  249. cfg := &wgcfg.Config{
  250. Peers: []wgcfg.Peer{
  251. {
  252. PublicKey: nodeKey,
  253. AllowedIPs: []netip.Prefix{
  254. netip.PrefixFrom(netaddr.IPv4(100, 100, 99, 1), 32),
  255. },
  256. },
  257. },
  258. }
  259. routerCfg := &router.Config{}
  260. tests := []struct {
  261. desc string // test description
  262. wantP bool // desired value of PMTUD setting
  263. wantDF bool // desired value of don't fragment bits
  264. shouldP opt.Bool // if set, force peer MTU to this value
  265. }{
  266. {desc: "after_first_reconfig", wantP: false, wantDF: osDefaultDF, shouldP: ""},
  267. {desc: "enabling_PMTUD_first_time", wantP: true, wantDF: true, shouldP: "true"},
  268. {desc: "disabling_PMTUD", wantP: false, wantDF: false, shouldP: "false"},
  269. {desc: "enabling_PMTUD_second_time", wantP: true, wantDF: true, shouldP: "true"},
  270. {desc: "returning_to_default_PMTUD", wantP: false, wantDF: false, shouldP: ""},
  271. }
  272. for _, tt := range tests {
  273. t.Run(tt.desc, func(t *testing.T) {
  274. if v, ok := tt.shouldP.Get(); ok {
  275. knobs.PeerMTUEnable.Store(v)
  276. } else {
  277. knobs.PeerMTUEnable.Store(false)
  278. }
  279. if err := ue.Reconfig(cfg, routerCfg, &dns.Config{}); err != nil {
  280. t.Fatal(err)
  281. }
  282. if v := ue.magicConn.PeerMTUEnabled(); v != tt.wantP {
  283. t.Errorf("peer MTU set to %v, want %v", v, tt.wantP)
  284. }
  285. if v, err := ue.magicConn.DontFragSetting(); v != tt.wantDF || err != nil {
  286. t.Errorf("don't fragment bit set to %v, want %v, err %v", v, tt.wantP, err)
  287. }
  288. })
  289. }
  290. }
  291. func nkFromHex(hex string) key.NodePublic {
  292. if len(hex) != 64 {
  293. panic(fmt.Sprintf("%q is len %d; want 64", hex, len(hex)))
  294. }
  295. k, err := key.ParseNodePublicUntyped(mem.S(hex[:64]))
  296. if err != nil {
  297. panic(fmt.Sprintf("%q is not hex: %v", hex, err))
  298. }
  299. return k
  300. }
  301. // an experiment to see if genLocalAddrFunc was worth it. As of Go
  302. // 1.16, it still very much is. (30-40x faster)
  303. func BenchmarkGenLocalAddrFunc(b *testing.B) {
  304. la1 := netip.MustParseAddr("1.2.3.4")
  305. la2 := netip.MustParseAddr("::4")
  306. lanot := netip.MustParseAddr("5.5.5.5")
  307. var x bool
  308. b.Run("map1", func(b *testing.B) {
  309. b.ReportAllocs()
  310. b.ResetTimer()
  311. m := map[netip.Addr]bool{
  312. la1: true,
  313. }
  314. for range b.N {
  315. x = m[la1]
  316. x = m[lanot]
  317. }
  318. })
  319. b.Run("map2", func(b *testing.B) {
  320. b.ReportAllocs()
  321. b.ResetTimer()
  322. m := map[netip.Addr]bool{
  323. la1: true,
  324. la2: true,
  325. }
  326. for range b.N {
  327. x = m[la1]
  328. x = m[lanot]
  329. }
  330. })
  331. b.Run("or1", func(b *testing.B) {
  332. b.ReportAllocs()
  333. b.ResetTimer()
  334. f := func(t netip.Addr) bool {
  335. return t == la1
  336. }
  337. for range b.N {
  338. x = f(la1)
  339. x = f(lanot)
  340. }
  341. })
  342. b.Run("or2", func(b *testing.B) {
  343. b.ReportAllocs()
  344. b.ResetTimer()
  345. f := func(t netip.Addr) bool {
  346. return t == la1 || t == la2
  347. }
  348. for range b.N {
  349. x = f(la1)
  350. x = f(lanot)
  351. }
  352. })
  353. b.Logf("x = %v", x)
  354. }