From f0ea478cb811675a450839b8dcd351e43404efd4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 15 Apr 2025 16:46:30 +0400 Subject: [PATCH] feat: support address priority See https://github.com/jsimonetti/rtnetlink/pull/256 See https://github.com/siderolabs/talos/issues/10696 Support setting address priority, this is important to ensure that the prefix route has appropriate priority. For now, we don't have it exposed in the machine config except for the DHCP4 operator, so now both routes created explicitly by DHCP and routes created implicitly have same metric/priority: ``` 172.20.0.2 network RouteStatus inet4//172.20.0.0/24/1024 1 172.20.0.0/24 enp0s2 1024 172.20.0.2 network RouteStatus inet4/172.20.0.1//1024 1 172.20.0.1 enp0s2 1024 ``` Before this change, the first route would have a metric zero. Signed-off-by: Andrey Smirnov --- .../definitions/network/network.proto | 2 + go.mod | 4 +- go.sum | 8 +- .../pkg/controllers/network/address_spec.go | 5 +- .../controllers/network/address_spec_test.go | 155 ++++++------------ .../pkg/controllers/network/address_status.go | 1 + .../network/address_status_test.go | 70 ++------ .../network/nftables_chain_test.go | 15 +- .../pkg/controllers/network/operator/dhcp4.go | 1 + .../definitions/network/network.pb.go | 24 ++- .../definitions/network/network_vtproto.pb.go | 54 ++++++ pkg/machinery/go.mod | 2 +- pkg/machinery/go.sum | 8 +- .../resources/network/address_spec.go | 1 + .../resources/network/address_status.go | 1 + website/content/v1.10/reference/api.md | 2 + 16 files changed, 172 insertions(+), 181 deletions(-) diff --git a/api/resource/definitions/network/network.proto b/api/resource/definitions/network/network.proto index a9de05949..50c08ff85 100755 --- a/api/resource/definitions/network/network.proto +++ b/api/resource/definitions/network/network.proto @@ -18,6 +18,7 @@ message AddressSpecSpec { uint32 flags = 5; bool announce_with_arp = 6; talos.resource.definitions.enums.NetworkConfigLayer config_layer = 7; + uint32 priority = 8; } // AddressStatusSpec describes status of rendered secrets. @@ -32,6 +33,7 @@ message AddressStatusSpec { talos.resource.definitions.enums.NethelpersFamily family = 8; talos.resource.definitions.enums.NethelpersScope scope = 9; uint32 flags = 10; + uint32 priority = 11; } // BondMasterSpec describes bond settings if Kind == "bond". diff --git a/go.mod b/go.mod index 3f8a61c78..3fb0d6054 100644 --- a/go.mod +++ b/go.mod @@ -107,7 +107,7 @@ require ( github.com/hetznercloud/hcloud-go/v2 v2.21.0 github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 github.com/jeromer/syslogparser v1.1.0 - github.com/jsimonetti/rtnetlink/v2 v2.0.3-0.20241216183107-2d6e9f8ad3f2 + github.com/jsimonetti/rtnetlink/v2 v2.0.3 github.com/jxskiss/base62 v1.1.0 github.com/klauspost/compress v1.18.0 github.com/klauspost/cpuid/v2 v2.2.10 @@ -232,7 +232,7 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/cilium/ebpf v0.16.0 // indirect + github.com/cilium/ebpf v0.17.3 // indirect github.com/cloudflare/circl v1.6.0 // indirect github.com/containerd/continuity v0.4.4 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect diff --git a/go.sum b/go.sum index a012a54e0..c15594134 100644 --- a/go.sum +++ b/go.sum @@ -113,8 +113,8 @@ github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHe github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= -github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= -github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= +github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg= +github.com/cilium/ebpf v0.17.3/go.mod h1:G5EDHij8yiLzaqn0WjyfJHvRa+3aDlReIaLVRMvOyJk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= @@ -408,8 +408,8 @@ github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmK github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= github.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA= github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00= -github.com/jsimonetti/rtnetlink/v2 v2.0.3-0.20241216183107-2d6e9f8ad3f2 h1:4pspWog/mjnfv+B3rjEUfCoFL80T7J8ojK9ay8ApPCM= -github.com/jsimonetti/rtnetlink/v2 v2.0.3-0.20241216183107-2d6e9f8ad3f2/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= +github.com/jsimonetti/rtnetlink/v2 v2.0.3 h1:Jcp7GTnTPepoUAJ9+LhTa7ZiebvNS56T1GtlEUaPNFE= +github.com/jsimonetti/rtnetlink/v2 v2.0.3/go.mod h1:atIkksp/9fqtf6rpAw45JnttnP2gtuH9X88WPfWfS9A= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw= diff --git a/internal/app/machined/pkg/controllers/network/address_spec.go b/internal/app/machined/pkg/controllers/network/address_spec.go index 84f654a45..2f528cf78 100644 --- a/internal/app/machined/pkg/controllers/network/address_spec.go +++ b/internal/app/machined/pkg/controllers/network/address_spec.go @@ -207,7 +207,7 @@ func (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller // check if existing matches the spec: if it does, skip update if existing.Scope == uint8(address.TypedSpec().Scope) && existing.Flags == uint8(address.TypedSpec().Flags) && - existing.Attributes.Flags == uint32(address.TypedSpec().Flags) { + existing.Attributes.Flags == uint32(address.TypedSpec().Flags) && existing.Attributes.Priority == address.TypedSpec().Priority { return nil } @@ -218,6 +218,8 @@ func (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller zap.Stringer("new_scope", address.TypedSpec().Scope), zap.Stringer("old_flags", nethelpers.AddressFlags(existing.Attributes.Flags)), zap.Stringer("new_flags", address.TypedSpec().Flags), + zap.Uint32("old_priority", existing.Attributes.Priority), + zap.Uint32("new_priority", address.TypedSpec().Priority), ) // delete address to get new one assigned below @@ -240,6 +242,7 @@ func (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller Local: address.TypedSpec().Address.Addr().AsSlice(), Broadcast: broadcastAddr(address.TypedSpec().Address), Flags: uint32(address.TypedSpec().Flags), + Priority: address.TypedSpec().Priority, }, }); err != nil { // ignore EEXIST error diff --git a/internal/app/machined/pkg/controllers/network/address_spec_test.go b/internal/app/machined/pkg/controllers/network/address_spec_test.go index 9e1817c15..9752c542f 100644 --- a/internal/app/machined/pkg/controllers/network/address_spec_test.go +++ b/internal/app/machined/pkg/controllers/network/address_spec_test.go @@ -6,86 +6,48 @@ package network_test import ( - "context" "fmt" "math/rand/v2" "net" "net/netip" "os" - "sync" "testing" "time" - "github.com/cosi-project/runtime/pkg/controller/runtime" "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/state" - "github.com/cosi-project/runtime/pkg/state/impl/inmem" - "github.com/cosi-project/runtime/pkg/state/impl/namespaced" "github.com/jsimonetti/rtnetlink/v2" - "github.com/siderolabs/go-retry/retry" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" - "go.uber.org/zap/zaptest" "golang.org/x/sys/unix" + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/network" ) type AddressSpecSuite struct { - suite.Suite - - state state.State - - runtime *runtime.Runtime - wg sync.WaitGroup - - ctx context.Context //nolint:containedctx - ctxCancel context.CancelFunc -} - -func (suite *AddressSpecSuite) SetupTest() { - suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute) - - suite.state = state.WrapCore(namespaced.NewState(inmem.Build)) - - var err error - - suite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T())) - suite.Require().NoError(err) - - suite.Require().NoError(suite.runtime.RegisterController(&netctrl.AddressSpecController{})) - - suite.startRuntime() + ctest.DefaultSuite } func (suite *AddressSpecSuite) uniqueDummyInterface() string { return fmt.Sprintf("dummy%02x%02x%02x", rand.Int32()&0xff, rand.Int32()&0xff, rand.Int32()&0xff) } -func (suite *AddressSpecSuite) startRuntime() { - suite.wg.Add(1) - - go func() { - defer suite.wg.Done() - - suite.Assert().NoError(suite.runtime.Run(suite.ctx)) - }() -} - -func (suite *AddressSpecSuite) assertLinkAddress(linkName, address string) error { +func assertLinkAddress(asrt *assert.Assertions, linkName, address string) { addr := netip.MustParsePrefix(address) iface, err := net.InterfaceByName(linkName) - suite.Require().NoError(err) + asrt.NoError(err) conn, err := rtnetlink.Dial(nil) - suite.Require().NoError(err) + asrt.NoError(err) defer conn.Close() //nolint:errcheck linkAddresses, err := conn.Address.List() - suite.Require().NoError(err) + asrt.NoError(err) for _, linkAddress := range linkAddresses { if linkAddress.Index != uint32(iface.Index) { @@ -100,33 +62,31 @@ func (suite *AddressSpecSuite) assertLinkAddress(linkName, address string) error continue } - return nil + return } - return retry.ExpectedErrorf("address %s not found on %q", addr, linkName) + asrt.Failf("address not found", "address %s not found on %q", addr, linkName) } -func (suite *AddressSpecSuite) assertNoLinkAddress(linkName, address string) error { +func assertNoLinkAddress(asrt *assert.Assertions, linkName, address string) { addr := netip.MustParsePrefix(address) iface, err := net.InterfaceByName(linkName) - suite.Require().NoError(err) + asrt.NoError(err) conn, err := rtnetlink.Dial(nil) - suite.Require().NoError(err) + asrt.NoError(err) defer conn.Close() //nolint:errcheck linkAddresses, err := conn.Address.List() - suite.Require().NoError(err) + asrt.NoError(err) for _, linkAddress := range linkAddresses { if linkAddress.Index == uint32(iface.Index) && int(linkAddress.PrefixLength) == addr.Bits() && linkAddress.Attributes.Address.Equal(addr.Addr().AsSlice()) { - return retry.ExpectedErrorf("address %s is assigned to %q", addr, linkName) + asrt.Failf("address is still there", "address %s is assigned to %q", addr, linkName) } } - - return nil } func (suite *AddressSpecSuite) TestLoopback() { @@ -141,33 +101,26 @@ func (suite *AddressSpecSuite) TestLoopback() { } for _, res := range []resource.Resource{loopback} { - suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) + suite.Create(res) } - suite.Assert().NoError( - retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( - func() error { - return suite.assertLinkAddress("lo", "127.11.0.1/32") - }, - ), - ) + suite.Assert().EventuallyWithT(func(collect *assert.CollectT) { + assertLinkAddress(assert.New(collect), "lo", "127.11.0.1/32") + }, 3*time.Second, 10*time.Millisecond) // teardown the address - for { - ready, err := suite.state.Teardown(suite.ctx, loopback.Metadata()) - suite.Require().NoError(err) + _, err := suite.State().Teardown(suite.Ctx(), loopback.Metadata()) + suite.Require().NoError(err) - if ready { - break - } - - time.Sleep(100 * time.Millisecond) - } + _, err = suite.State().WatchFor(suite.Ctx(), loopback.Metadata(), state.WithFinalizerEmpty()) + suite.Require().NoError(err) // torn down address should be removed immediately - suite.Assert().NoError(suite.assertNoLinkAddress("lo", "127.11.0.1/32")) + suite.Assert().EventuallyWithT(func(collect *assert.CollectT) { + assertNoLinkAddress(assert.New(collect), "lo", "127.11.0.1/32") + }, 3*time.Second, 10*time.Millisecond) - suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata())) + suite.Destroy(loopback) } func (suite *AddressSpecSuite) TestDummy() { @@ -190,7 +143,7 @@ func (suite *AddressSpecSuite) TestDummy() { // it's fine to create the address before the interface is actually created for _, res := range []resource.Resource{dummy} { - suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) + suite.Create(res) } // create dummy interface @@ -214,28 +167,21 @@ func (suite *AddressSpecSuite) TestDummy() { defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck - suite.Assert().NoError( - retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( - func() error { - return suite.assertLinkAddress(dummyInterface, "10.0.0.1/8") - }, - ), - ) + suite.Assert().EventuallyWithT(func(collect *assert.CollectT) { + assertLinkAddress(assert.New(collect), dummyInterface, "10.0.0.1/8") + }, 3*time.Second, 10*time.Millisecond) // delete dummy interface, address should be unassigned automatically suite.Require().NoError(conn.Link.Delete(uint32(iface.Index))) // teardown the address - for { - ready, err := suite.state.Teardown(suite.ctx, dummy.Metadata()) - suite.Require().NoError(err) + _, err = suite.State().Teardown(suite.Ctx(), dummy.Metadata()) + suite.Require().NoError(err) - if ready { - break - } + _, err = suite.State().WatchFor(suite.Ctx(), dummy.Metadata(), state.WithFinalizerEmpty()) + suite.Require().NoError(err) - time.Sleep(100 * time.Millisecond) - } + suite.Destroy(dummy) } func (suite *AddressSpecSuite) TestDummyAlias() { @@ -261,7 +207,7 @@ func (suite *AddressSpecSuite) TestDummyAlias() { // it's fine to create the address before the interface is actually created for _, res := range []resource.Resource{dummy} { - suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) + suite.Create(res) } // create dummy interface @@ -297,27 +243,24 @@ func (suite *AddressSpecSuite) TestDummyAlias() { defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck - suite.Assert().NoError( - retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( - func() error { - return suite.assertLinkAddress(dummyInterface, "10.0.0.5/8") - }, - ), - ) -} - -func (suite *AddressSpecSuite) TearDownTest() { - suite.T().Log("tear down") - - suite.ctxCancel() - - suite.wg.Wait() + suite.Assert().EventuallyWithT(func(collect *assert.CollectT) { + assertLinkAddress(assert.New(collect), dummyInterface, "10.0.0.5/8") + }, 3*time.Second, 10*time.Millisecond) } func TestAddressSpecSuite(t *testing.T) { + t.Parallel() + if os.Geteuid() != 0 { t.Skip("requires root") } - suite.Run(t, new(AddressSpecSuite)) + suite.Run(t, &AddressSpecSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 10 * time.Second, + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressSpecController{})) + }, + }, + }) } diff --git a/internal/app/machined/pkg/controllers/network/address_status.go b/internal/app/machined/pkg/controllers/network/address_status.go index 812015a0b..8ce671193 100644 --- a/internal/app/machined/pkg/controllers/network/address_status.go +++ b/internal/app/machined/pkg/controllers/network/address_status.go @@ -112,6 +112,7 @@ func (ctrl *AddressStatusController) Run(ctx context.Context, r controller.Runti status.Family = nethelpers.Family(addr.Family) status.Scope = nethelpers.Scope(addr.Scope) status.Flags = nethelpers.AddressFlags(addr.Attributes.Flags) + status.Priority = addr.Attributes.Priority return nil }); err != nil { diff --git a/internal/app/machined/pkg/controllers/network/address_status_test.go b/internal/app/machined/pkg/controllers/network/address_status_test.go index b5a02f721..7c8e7c15a 100644 --- a/internal/app/machined/pkg/controllers/network/address_status_test.go +++ b/internal/app/machined/pkg/controllers/network/address_status_test.go @@ -6,78 +6,34 @@ package network_test import ( - "context" - "sync" "testing" "time" - "github.com/cosi-project/runtime/pkg/controller/runtime" - "github.com/cosi-project/runtime/pkg/state" - "github.com/cosi-project/runtime/pkg/state/impl/inmem" - "github.com/cosi-project/runtime/pkg/state/impl/namespaced" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" - "go.uber.org/zap/zaptest" + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest" netctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network" "github.com/siderolabs/talos/pkg/machinery/resources/network" ) type AddressStatusSuite struct { - suite.Suite - - state state.State - - runtime *runtime.Runtime - wg sync.WaitGroup - - ctx context.Context //nolint:containedctx - ctxCancel context.CancelFunc -} - -func (suite *AddressStatusSuite) SetupTest() { - suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute) - - suite.state = state.WrapCore(namespaced.NewState(inmem.Build)) - - var err error - - suite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T())) - suite.Require().NoError(err) - - suite.Require().NoError(suite.runtime.RegisterController(&netctrl.AddressStatusController{})) - - suite.startRuntime() -} - -func (suite *AddressStatusSuite) startRuntime() { - suite.wg.Add(1) - - go func() { - defer suite.wg.Done() - - suite.Assert().NoError(suite.runtime.Run(suite.ctx)) - }() -} - -func (suite *AddressStatusSuite) assertAddresses(requiredIDs []string, check func(*network.AddressStatus, *assert.Assertions)) { - assertResources(suite.ctx, suite.T(), suite.state, requiredIDs, check) + ctest.DefaultSuite } func (suite *AddressStatusSuite) TestLoopback() { - suite.assertAddresses( - []string{"lo/127.0.0.1/8"}, func(r *network.AddressStatus, asrt *assert.Assertions) {}, - ) -} - -func (suite *AddressStatusSuite) TearDownTest() { - suite.T().Log("tear down") - - suite.ctxCancel() - - suite.wg.Wait() + ctest.AssertResource(suite, "lo/127.0.0.1/8", func(r *network.AddressStatus, asrt *assert.Assertions) {}) } func TestAddressStatusSuite(t *testing.T) { - suite.Run(t, new(AddressStatusSuite)) + t.Parallel() + + suite.Run(t, &AddressStatusSuite{ + DefaultSuite: ctest.DefaultSuite{ + Timeout: 10 * time.Second, + AfterSetup: func(suite *ctest.DefaultSuite) { + suite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressStatusController{})) + }, + }, + }) } diff --git a/internal/app/machined/pkg/controllers/network/nftables_chain_test.go b/internal/app/machined/pkg/controllers/network/nftables_chain_test.go index d96092246..98ce5d188 100644 --- a/internal/app/machined/pkg/controllers/network/nftables_chain_test.go +++ b/internal/app/machined/pkg/controllers/network/nftables_chain_test.go @@ -8,6 +8,7 @@ import ( "net/netip" "os" "os/exec" + "slices" "strings" "testing" "time" @@ -33,23 +34,24 @@ func (s *NfTablesChainSuite) nftOutput() string { return string(out) } -func (s *NfTablesChainSuite) checkNftOutput(expected string) { +func (s *NfTablesChainSuite) checkNftOutput(expected ...string) { s.T().Helper() var prevOutput string s.Eventually(func() bool { output := s.nftOutput() + matches := slices.Contains(expected, strings.TrimSpace(output)) if output != prevOutput { - if strings.TrimSpace(output) != expected { + if !matches { s.T().Logf("nft list table inet talos-test:\n%s", output) } prevOutput = output } - return strings.TrimSpace(output) == expected + return matches }, 5*time.Second, 100*time.Millisecond) } @@ -351,12 +353,19 @@ func (s *NfTablesChainSuite) TestClampMSS() { s.Require().NoError(s.State().Create(s.Ctx(), chain)) + // several versions here for different version of `nft` CLI decoding the rules s.checkNftOutput(`table inet talos-test { chain test1 { type filter hook input priority filter; policy accept; meta nfproto ipv4 tcp flags syn / syn,rst tcp option maxseg size > 1380 tcp option maxseg size set 1380 meta nfproto ipv6 tcp flags syn / syn,rst tcp option maxseg size > 1360 tcp option maxseg size set 1360 } +}`, `table inet talos-test { + chain test1 { + type filter hook input priority filter; policy accept; + meta nfproto ipv4 tcp flags & (syn | rst) == syn tcp option maxseg size > 1380 tcp option maxseg size set 1380 + meta nfproto ipv6 tcp flags & (syn | rst) == syn tcp option maxseg size > 1360 tcp option maxseg size set 1360 + } }`) } diff --git a/internal/app/machined/pkg/controllers/network/operator/dhcp4.go b/internal/app/machined/pkg/controllers/network/operator/dhcp4.go index cfc4e77f5..7aa70959c 100644 --- a/internal/app/machined/pkg/controllers/network/operator/dhcp4.go +++ b/internal/app/machined/pkg/controllers/network/operator/dhcp4.go @@ -311,6 +311,7 @@ func (d *DHCP4) parseNetworkConfigFromAck(ack *dhcpv4.DHCPv4, useHostname bool) Family: nethelpers.FamilyInet4, Scope: nethelpers.ScopeGlobal, Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent), + Priority: d.routeMetric, ConfigLayer: network.ConfigOperator, }, } diff --git a/pkg/machinery/api/resource/definitions/network/network.pb.go b/pkg/machinery/api/resource/definitions/network/network.pb.go index 4d9fb00f1..c0609828c 100644 --- a/pkg/machinery/api/resource/definitions/network/network.pb.go +++ b/pkg/machinery/api/resource/definitions/network/network.pb.go @@ -36,6 +36,7 @@ type AddressSpecSpec struct { Flags uint32 `protobuf:"varint,5,opt,name=flags,proto3" json:"flags,omitempty"` AnnounceWithArp bool `protobuf:"varint,6,opt,name=announce_with_arp,json=announceWithArp,proto3" json:"announce_with_arp,omitempty"` ConfigLayer enums.NetworkConfigLayer `protobuf:"varint,7,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer" json:"config_layer,omitempty"` + Priority uint32 `protobuf:"varint,8,opt,name=priority,proto3" json:"priority,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -119,6 +120,13 @@ func (x *AddressSpecSpec) GetConfigLayer() enums.NetworkConfigLayer { return enums.NetworkConfigLayer(0) } +func (x *AddressSpecSpec) GetPriority() uint32 { + if x != nil { + return x.Priority + } + return 0 +} + // AddressStatusSpec describes status of rendered secrets. type AddressStatusSpec struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -132,6 +140,7 @@ type AddressStatusSpec struct { Family enums.NethelpersFamily `protobuf:"varint,8,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily" json:"family,omitempty"` Scope enums.NethelpersScope `protobuf:"varint,9,opt,name=scope,proto3,enum=talos.resource.definitions.enums.NethelpersScope" json:"scope,omitempty"` Flags uint32 `protobuf:"varint,10,opt,name=flags,proto3" json:"flags,omitempty"` + Priority uint32 `protobuf:"varint,11,opt,name=priority,proto3" json:"priority,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -236,6 +245,13 @@ func (x *AddressStatusSpec) GetFlags() uint32 { return 0 } +func (x *AddressStatusSpec) GetPriority() uint32 { + if x != nil { + return x.Priority + } + return 0 +} + // BondMasterSpec describes bond settings if Kind == "bond". type BondMasterSpec struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -4330,7 +4346,7 @@ var File_resource_definitions_network_network_proto protoreflect.FileDescriptor const file_resource_definitions_network_network_proto_rawDesc = "" + "\n" + - "*resource/definitions/network/network.proto\x12\"talos.resource.definitions.network\x1a\x13common/common.proto\x1a\x1egoogle/protobuf/duration.proto\x1a&resource/definitions/enums/enums.proto\"\x8d\x03\n" + + "*resource/definitions/network/network.proto\x12\"talos.resource.definitions.network\x1a\x13common/common.proto\x1a\x1egoogle/protobuf/duration.proto\x1a&resource/definitions/enums/enums.proto\"\xa9\x03\n" + "\x0fAddressSpecSpec\x12-\n" + "\aaddress\x18\x01 \x01(\v2\x13.common.NetIPPrefixR\aaddress\x12\x1b\n" + "\tlink_name\x18\x02 \x01(\tR\blinkName\x12J\n" + @@ -4338,7 +4354,8 @@ const file_resource_definitions_network_network_proto_rawDesc = "" + "\x05scope\x18\x04 \x01(\x0e21.talos.resource.definitions.enums.NethelpersScopeR\x05scope\x12\x14\n" + "\x05flags\x18\x05 \x01(\rR\x05flags\x12*\n" + "\x11announce_with_arp\x18\x06 \x01(\bR\x0fannounceWithArp\x12W\n" + - "\fconfig_layer\x18\a \x01(\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\vconfigLayer\"\xd1\x03\n" + + "\fconfig_layer\x18\a \x01(\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\vconfigLayer\x12\x1a\n" + + "\bpriority\x18\b \x01(\rR\bpriority\"\xed\x03\n" + "\x11AddressStatusSpec\x12-\n" + "\aaddress\x18\x01 \x01(\v2\x13.common.NetIPPrefixR\aaddress\x12#\n" + "\x05local\x18\x02 \x01(\v2\r.common.NetIPR\x05local\x12+\n" + @@ -4351,7 +4368,8 @@ const file_resource_definitions_network_network_proto_rawDesc = "" + "\x06family\x18\b \x01(\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\x06family\x12G\n" + "\x05scope\x18\t \x01(\x0e21.talos.resource.definitions.enums.NethelpersScopeR\x05scope\x12\x14\n" + "\x05flags\x18\n" + - " \x01(\rR\x05flags\"\xa4\n" + + " \x01(\rR\x05flags\x12\x1a\n" + + "\bpriority\x18\v \x01(\rR\bpriority\"\xa4\n" + "\n" + "\x0eBondMasterSpec\x12H\n" + "\x04mode\x18\x01 \x01(\x0e24.talos.resource.definitions.enums.NethelpersBondModeR\x04mode\x12_\n" + diff --git a/pkg/machinery/api/resource/definitions/network/network_vtproto.pb.go b/pkg/machinery/api/resource/definitions/network/network_vtproto.pb.go index 6ac472946..561b85dd6 100644 --- a/pkg/machinery/api/resource/definitions/network/network_vtproto.pb.go +++ b/pkg/machinery/api/resource/definitions/network/network_vtproto.pb.go @@ -56,6 +56,11 @@ func (m *AddressSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.Priority != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority)) + i-- + dAtA[i] = 0x40 + } if m.ConfigLayer != 0 { i = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer)) i-- @@ -148,6 +153,11 @@ func (m *AddressStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.Priority != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority)) + i-- + dAtA[i] = 0x58 + } if m.Flags != 0 { i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Flags)) i-- @@ -4273,6 +4283,9 @@ func (m *AddressSpecSpec) SizeVT() (n int) { if m.ConfigLayer != 0 { n += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer)) } + if m.Priority != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Priority)) + } n += len(m.unknownFields) return n } @@ -4349,6 +4362,9 @@ func (m *AddressStatusSpec) SizeVT() (n int) { if m.Flags != 0 { n += 1 + protohelpers.SizeOfVarint(uint64(m.Flags)) } + if m.Priority != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Priority)) + } n += len(m.unknownFields) return n } @@ -6139,6 +6155,25 @@ func (m *AddressSpecSpec) UnmarshalVT(dAtA []byte) error { break } } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Priority", wireType) + } + m.Priority = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Priority |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) @@ -6518,6 +6553,25 @@ func (m *AddressStatusSpec) UnmarshalVT(dAtA []byte) error { break } } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Priority", wireType) + } + m.Priority = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Priority |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index 4e70dbe3a..d9d2dbc4c 100644 --- a/pkg/machinery/go.mod +++ b/pkg/machinery/go.mod @@ -23,7 +23,7 @@ require ( github.com/google/cel-go v0.24.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hexops/gotextdiff v1.0.3 - github.com/jsimonetti/rtnetlink/v2 v2.0.3-0.20241216183107-2d6e9f8ad3f2 + github.com/jsimonetti/rtnetlink/v2 v2.0.3 github.com/mdlayher/ethtool v0.4.0 github.com/opencontainers/runtime-spec v1.2.1 github.com/planetscale/vtprotobuf v0.6.1-0.20241121165744-79df5c4772f2 diff --git a/pkg/machinery/go.sum b/pkg/machinery/go.sum index 0290c2245..dfeb3319d 100644 --- a/pkg/machinery/go.sum +++ b/pkg/machinery/go.sum @@ -16,8 +16,8 @@ github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= -github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= +github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg= +github.com/cilium/ebpf v0.17.3/go.mod h1:G5EDHij8yiLzaqn0WjyfJHvRa+3aDlReIaLVRMvOyJk= github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/containerd/go-cni v1.1.12 h1:wm/5VD/i255hjM4uIZjBRiEQ7y98W9ACy/mHeLi4+94= @@ -69,8 +69,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/jsimonetti/rtnetlink/v2 v2.0.3-0.20241216183107-2d6e9f8ad3f2 h1:4pspWog/mjnfv+B3rjEUfCoFL80T7J8ojK9ay8ApPCM= -github.com/jsimonetti/rtnetlink/v2 v2.0.3-0.20241216183107-2d6e9f8ad3f2/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= +github.com/jsimonetti/rtnetlink/v2 v2.0.3 h1:Jcp7GTnTPepoUAJ9+LhTa7ZiebvNS56T1GtlEUaPNFE= +github.com/jsimonetti/rtnetlink/v2 v2.0.3/go.mod h1:atIkksp/9fqtf6rpAw45JnttnP2gtuH9X88WPfWfS9A= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= diff --git a/pkg/machinery/resources/network/address_spec.go b/pkg/machinery/resources/network/address_spec.go index 44d1d7864..73eb44fdb 100644 --- a/pkg/machinery/resources/network/address_spec.go +++ b/pkg/machinery/resources/network/address_spec.go @@ -34,6 +34,7 @@ type AddressSpecSpec struct { Scope nethelpers.Scope `yaml:"scope" protobuf:"4"` Flags nethelpers.AddressFlags `yaml:"flags" protobuf:"5"` AnnounceWithARP bool `yaml:"announceWithARP,omitempty" protobuf:"6"` + Priority uint32 `yaml:"priority,omitempty" protobuf:"8"` ConfigLayer ConfigLayer `yaml:"layer" protobuf:"7"` } diff --git a/pkg/machinery/resources/network/address_status.go b/pkg/machinery/resources/network/address_status.go index 1bf8dc0bb..aaf50f084 100644 --- a/pkg/machinery/resources/network/address_status.go +++ b/pkg/machinery/resources/network/address_status.go @@ -36,6 +36,7 @@ type AddressStatusSpec struct { Family nethelpers.Family `yaml:"family" protobuf:"8"` Scope nethelpers.Scope `yaml:"scope" protobuf:"9"` Flags nethelpers.AddressFlags `yaml:"flags" protobuf:"10"` + Priority uint32 `yaml:"priority" protobuf:"11"` } // NewAddressStatus initializes a AddressStatus resource. diff --git a/website/content/v1.10/reference/api.md b/website/content/v1.10/reference/api.md index fad3e4091..332a30064 100644 --- a/website/content/v1.10/reference/api.md +++ b/website/content/v1.10/reference/api.md @@ -3702,6 +3702,7 @@ AddressSpecSpec describes status of rendered secrets. | flags | [uint32](#uint32) | | | | announce_with_arp | [bool](#bool) | | | | config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) | | | +| priority | [uint32](#uint32) | | | @@ -3726,6 +3727,7 @@ AddressStatusSpec describes status of rendered secrets. | family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) | | | | scope | [talos.resource.definitions.enums.NethelpersScope](#talos.resource.definitions.enums.NethelpersScope) | | | | flags | [uint32](#uint32) | | | +| priority | [uint32](#uint32) | | |