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 <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2025-04-15 16:46:30 +04:00
parent 8cd3c8dc77
commit f0ea478cb8
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
16 changed files with 172 additions and 181 deletions

View File

@ -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".

4
go.mod
View File

@ -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

8
go.sum
View File

@ -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=

View File

@ -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

View File

@ -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{}))
},
},
})
}

View File

@ -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 {

View File

@ -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{}))
},
},
})
}

View File

@ -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
}
}`)
}

View File

@ -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,
},
}

View File

@ -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" +

View File

@ -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:])

View File

@ -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

View File

@ -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=

View File

@ -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"`
}

View File

@ -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.

View File

@ -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) | | |