Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions api/resource/definitions/enums/enums.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ enum NethelpersAddressSortAlgorithm {
ADDRESS_SORT_ALGORITHM_V2 = 1;
}

// NethelpersADLACPActive is ADLACPActive.
enum NethelpersADLACPActive {
ADLACP_ACTIVE_OFF = 0;
ADLACP_ACTIVE_ON = 1;
}

// NethelpersADSelect is ADSelect.
enum NethelpersADSelect {
AD_SELECT_STABLE = 0;
Expand All @@ -89,6 +95,9 @@ enum NethelpersARPValidate {
ARP_VALIDATE_ACTIVE = 1;
ARP_VALIDATE_BACKUP = 2;
ARP_VALIDATE_ALL = 3;
ARP_VALIDATE_FILTER = 4;
ARP_VALIDATE_FILTER_ACTIVE = 5;
ARP_VALIDATE_FILTER_BACKUP = 6;
}

// NethelpersAutoHostnameKind is a kind of automatically generated hostname.
Expand Down
4 changes: 4 additions & 0 deletions api/resource/definitions/network/network.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ message BondMasterSpec {
uint32 ad_actor_sys_prio = 22;
uint32 ad_user_port_key = 23;
uint32 peer_notify_delay = 24;
repeated common.NetIP arpip_targets = 25;
repeated common.NetIP nsip6_targets = 26;
talos.resource.definitions.enums.NethelpersADLACPActive adlacp_active = 27;
uint32 missed_max = 28;
}

// BondSlave contains a bond's master name and slave index.
Expand Down
87 changes: 83 additions & 4 deletions internal/app/machined/pkg/adapters/network/bond_master_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
package network

import (
"fmt"
"net/netip"

"github.com/mdlayher/netlink"
"github.com/siderolabs/go-pointer"
"golang.org/x/sys/unix"

"github.com/siderolabs/talos/pkg/machinery/nethelpers"
Expand All @@ -26,6 +30,8 @@ type bondMaster struct {
}

// FillDefaults fills zero values with proper default values.
//
//nolint:gocyclo
func (a bondMaster) FillDefaults() {
bond := a.BondMasterSpec

Expand All @@ -49,14 +55,22 @@ func (a bondMaster) FillDefaults() {
bond.TLBDynamicLB = 1
}

if bond.Mode == nethelpers.BondMode8023AD {
if bond.Mode == nethelpers.BondMode8023AD && bond.ADActorSysPrio == 0 {
bond.ADActorSysPrio = 65535
}

if bond.MissedMax == 0 {
bond.MissedMax = 2
}

if bond.Mode != nethelpers.BondMode8023AD {
bond.ADLACPActive = nethelpers.ADLACPActiveOn
}
}

// Encode the BondMasterSpec into netlink attributes.
//
//nolint:gocyclo
//nolint:gocyclo,cyclop
func (a bondMaster) Encode() ([]byte, error) {
bond := a.BondMasterSpec

Expand All @@ -67,6 +81,7 @@ func (a bondMaster) Encode() ([]byte, error) {

if bond.Mode == nethelpers.BondMode8023AD {
encoder.Uint8(unix.IFLA_BOND_AD_LACP_RATE, uint8(bond.LACPRate))
encoder.Uint8(unix.IFLA_BOND_AD_LACP_ACTIVE, uint8(bond.ADLACPActive))
}

if bond.Mode != nethelpers.BondMode8023AD && bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {
Expand All @@ -76,7 +91,9 @@ func (a bondMaster) Encode() ([]byte, error) {
encoder.Uint32(unix.IFLA_BOND_ARP_ALL_TARGETS, uint32(bond.ARPAllTargets))

if bond.Mode == nethelpers.BondModeActiveBackup || bond.Mode == nethelpers.BondModeALB || bond.Mode == nethelpers.BondModeTLB {
encoder.Uint32(unix.IFLA_BOND_PRIMARY, bond.PrimaryIndex)
if bond.PrimaryIndex != nil {
encoder.Uint32(unix.IFLA_BOND_PRIMARY, *bond.PrimaryIndex)
}
}

encoder.Uint8(unix.IFLA_BOND_PRIMARY_RESELECT, uint8(bond.PrimaryReselect))
Expand All @@ -91,6 +108,32 @@ func (a bondMaster) Encode() ([]byte, error) {

if bond.Mode != nethelpers.BondMode8023AD && bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {
encoder.Uint32(unix.IFLA_BOND_ARP_INTERVAL, bond.ARPInterval)

encoder.Nested(unix.IFLA_BOND_ARP_IP_TARGET, func(nae *netlink.AttributeEncoder) error {
for i, addr := range bond.ARPIPTargets {
if !addr.Is4() {
return fmt.Errorf("%s is not IPV4 address", addr)
}

ip := addr.As4()
nae.Bytes(uint16(i), ip[:])
}

return nil
})

encoder.Nested(unix.IFLA_BOND_NS_IP6_TARGET, func(nae *netlink.AttributeEncoder) error {
for i, addr := range bond.NSIP6Targets {
if !addr.Is6() {
return fmt.Errorf("%s is not IPV6 address", addr)
}

ip := addr.As16()
nae.Bytes(uint16(i), ip[:])
}

return nil
})
}

encoder.Uint32(unix.IFLA_BOND_RESEND_IGMP, bond.ResendIGMP)
Expand Down Expand Up @@ -126,6 +169,10 @@ func (a bondMaster) Encode() ([]byte, error) {
encoder.Uint32(unix.IFLA_BOND_PEER_NOTIF_DELAY, bond.PeerNotifyDelay)
}

if bond.MissedMax != 0 {
encoder.Uint8(unix.IFLA_BOND_MISSED_MAX, bond.MissedMax)
}

return encoder.Encode()
}

Expand Down Expand Up @@ -153,7 +200,7 @@ func (a bondMaster) Decode(data []byte) error {
case unix.IFLA_BOND_ARP_ALL_TARGETS:
bond.ARPAllTargets = nethelpers.ARPAllTargets(decoder.Uint32())
case unix.IFLA_BOND_PRIMARY:
bond.PrimaryIndex = decoder.Uint32()
bond.PrimaryIndex = pointer.To(decoder.Uint32())
case unix.IFLA_BOND_PRIMARY_RESELECT:
bond.PrimaryReselect = nethelpers.PrimaryReselect(decoder.Uint8())
case unix.IFLA_BOND_FAIL_OVER_MAC:
Expand All @@ -168,6 +215,34 @@ func (a bondMaster) Decode(data []byte) error {
bond.DownDelay = decoder.Uint32()
case unix.IFLA_BOND_ARP_INTERVAL:
bond.ARPInterval = decoder.Uint32()
case unix.IFLA_BOND_ARP_IP_TARGET:
decoder.Nested(func(nad *netlink.AttributeDecoder) error {
for nad.Next() {
addr, ok := netip.AddrFromSlice(nad.Bytes())

if ok {
bond.ARPIPTargets = append(bond.ARPIPTargets, addr)
} else {
return fmt.Errorf("invalid ARP IP target")
}
}

return nil
})
case unix.IFLA_BOND_NS_IP6_TARGET:
decoder.Nested(func(nad *netlink.AttributeDecoder) error {
for nad.Next() {
addr, ok := netip.AddrFromSlice(nad.Bytes())

if ok {
bond.NSIP6Targets = append(bond.NSIP6Targets, addr)
} else {
return fmt.Errorf("invalid NS IP6 target")
}
}

return nil
})
case unix.IFLA_BOND_RESEND_IGMP:
bond.ResendIGMP = decoder.Uint32()
case unix.IFLA_BOND_MIN_LINKS:
Expand All @@ -190,6 +265,10 @@ func (a bondMaster) Decode(data []byte) error {
bond.ADUserPortKey = decoder.Uint16()
case unix.IFLA_BOND_PEER_NOTIF_DELAY:
bond.PeerNotifyDelay = decoder.Uint32()
case unix.IFLA_BOND_AD_LACP_ACTIVE:
bond.ADLACPActive = nethelpers.ADLACPActive(decoder.Uint8())
case unix.IFLA_BOND_MISSED_MAX:
bond.MissedMax = decoder.Uint8()
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/app/machined/pkg/controllers/network/cmdline.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func ParseCmdlineNetwork(cmdline *procfs.Cmdline, linkNameResolver *network.Link
bondLinkSpec.MTU = uint32(mtu)
}

if err := SetBondMaster(&bondLinkSpec, &bondOptions); err != nil {
if err := SetBondMasterLegacy(&bondLinkSpec, &bondOptions); err != nil {
return settings, fmt.Errorf("error setting bond master: %w", err)
}

Expand Down
6 changes: 6 additions & 0 deletions internal/app/machined/pkg/controllers/network/cmdline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"slices"
"testing"

"github.com/siderolabs/go-pointer"
"github.com/siderolabs/go-procfs/procfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -57,6 +58,9 @@ func TestCmdlineParse(t *testing.T) {
NumPeerNotif: 1,
TLBDynamicLB: 1,
UseCarrier: true,
PrimaryIndex: pointer.To[uint32](0),
ADLACPActive: nethelpers.ADLACPActiveOn,
MissedMax: 2,
},
},
{
Expand Down Expand Up @@ -404,6 +408,8 @@ func TestCmdlineParse(t *testing.T) {
NumPeerNotif: 1,
TLBDynamicLB: 1,
UseCarrier: true,
PrimaryIndex: pointer.To[uint32](0),
MissedMax: 2,
},
},
{
Expand Down
22 changes: 20 additions & 2 deletions internal/app/machined/pkg/controllers/network/link_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/siderolabs/gen/maps"
"github.com/siderolabs/gen/optional"
"github.com/siderolabs/gen/pair/ordered"
"github.com/siderolabs/gen/xslices"
"github.com/siderolabs/go-procfs/procfs"
"go.uber.org/zap"

Expand Down Expand Up @@ -349,7 +350,7 @@ func (ctrl *LinkConfigController) processDevicesConfiguration(
}

if device.Bond() != nil {
if err := SetBondMaster(linkMap[deviceInterface], device.Bond()); err != nil {
if err := SetBondMasterLegacy(linkMap[deviceInterface], device.Bond()); err != nil {
logger.Error("error parsing bond config", zap.Error(err))
}
}
Expand Down Expand Up @@ -444,7 +445,24 @@ func (ctrl *LinkConfigController) processLinkConfigs(logger *zap.Logger, linkMap
case talosconfig.NetworkDummyLinkConfig:
dummyLink(linkMap[linkName])
case talosconfig.NetworkVLANConfig:
vlanLink(linkMap[linkName], linkName, specificLinkConfig.ParentLink(), networkVLANConfigToVlaner{specificLinkConfig})
parentLink := linkNameResolver.Resolve(specificLinkConfig.ParentLink())
vlanLink(linkMap[linkName], linkName, parentLink, networkVLANConfigToVlaner{specificLinkConfig})
case talosconfig.NetworkBondConfig:
SendBondMaster(linkMap[linkName], specificLinkConfig)

bondedLinks := xslices.Map(specificLinkConfig.Links(), linkNameResolver.Resolve)

for idx, slaveLinkName := range bondedLinks {
if _, exists := linkMap[slaveLinkName]; !exists {
linkMap[slaveLinkName] = &network.LinkSpecSpec{
Name: slaveLinkName,
Up: true,
ConfigLayer: network.ConfigMachineConfiguration,
}
}

SetBondSlave(linkMap[slaveLinkName], ordered.MakePair(linkName, idx))
}
default:
logger.Error("unknown link config type", zap.String("linkName", linkName), zap.String("type", fmt.Sprintf("%T", specificLinkConfig)))
}
Expand Down
26 changes: 24 additions & 2 deletions internal/app/machined/pkg/controllers/network/link_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,15 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
vl1.LinkMTU = 200
vl1.LinkUp = pointer.To(true)

ctr, err := container.New(dc1, lc1, vl1)
dc2 := networkcfg.NewDummyLinkConfigV1Alpha1("dummy2")
dc3 := networkcfg.NewDummyLinkConfigV1Alpha1("dummy3")

bc1 := networkcfg.NewBondConfigV1Alpha1("bond357")
bc1.BondMode = pointer.To(nethelpers.BondModeActiveBackup)
bc1.BondLinks = []string{"dummy2", "dummy3"}
bc1.BondUpDelay = pointer.To(uint32(200))

ctr, err := container.New(dc1, lc1, vl1, dc2, dc3, bc1)
suite.Require().NoError(err)

cfg := config.NewMachineConfig(ctr)
Expand All @@ -501,7 +509,10 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
[]string{
"configuration/eth0",
"configuration/dummy1",
"configuration/dummy2",
"configuration/dummy3",
"configuration/dummy1.100",
"configuration/bond357",
}, func(r *network.LinkSpec, asrt *assert.Assertions) {
asrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)

Expand All @@ -510,11 +521,15 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
asrt.True(r.TypedSpec().Up)
asrt.False(r.TypedSpec().Logical)
asrt.EqualValues(9001, r.TypedSpec().MTU)
case "dummy1":
case "dummy1", "dummy2", "dummy3":
asrt.True(r.TypedSpec().Up)
asrt.True(r.TypedSpec().Logical)
asrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)
asrt.Equal("dummy", r.TypedSpec().Kind)

if r.TypedSpec().Name == "dummy2" || r.TypedSpec().Name == "dummy3" {
asrt.Equal("bond357", r.TypedSpec().BondSlave.MasterName)
}
case "dummy1.100":
asrt.True(r.TypedSpec().Up)
asrt.True(r.TypedSpec().Logical)
Expand All @@ -524,6 +539,13 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
asrt.Equal(nethelpers.VLANProtocol8021AD, r.TypedSpec().VLAN.Protocol)
asrt.EqualValues(100, r.TypedSpec().VLAN.VID)
asrt.EqualValues(200, r.TypedSpec().MTU)
case "bond357":
asrt.True(r.TypedSpec().Up)
asrt.True(r.TypedSpec().Logical)
asrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)
asrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)
asrt.Equal(nethelpers.BondModeActiveBackup, r.TypedSpec().BondMaster.Mode)
asrt.EqualValues(200, r.TypedSpec().BondMaster.UpDelay)
}
},
)
Expand Down
7 changes: 6 additions & 1 deletion internal/app/machined/pkg/controllers/network/link_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,12 @@ func (ctrl *LinkSpecController) syncLink(ctx context.Context, r controller.Runti
return fmt.Errorf("error parsing bond attributes for %q: %w", link.TypedSpec().Name, err)
}

if existingBond != link.TypedSpec().BondMaster {
// primaryIndex might be reported from the kernel, but if it's nil in the spec, we should treat it as equal
if existingBond.PrimaryIndex != nil && link.TypedSpec().BondMaster.PrimaryIndex == nil {
existingBond.PrimaryIndex = nil
}

if !existingBond.Equal(&link.TypedSpec().BondMaster) {
logger.Debug("updating bond settings",
zap.String("old", fmt.Sprintf("%+v", existingBond)),
zap.String("new", fmt.Sprintf("%+v", link.TypedSpec().BondMaster)),
Expand Down
Loading