Skip to content

Commit f4ad307

Browse files
committed
feat: implement bond multi-doc configuration
Also expand internal bond configuration to cover missing fields. They are not going to be exposed in legacy configuration. Fixes #10960 Signed-off-by: Andrey Smirnov <[email protected]>
1 parent 75fe475 commit f4ad307

File tree

43 files changed

+3530
-373
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3530
-373
lines changed

api/resource/definitions/enums/enums.proto

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ enum NethelpersAddressSortAlgorithm {
7070
ADDRESS_SORT_ALGORITHM_V2 = 1;
7171
}
7272

73+
// NethelpersADLACPActive is ADLACPActive.
74+
enum NethelpersADLACPActive {
75+
ADLACP_ACTIVE_OFF = 0;
76+
ADLACP_ACTIVE_ON = 1;
77+
}
78+
7379
// NethelpersADSelect is ADSelect.
7480
enum NethelpersADSelect {
7581
AD_SELECT_STABLE = 0;
@@ -89,6 +95,9 @@ enum NethelpersARPValidate {
8995
ARP_VALIDATE_ACTIVE = 1;
9096
ARP_VALIDATE_BACKUP = 2;
9197
ARP_VALIDATE_ALL = 3;
98+
ARP_VALIDATE_FILTER = 4;
99+
ARP_VALIDATE_FILTER_ACTIVE = 5;
100+
ARP_VALIDATE_FILTER_BACKUP = 6;
92101
}
93102

94103
// NethelpersAutoHostnameKind is a kind of automatically generated hostname.

api/resource/definitions/network/network.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ message BondMasterSpec {
6363
uint32 ad_actor_sys_prio = 22;
6464
uint32 ad_user_port_key = 23;
6565
uint32 peer_notify_delay = 24;
66+
repeated common.NetIP arpip_targets = 25;
67+
repeated common.NetIP nsip6_targets = 26;
68+
talos.resource.definitions.enums.NethelpersADLACPActive adlacp_active = 27;
69+
uint32 missed_max = 28;
6670
}
6771

6872
// BondSlave contains a bond's master name and slave index.

internal/app/machined/pkg/adapters/network/bond_master_spec.go

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
package network
66

77
import (
8+
"fmt"
9+
"net/netip"
10+
811
"github.com/mdlayher/netlink"
12+
"github.com/siderolabs/go-pointer"
913
"golang.org/x/sys/unix"
1014

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

2832
// FillDefaults fills zero values with proper default values.
33+
//
34+
//nolint:gocyclo
2935
func (a bondMaster) FillDefaults() {
3036
bond := a.BondMasterSpec
3137

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

52-
if bond.Mode == nethelpers.BondMode8023AD {
58+
if bond.Mode == nethelpers.BondMode8023AD && bond.ADActorSysPrio == 0 {
5359
bond.ADActorSysPrio = 65535
5460
}
61+
62+
if bond.MissedMax == 0 {
63+
bond.MissedMax = 2
64+
}
65+
66+
if bond.Mode != nethelpers.BondMode8023AD {
67+
bond.ADLACPActive = nethelpers.ADLACPActiveOn
68+
}
5569
}
5670

5771
// Encode the BondMasterSpec into netlink attributes.
5872
//
59-
//nolint:gocyclo
73+
//nolint:gocyclo,cyclop
6074
func (a bondMaster) Encode() ([]byte, error) {
6175
bond := a.BondMasterSpec
6276

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

6882
if bond.Mode == nethelpers.BondMode8023AD {
6983
encoder.Uint8(unix.IFLA_BOND_AD_LACP_RATE, uint8(bond.LACPRate))
84+
encoder.Uint8(unix.IFLA_BOND_AD_LACP_ACTIVE, uint8(bond.ADLACPActive))
7085
}
7186

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

7893
if bond.Mode == nethelpers.BondModeActiveBackup || bond.Mode == nethelpers.BondModeALB || bond.Mode == nethelpers.BondModeTLB {
79-
encoder.Uint32(unix.IFLA_BOND_PRIMARY, bond.PrimaryIndex)
94+
if bond.PrimaryIndex != nil {
95+
encoder.Uint32(unix.IFLA_BOND_PRIMARY, *bond.PrimaryIndex)
96+
}
8097
}
8198

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

92109
if bond.Mode != nethelpers.BondMode8023AD && bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {
93110
encoder.Uint32(unix.IFLA_BOND_ARP_INTERVAL, bond.ARPInterval)
111+
112+
encoder.Nested(unix.IFLA_BOND_ARP_IP_TARGET, func(nae *netlink.AttributeEncoder) error {
113+
for i, addr := range bond.ARPIPTargets {
114+
if !addr.Is4() {
115+
return fmt.Errorf("%s is not IPV4 address", addr)
116+
}
117+
118+
ip := addr.As4()
119+
nae.Bytes(uint16(i), ip[:])
120+
}
121+
122+
return nil
123+
})
124+
125+
encoder.Nested(unix.IFLA_BOND_NS_IP6_TARGET, func(nae *netlink.AttributeEncoder) error {
126+
for i, addr := range bond.NSIP6Targets {
127+
if !addr.Is6() {
128+
return fmt.Errorf("%s is not IPV6 address", addr)
129+
}
130+
131+
ip := addr.As16()
132+
nae.Bytes(uint16(i), ip[:])
133+
}
134+
135+
return nil
136+
})
94137
}
95138

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

172+
if bond.MissedMax != 0 {
173+
encoder.Uint8(unix.IFLA_BOND_MISSED_MAX, bond.MissedMax)
174+
}
175+
129176
return encoder.Encode()
130177
}
131178

@@ -153,7 +200,7 @@ func (a bondMaster) Decode(data []byte) error {
153200
case unix.IFLA_BOND_ARP_ALL_TARGETS:
154201
bond.ARPAllTargets = nethelpers.ARPAllTargets(decoder.Uint32())
155202
case unix.IFLA_BOND_PRIMARY:
156-
bond.PrimaryIndex = decoder.Uint32()
203+
bond.PrimaryIndex = pointer.To(decoder.Uint32())
157204
case unix.IFLA_BOND_PRIMARY_RESELECT:
158205
bond.PrimaryReselect = nethelpers.PrimaryReselect(decoder.Uint8())
159206
case unix.IFLA_BOND_FAIL_OVER_MAC:
@@ -168,6 +215,34 @@ func (a bondMaster) Decode(data []byte) error {
168215
bond.DownDelay = decoder.Uint32()
169216
case unix.IFLA_BOND_ARP_INTERVAL:
170217
bond.ARPInterval = decoder.Uint32()
218+
case unix.IFLA_BOND_ARP_IP_TARGET:
219+
decoder.Nested(func(nad *netlink.AttributeDecoder) error {
220+
for nad.Next() {
221+
addr, ok := netip.AddrFromSlice(nad.Bytes())
222+
223+
if ok {
224+
bond.ARPIPTargets = append(bond.ARPIPTargets, addr)
225+
} else {
226+
return fmt.Errorf("invalid ARP IP target")
227+
}
228+
}
229+
230+
return nil
231+
})
232+
case unix.IFLA_BOND_NS_IP6_TARGET:
233+
decoder.Nested(func(nad *netlink.AttributeDecoder) error {
234+
for nad.Next() {
235+
addr, ok := netip.AddrFromSlice(nad.Bytes())
236+
237+
if ok {
238+
bond.NSIP6Targets = append(bond.NSIP6Targets, addr)
239+
} else {
240+
return fmt.Errorf("invalid NS IP6 target")
241+
}
242+
}
243+
244+
return nil
245+
})
171246
case unix.IFLA_BOND_RESEND_IGMP:
172247
bond.ResendIGMP = decoder.Uint32()
173248
case unix.IFLA_BOND_MIN_LINKS:
@@ -190,6 +265,10 @@ func (a bondMaster) Decode(data []byte) error {
190265
bond.ADUserPortKey = decoder.Uint16()
191266
case unix.IFLA_BOND_PEER_NOTIF_DELAY:
192267
bond.PeerNotifyDelay = decoder.Uint32()
268+
case unix.IFLA_BOND_AD_LACP_ACTIVE:
269+
bond.ADLACPActive = nethelpers.ADLACPActive(decoder.Uint8())
270+
case unix.IFLA_BOND_MISSED_MAX:
271+
bond.MissedMax = decoder.Uint8()
193272
}
194273
}
195274

internal/app/machined/pkg/controllers/network/cmdline.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ func ParseCmdlineNetwork(cmdline *procfs.Cmdline, linkNameResolver *network.Link
284284
bondLinkSpec.MTU = uint32(mtu)
285285
}
286286

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

internal/app/machined/pkg/controllers/network/cmdline_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"slices"
1414
"testing"
1515

16+
"github.com/siderolabs/go-pointer"
1617
"github.com/siderolabs/go-procfs/procfs"
1718
"github.com/stretchr/testify/assert"
1819
"github.com/stretchr/testify/require"
@@ -57,6 +58,9 @@ func TestCmdlineParse(t *testing.T) {
5758
NumPeerNotif: 1,
5859
TLBDynamicLB: 1,
5960
UseCarrier: true,
61+
PrimaryIndex: pointer.To[uint32](0),
62+
ADLACPActive: nethelpers.ADLACPActiveOn,
63+
MissedMax: 2,
6064
},
6165
},
6266
{
@@ -404,6 +408,8 @@ func TestCmdlineParse(t *testing.T) {
404408
NumPeerNotif: 1,
405409
TLBDynamicLB: 1,
406410
UseCarrier: true,
411+
PrimaryIndex: pointer.To[uint32](0),
412+
MissedMax: 2,
407413
},
408414
},
409415
{

internal/app/machined/pkg/controllers/network/link_config.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/siderolabs/gen/maps"
1717
"github.com/siderolabs/gen/optional"
1818
"github.com/siderolabs/gen/pair/ordered"
19+
"github.com/siderolabs/gen/xslices"
1920
"github.com/siderolabs/go-procfs/procfs"
2021
"go.uber.org/zap"
2122

@@ -349,7 +350,7 @@ func (ctrl *LinkConfigController) processDevicesConfiguration(
349350
}
350351

351352
if device.Bond() != nil {
352-
if err := SetBondMaster(linkMap[deviceInterface], device.Bond()); err != nil {
353+
if err := SetBondMasterLegacy(linkMap[deviceInterface], device.Bond()); err != nil {
353354
logger.Error("error parsing bond config", zap.Error(err))
354355
}
355356
}
@@ -444,7 +445,24 @@ func (ctrl *LinkConfigController) processLinkConfigs(logger *zap.Logger, linkMap
444445
case talosconfig.NetworkDummyLinkConfig:
445446
dummyLink(linkMap[linkName])
446447
case talosconfig.NetworkVLANConfig:
447-
vlanLink(linkMap[linkName], linkName, specificLinkConfig.ParentLink(), networkVLANConfigToVlaner{specificLinkConfig})
448+
parentLink := linkNameResolver.Resolve(specificLinkConfig.ParentLink())
449+
vlanLink(linkMap[linkName], linkName, parentLink, networkVLANConfigToVlaner{specificLinkConfig})
450+
case talosconfig.NetworkBondConfig:
451+
SendBondMaster(linkMap[linkName], specificLinkConfig)
452+
453+
bondedLinks := xslices.Map(specificLinkConfig.Links(), linkNameResolver.Resolve)
454+
455+
for idx, slaveLinkName := range bondedLinks {
456+
if _, exists := linkMap[slaveLinkName]; !exists {
457+
linkMap[slaveLinkName] = &network.LinkSpecSpec{
458+
Name: slaveLinkName,
459+
Up: true,
460+
ConfigLayer: network.ConfigMachineConfiguration,
461+
}
462+
}
463+
464+
SetBondSlave(linkMap[slaveLinkName], ordered.MakePair(linkName, idx))
465+
}
448466
default:
449467
logger.Error("unknown link config type", zap.String("linkName", linkName), zap.String("type", fmt.Sprintf("%T", specificLinkConfig)))
450468
}

internal/app/machined/pkg/controllers/network/link_config_test.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,15 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
476476
vl1.LinkMTU = 200
477477
vl1.LinkUp = pointer.To(true)
478478

479-
ctr, err := container.New(dc1, lc1, vl1)
479+
dc2 := networkcfg.NewDummyLinkConfigV1Alpha1("dummy2")
480+
dc3 := networkcfg.NewDummyLinkConfigV1Alpha1("dummy3")
481+
482+
bc1 := networkcfg.NewBondConfigV1Alpha1("bond357")
483+
bc1.BondMode = pointer.To(nethelpers.BondModeActiveBackup)
484+
bc1.BondLinks = []string{"dummy2", "dummy3"}
485+
bc1.BondUpDelay = pointer.To(uint32(200))
486+
487+
ctr, err := container.New(dc1, lc1, vl1, dc2, dc3, bc1)
480488
suite.Require().NoError(err)
481489

482490
cfg := config.NewMachineConfig(ctr)
@@ -501,7 +509,10 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
501509
[]string{
502510
"configuration/eth0",
503511
"configuration/dummy1",
512+
"configuration/dummy2",
513+
"configuration/dummy3",
504514
"configuration/dummy1.100",
515+
"configuration/bond357",
505516
}, func(r *network.LinkSpec, asrt *assert.Assertions) {
506517
asrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)
507518

@@ -510,11 +521,15 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
510521
asrt.True(r.TypedSpec().Up)
511522
asrt.False(r.TypedSpec().Logical)
512523
asrt.EqualValues(9001, r.TypedSpec().MTU)
513-
case "dummy1":
524+
case "dummy1", "dummy2", "dummy3":
514525
asrt.True(r.TypedSpec().Up)
515526
asrt.True(r.TypedSpec().Logical)
516527
asrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)
517528
asrt.Equal("dummy", r.TypedSpec().Kind)
529+
530+
if r.TypedSpec().Name == "dummy2" || r.TypedSpec().Name == "dummy3" {
531+
asrt.Equal("bond357", r.TypedSpec().BondSlave.MasterName)
532+
}
518533
case "dummy1.100":
519534
asrt.True(r.TypedSpec().Up)
520535
asrt.True(r.TypedSpec().Logical)
@@ -524,6 +539,13 @@ func (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {
524539
asrt.Equal(nethelpers.VLANProtocol8021AD, r.TypedSpec().VLAN.Protocol)
525540
asrt.EqualValues(100, r.TypedSpec().VLAN.VID)
526541
asrt.EqualValues(200, r.TypedSpec().MTU)
542+
case "bond357":
543+
asrt.True(r.TypedSpec().Up)
544+
asrt.True(r.TypedSpec().Logical)
545+
asrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)
546+
asrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)
547+
asrt.Equal(nethelpers.BondModeActiveBackup, r.TypedSpec().BondMaster.Mode)
548+
asrt.EqualValues(200, r.TypedSpec().BondMaster.UpDelay)
527549
}
528550
},
529551
)

internal/app/machined/pkg/controllers/network/link_spec.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,12 @@ func (ctrl *LinkSpecController) syncLink(ctx context.Context, r controller.Runti
393393
return fmt.Errorf("error parsing bond attributes for %q: %w", link.TypedSpec().Name, err)
394394
}
395395

396-
if existingBond != link.TypedSpec().BondMaster {
396+
// primaryIndex might be reported from the kernel, but if it's nil in the spec, we should treat it as equal
397+
if existingBond.PrimaryIndex != nil && link.TypedSpec().BondMaster.PrimaryIndex == nil {
398+
existingBond.PrimaryIndex = nil
399+
}
400+
401+
if !existingBond.Equal(&link.TypedSpec().BondMaster) {
397402
logger.Debug("updating bond settings",
398403
zap.String("old", fmt.Sprintf("%+v", existingBond)),
399404
zap.String("new", fmt.Sprintf("%+v", link.TypedSpec().BondMaster)),

0 commit comments

Comments
 (0)