From 7d4bb80d87276dd2e8addc5f5a25b82adbbed9a3 Mon Sep 17 00:00:00 2001 From: Cory Snider Date: Fri, 26 Jun 2026 11:37:16 -0400 Subject: [PATCH] d/libn/i/nftables: define dynamic maps, sets Add support for defining nftables maps and sets with size and timeout specified, which are required values for maps and sets that are updated from the packet path. Signed-off-by: Cory Snider --- .../nftables/incremental_update.nft.gotmpl | 4 ++++ .../libnetwork/internal/nftables/nftables_linux.go | 13 +++++++++++++ .../internal/nftables/nftables_linux_test.go | 4 ++++ .../libnetwork/internal/nftables/reload.nft.gotmpl | 4 ++++ .../nftables/testdata/TestReload/created.golden | 14 ++++++++++++++ .../nftables/testdata/TestReload/recovered.golden | 14 ++++++++++++++ 6 files changed, 53 insertions(+) diff --git a/daemon/libnetwork/internal/nftables/incremental_update.nft.gotmpl b/daemon/libnetwork/internal/nftables/incremental_update.nft.gotmpl index eeb0a95708..bb6ca38392 100644 --- a/daemon/libnetwork/internal/nftables/incremental_update.nft.gotmpl +++ b/daemon/libnetwork/internal/nftables/incremental_update.nft.gotmpl @@ -22,11 +22,15 @@ table {{$family}} {{$tableName}} { {{range .Maps}}map {{.Name}} { {{.ElementTypeExpr}} {{if len .Flags}}flags{{range .Flags}} {{.}}{{end}}{{end}} + {{if .Size}}size {{.Size}}{{end}} + {{if .Timeout}}timeout {{.Timeout.Milliseconds}}ms{{end}} } {{end}} {{range .Sets}}set {{.Name}} { {{.ElementTypeExpr}} {{if len .Flags}}flags{{range .Flags}} {{.}}{{end}}{{end}} + {{if .Size}}size {{.Size}}{{end}} + {{if .Timeout}}timeout {{.Timeout.Milliseconds}}ms{{end}} } {{end}} {{range .Chains}}{{if .MustFlush}}chain {{.Name}} { diff --git a/daemon/libnetwork/internal/nftables/nftables_linux.go b/daemon/libnetwork/internal/nftables/nftables_linux.go index 41236a156c..252d964cf9 100644 --- a/daemon/libnetwork/internal/nftables/nftables_linux.go +++ b/daemon/libnetwork/internal/nftables/nftables_linux.go @@ -56,6 +56,7 @@ import ( "strings" "sync" "text/template" + "time" "github.com/containerd/log" ) @@ -761,6 +762,8 @@ type nftMap struct { Name string ElementTypeExpr string Flags []string + Size int + Timeout time.Duration Elements map[string]mapValue AddedElements map[string]mapValue DeletedElements map[string]string @@ -773,6 +776,8 @@ type Map struct { Name string ElementType MapTyper Flags []string + Size int + Timeout time.Duration } func (m Map) create(ctx context.Context, t *table) (bool, error) { @@ -790,6 +795,8 @@ func (m Map) create(ctx context.Context, t *table) (bool, error) { Name: m.Name, ElementTypeExpr: m.ElementType.mapType(), Flags: slices.Clone(m.Flags), + Size: m.Size, + Timeout: m.Timeout, Elements: map[string]mapValue{}, AddedElements: map[string]mapValue{}, DeletedElements: map[string]string{}, @@ -910,6 +917,8 @@ type set struct { Name string ElementTypeExpr string Flags []string + Size int + Timeout time.Duration Elements map[string]setElementOptions AddedElements map[string]setElementOptions DeletedElements map[string]struct{} @@ -922,6 +931,8 @@ type Set struct { Name string ElementType SetTyper Flags []string + Size int + Timeout time.Duration } // See https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets @@ -941,6 +952,8 @@ func (sd Set) create(ctx context.Context, t *table) (bool, error) { Elements: map[string]setElementOptions{}, ElementTypeExpr: sd.ElementType.setType(), Flags: slices.Clone(sd.Flags), + Size: sd.Size, + Timeout: sd.Timeout, AddedElements: map[string]setElementOptions{}, DeletedElements: map[string]struct{}{}, MustFlush: true, diff --git a/daemon/libnetwork/internal/nftables/nftables_linux_test.go b/daemon/libnetwork/internal/nftables/nftables_linux_test.go index 3c67b9ef9d..6a8438d404 100644 --- a/daemon/libnetwork/internal/nftables/nftables_linux_test.go +++ b/daemon/libnetwork/internal/nftables/nftables_linux_test.go @@ -4,6 +4,7 @@ import ( "context" "os" "testing" + "time" "github.com/moby/moby/v2/internal/testutil/netnsutils" "gotest.tools/v3/assert" @@ -264,6 +265,9 @@ func TestReload(t *testing.T) { tm.Create(Set{Name: setName, ElementType: IPv4Addr, Flags: []string{"interval"}}) tm.Create(SetElement{SetName: setName, Element: "192.0.2.0/24", Comment: "}bar{"}) + tm.Create(Map{Name: "dynamic_map", ElementType: IPv4Addr.MapTo(EtherAddr), Flags: []string{"dynamic"}, Size: 1024, Timeout: 2*time.Minute + 30*time.Second + 500*time.Millisecond + 654*time.Microsecond}) + tm.Create(Set{Name: "dynamic_set", ElementType: IPv4Addr, Flags: []string{"dynamic"}, Size: 4096, Timeout: 5*time.Minute + 10*time.Second + 250*time.Millisecond + 123*time.Microsecond}) + applyAndCheck(t, t.Name()+"/created.golden", tbl, tm) // Delete the underlying nftables table. diff --git a/daemon/libnetwork/internal/nftables/reload.nft.gotmpl b/daemon/libnetwork/internal/nftables/reload.nft.gotmpl index 16dc523fc6..c2ce58bbe5 100644 --- a/daemon/libnetwork/internal/nftables/reload.nft.gotmpl +++ b/daemon/libnetwork/internal/nftables/reload.nft.gotmpl @@ -13,6 +13,8 @@ table {{$family}} {{$tableName}} { {{range .Maps}}map {{.Name}} { {{.ElementTypeExpr}} {{if len .Flags}}flags{{range .Flags}} {{.}}{{end}}{{end}} + {{if .Size}}size {{.Size}}{{end}} + {{if .Timeout}}timeout {{.Timeout.Milliseconds}}ms{{end}} {{if .Elements}}elements = { {{range $k,$v := .Elements}}{{$k}}{{if $v.Comment}} comment "{{$v.Comment}}"{{end}} : {{$v.Value}}, {{end -}} @@ -22,6 +24,8 @@ table {{$family}} {{$tableName}} { {{range .Sets}}set {{.Name}} { {{.ElementTypeExpr}} {{if len .Flags}}flags{{range .Flags}} {{.}}{{end}}{{end}} + {{if .Size}}size {{.Size}}{{end}} + {{if .Timeout}}timeout {{.Timeout.Milliseconds}}ms{{end}} {{if .Elements}}elements = { {{range $k,$v := .Elements}}{{$k}}{{if $v.Comment}} comment "{{$v.Comment}}"{{end}}, {{end -}} diff --git a/daemon/libnetwork/internal/nftables/testdata/TestReload/created.golden b/daemon/libnetwork/internal/nftables/testdata/TestReload/created.golden index e04d42d95a..e0e5f905c2 100644 --- a/daemon/libnetwork/internal/nftables/testdata/TestReload/created.golden +++ b/daemon/libnetwork/internal/nftables/testdata/TestReload/created.golden @@ -1,10 +1,24 @@ table ip this_is_a_table { + map dynamic_map { + type ipv4_addr : ether_addr + size 1024 + flags dynamic,timeout + timeout 2m30s500ms + } + map this_is_a_vmap { type ifname : verdict elements = { "eth0" : return, "eth1" comment "{foo}" : return } } + set dynamic_set { + type ipv4_addr + size 4096 + flags dynamic,timeout + timeout 5m10s250ms + } + set this_is_a_set { type ipv4_addr flags interval diff --git a/daemon/libnetwork/internal/nftables/testdata/TestReload/recovered.golden b/daemon/libnetwork/internal/nftables/testdata/TestReload/recovered.golden index af6f7683b0..2bbf0111e5 100644 --- a/daemon/libnetwork/internal/nftables/testdata/TestReload/recovered.golden +++ b/daemon/libnetwork/internal/nftables/testdata/TestReload/recovered.golden @@ -1,10 +1,24 @@ table ip this_is_a_table { + map dynamic_map { + type ipv4_addr : ether_addr + size 1024 + flags dynamic,timeout + timeout 2m30s500ms + } + map this_is_a_vmap { type ifname : verdict elements = { "eth0" : return, "eth1" comment "{foo}" : return } } + set dynamic_set { + type ipv4_addr + size 4096 + flags dynamic,timeout + timeout 5m10s250ms + } + set this_is_a_set { type ipv4_addr flags interval