mirror of
https://github.com/siderolabs/talos.git
synced 2026-05-05 12:26:21 +02:00
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:
parent
8cd3c8dc77
commit
f0ea478cb8
@ -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
4
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
|
||||
|
||||
8
go.sum
8
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=
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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{}))
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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{}))
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}`)
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
@ -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" +
|
||||
|
||||
@ -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:])
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=
|
||||
|
||||
@ -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"`
|
||||
}
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user