feature/conn25: return expired assignments to address pools

Make it possible to remove the least recently used expired address
assignment from addrAssignments.
Before checking out a new address from the IP pools, return a handful of
expired addresses.

Updates tailscale/corp#39975

Signed-off-by: Fran Bull <fran@tailscale.com>
This commit is contained in:
Fran Bull
2026-05-01 07:41:19 -07:00
committed by franbull
parent 82346f3882
commit 2f45a6a9d8
4 changed files with 208 additions and 52 deletions
+84 -1
View File
@@ -4,17 +4,20 @@
package conn25
import (
"fmt"
"net/netip"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"tailscale.com/tstest"
)
func TestAssignmentsExpire(t *testing.T) {
clock := tstest.NewClock(tstest.ClockOpts{Start: time.Now()})
assignments := addrAssignments{clock: clock}
as := addrs{
as := &addrs{
dst: netip.MustParseAddr("0.0.0.1"),
magic: netip.MustParseAddr("0.0.0.2"),
transit: netip.MustParseAddr("0.0.0.3"),
@@ -64,3 +67,83 @@ func TestAssignmentsExpire(t *testing.T) {
t.Fatalf("expected foundAs to expire after now")
}
}
func TestPopExpired(t *testing.T) {
clock := tstest.NewClock(tstest.ClockOpts{Start: time.Now()})
assignments := addrAssignments{clock: clock}
makeAndAddAddrs := func(n int) *addrs {
t.Helper()
as := &addrs{
dst: netip.MustParseAddr(fmt.Sprintf("0.0.1.%d", n)),
magic: netip.MustParseAddr(fmt.Sprintf("0.0.2.%d", n)),
transit: netip.MustParseAddr(fmt.Sprintf("0.0.3.%d", n)),
app: "a",
domain: "example.com.",
}
err := assignments.insert(as)
if err != nil {
t.Fatal(err)
}
return as
}
// cmp.Diff addrs ignoring expiresAt
doDiff := func(want, got *addrs) string {
t.Helper()
return cmp.Diff(
want,
got,
cmp.AllowUnexported(addrs{}),
cmpopts.EquateComparable(netip.Addr{}),
cmpopts.IgnoreFields(addrs{}, "expiresAt"),
)
}
testAddrs := []*addrs{}
for i := range 2 {
testAddrs = append(testAddrs, makeAndAddAddrs(i+1))
clock.Advance(1 * time.Second)
}
if len(assignments.byMagicIP) != 2 {
t.Fatalf("test setup wrong")
}
nn := assignments.popExpired(clock.Now())
want := &addrs{} // invalid addr
if diff := doDiff(want, nn); diff != "" {
t.Fatalf("only expired addresses are removed: %s", diff)
}
if len(assignments.byMagicIP) != 2 {
t.Fatalf("nothing should have been removed")
}
if nn.isValid() {
t.Fatal("empty addrs should be invalid")
}
clock.Advance(2 * defaultExpiry) // all addrs are now expired
want = testAddrs[0]
nn = assignments.popExpired(clock.Now())
if diff := doDiff(want, nn); diff != "" {
t.Fatal(diff)
}
if len(assignments.byMagicIP) != 1 {
t.Fatalf("an assignment should have been removed")
}
want = testAddrs[1]
nn = assignments.popExpired(clock.Now())
if diff := doDiff(want, nn); diff != "" {
t.Fatal(diff)
}
if len(assignments.byMagicIP) != 0 {
t.Fatalf("an assignment should have been removed")
}
want = &addrs{}
nn = assignments.popExpired(clock.Now())
if diff := doDiff(want, nn); diff != "" {
t.Fatal(diff)
}
if len(assignments.byMagicIP) != 0 {
t.Fatalf("there should have been no change")
}
}