net/udprelay: replace map+sync.Mutex with sync.Map for VNI lookup

This commit also introduces a sync.Mutex for guarding mutatable fields
on serverEndpoint, now that it is no longer guarded by the sync.Mutex
in Server.

These changes reduce lock contention and by effect increase aggregate
throughput under high flow count load. A benchmark on Linux with AWS
c8gn instances showed a ~30% increase in aggregate throughput (37Gb/s
vs 28Gb/s) for 12 tailscaled flows.

Updates tailscale/corp#35264

Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
Jordan Whited
2025-12-15 12:14:34 -08:00
committed by Jordan Whited
parent 951d711054
commit a663639bea
2 changed files with 93 additions and 82 deletions

View File

@@ -339,19 +339,18 @@ func TestServer_getNextVNILocked(t *testing.T) {
c := qt.New(t)
s := &Server{
nextVNI: minVNI,
byVNI: make(map[uint32]*serverEndpoint),
}
for i := uint64(0); i < uint64(totalPossibleVNI); i++ {
vni, err := s.getNextVNILocked()
if err != nil { // using quicktest here triples test time
t.Fatal(err)
}
s.byVNI[vni] = nil
s.serverEndpointByVNI.Store(vni, nil)
}
c.Assert(s.nextVNI, qt.Equals, minVNI)
_, err := s.getNextVNILocked()
c.Assert(err, qt.IsNotNil)
delete(s.byVNI, minVNI)
s.serverEndpointByVNI.Delete(minVNI)
_, err = s.getNextVNILocked()
c.Assert(err, qt.IsNil)
}
@@ -455,17 +454,17 @@ func TestServer_maybeRotateMACSecretLocked(t *testing.T) {
s := &Server{}
start := mono.Now()
s.maybeRotateMACSecretLocked(start)
qt.Assert(t, len(s.macSecrets), qt.Equals, 1)
macSecret := s.macSecrets[0]
qt.Assert(t, s.macSecrets.Len(), qt.Equals, 1)
macSecret := s.macSecrets.At(0)
s.maybeRotateMACSecretLocked(start.Add(macSecretRotationInterval - time.Nanosecond))
qt.Assert(t, len(s.macSecrets), qt.Equals, 1)
qt.Assert(t, s.macSecrets[0], qt.Equals, macSecret)
qt.Assert(t, s.macSecrets.Len(), qt.Equals, 1)
qt.Assert(t, s.macSecrets.At(0), qt.Equals, macSecret)
s.maybeRotateMACSecretLocked(start.Add(macSecretRotationInterval))
qt.Assert(t, len(s.macSecrets), qt.Equals, 2)
qt.Assert(t, s.macSecrets[1], qt.Equals, macSecret)
qt.Assert(t, s.macSecrets[0], qt.Not(qt.Equals), s.macSecrets[1])
qt.Assert(t, s.macSecrets.Len(), qt.Equals, 2)
qt.Assert(t, s.macSecrets.At(1), qt.Equals, macSecret)
qt.Assert(t, s.macSecrets.At(0), qt.Not(qt.Equals), s.macSecrets.At(1))
s.maybeRotateMACSecretLocked(s.macSecretRotatedAt.Add(macSecretRotationInterval))
qt.Assert(t, macSecret, qt.Not(qt.Equals), s.macSecrets[0])
qt.Assert(t, macSecret, qt.Not(qt.Equals), s.macSecrets[1])
qt.Assert(t, s.macSecrets[0], qt.Not(qt.Equals), s.macSecrets[1])
qt.Assert(t, macSecret, qt.Not(qt.Equals), s.macSecrets.At(0))
qt.Assert(t, macSecret, qt.Not(qt.Equals), s.macSecrets.At(1))
qt.Assert(t, s.macSecrets.At(0), qt.Not(qt.Equals), s.macSecrets.At(1))
}