1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <netinet/ether.h>
4 #include <linux/if_bonding.h>
6 #include "sd-netlink.h"
8 #include "alloc-util.h"
9 #include "conf-parser.h"
10 #include "ether-addr-util.h"
11 #include "extract-word.h"
13 #include "netdev/bond.h"
14 #include "string-table.h"
15 #include "string-util.h"
18 * Number of seconds between instances where the bonding
19 * driver sends learning packets to each slaves peer switch
21 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
22 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
24 /* Number of IGMP membership reports to be issued after
27 #define RESEND_IGMP_MIN 0
28 #define RESEND_IGMP_MAX 255
29 #define RESEND_IGMP_DEFAULT 1
32 * Number of packets to transmit through a slave before
33 * moving to the next one.
35 #define PACKETS_PER_SLAVE_MIN 0
36 #define PACKETS_PER_SLAVE_MAX 65535
37 #define PACKETS_PER_SLAVE_DEFAULT 1
40 * Number of peer notifications (gratuitous ARPs and
41 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
44 #define GRATUITOUS_ARP_MIN 0
45 #define GRATUITOUS_ARP_MAX 255
46 #define GRATUITOUS_ARP_DEFAULT 1
48 static const char* const bond_mode_table
[_NETDEV_BOND_MODE_MAX
] = {
49 [NETDEV_BOND_MODE_BALANCE_RR
] = "balance-rr",
50 [NETDEV_BOND_MODE_ACTIVE_BACKUP
] = "active-backup",
51 [NETDEV_BOND_MODE_BALANCE_XOR
] = "balance-xor",
52 [NETDEV_BOND_MODE_BROADCAST
] = "broadcast",
53 [NETDEV_BOND_MODE_802_3AD
] = "802.3ad",
54 [NETDEV_BOND_MODE_BALANCE_TLB
] = "balance-tlb",
55 [NETDEV_BOND_MODE_BALANCE_ALB
] = "balance-alb",
58 DEFINE_STRING_TABLE_LOOKUP(bond_mode
, BondMode
);
59 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
, "Failed to parse bond mode");
61 static const char* const bond_xmit_hash_policy_table
[_NETDEV_BOND_XMIT_HASH_POLICY_MAX
] = {
62 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
] = "layer2",
63 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
] = "layer3+4",
64 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
] = "layer2+3",
65 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
] = "encap2+3",
66 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
] = "encap3+4",
69 DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy
, BondXmitHashPolicy
);
70 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
71 bond_xmit_hash_policy
,
73 "Failed to parse bond transmit hash policy")
75 static const char* const bond_lacp_rate_table
[_NETDEV_BOND_LACP_RATE_MAX
] = {
76 [NETDEV_BOND_LACP_RATE_SLOW
] = "slow",
77 [NETDEV_BOND_LACP_RATE_FAST
] = "fast",
80 DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate
, BondLacpRate
);
81 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
, "Failed to parse bond lacp rate")
83 static const char* const bond_ad_select_table
[_NETDEV_BOND_AD_SELECT_MAX
] = {
84 [NETDEV_BOND_AD_SELECT_STABLE
] = "stable",
85 [NETDEV_BOND_AD_SELECT_BANDWIDTH
] = "bandwidth",
86 [NETDEV_BOND_AD_SELECT_COUNT
] = "count",
89 DEFINE_STRING_TABLE_LOOKUP(bond_ad_select
, BondAdSelect
);
90 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
, "Failed to parse bond AD select");
92 static const char* const bond_fail_over_mac_table
[_NETDEV_BOND_FAIL_OVER_MAC_MAX
] = {
93 [NETDEV_BOND_FAIL_OVER_MAC_NONE
] = "none",
94 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE
] = "active",
95 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW
] = "follow",
98 DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac
, BondFailOverMac
);
99 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
, "Failed to parse bond fail over MAC");
101 static const char *const bond_arp_validate_table
[_NETDEV_BOND_ARP_VALIDATE_MAX
] = {
102 [NETDEV_BOND_ARP_VALIDATE_NONE
] = "none",
103 [NETDEV_BOND_ARP_VALIDATE_ACTIVE
]= "active",
104 [NETDEV_BOND_ARP_VALIDATE_BACKUP
]= "backup",
105 [NETDEV_BOND_ARP_VALIDATE_ALL
]= "all",
108 DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate
, BondArpValidate
);
109 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
, "Failed to parse bond arp validate");
111 static const char *const bond_arp_all_targets_table
[_NETDEV_BOND_ARP_ALL_TARGETS_MAX
] = {
112 [NETDEV_BOND_ARP_ALL_TARGETS_ANY
] = "any",
113 [NETDEV_BOND_ARP_ALL_TARGETS_ALL
] = "all",
116 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets
, BondArpAllTargets
);
117 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
, "Failed to parse bond Arp all targets");
119 static const char *bond_primary_reselect_table
[_NETDEV_BOND_PRIMARY_RESELECT_MAX
] = {
120 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS
] = "always",
121 [NETDEV_BOND_PRIMARY_RESELECT_BETTER
]= "better",
122 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE
]= "failure",
125 DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect
, BondPrimaryReselect
);
126 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
, "Failed to parse bond primary reselect");
128 static uint8_t bond_mode_to_kernel(BondMode mode
) {
130 case NETDEV_BOND_MODE_BALANCE_RR
:
131 return BOND_MODE_ROUNDROBIN
;
132 case NETDEV_BOND_MODE_ACTIVE_BACKUP
:
133 return BOND_MODE_ACTIVEBACKUP
;
134 case NETDEV_BOND_MODE_BALANCE_XOR
:
135 return BOND_MODE_XOR
;
136 case NETDEV_BOND_MODE_BROADCAST
:
137 return BOND_MODE_BROADCAST
;
138 case NETDEV_BOND_MODE_802_3AD
:
139 return BOND_MODE_8023AD
;
140 case NETDEV_BOND_MODE_BALANCE_TLB
:
141 return BOND_MODE_TLB
;
142 case NETDEV_BOND_MODE_BALANCE_ALB
:
143 return BOND_MODE_ALB
;
149 static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy
) {
151 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
:
152 return BOND_XMIT_POLICY_LAYER2
;
153 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
:
154 return BOND_XMIT_POLICY_LAYER34
;
155 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
:
156 return BOND_XMIT_POLICY_LAYER23
;
157 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
:
158 return BOND_XMIT_POLICY_ENCAP23
;
159 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
:
160 return BOND_XMIT_POLICY_ENCAP34
;
166 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
168 ArpIpTarget
*target
= NULL
;
179 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
) {
180 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
, bond_mode_to_kernel(b
->mode
));
182 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MODE attribute: %m");
185 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
186 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
,
187 bond_xmit_hash_policy_to_kernel(b
->xmit_hash_policy
));
189 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
192 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
193 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
194 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
196 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
199 if (b
->miimon
!= 0) {
200 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
202 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
205 if (b
->downdelay
!= 0) {
206 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
208 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
211 if (b
->updelay
!= 0) {
212 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
214 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_UPDELAY attribute: %m");
217 if (b
->arp_interval
!= 0) {
218 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
220 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
222 if (b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
&&
223 b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
) {
224 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
226 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
230 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
231 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
232 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
234 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
237 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
238 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
) {
239 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
241 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
244 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
245 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
247 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
250 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
251 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
253 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
256 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
257 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_PRIMARY_RESELECT
, b
->primary_reselect
);
259 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PRIMARY_RESELECT attribute: %m");
262 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
263 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
265 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
268 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
269 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
270 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
272 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
275 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
276 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
278 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
281 if (b
->min_links
!= 0) {
282 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
284 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
287 if (b
->ad_actor_sys_prio
!= 0) {
288 r
= sd_netlink_message_append_u16(m
, IFLA_BOND_AD_ACTOR_SYS_PRIO
, b
->ad_actor_sys_prio
);
290 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_ACTOR_SYS_PRIO attribute: %m");
293 if (b
->ad_user_port_key
!= 0) {
294 r
= sd_netlink_message_append_u16(m
, IFLA_BOND_AD_USER_PORT_KEY
, b
->ad_user_port_key
);
296 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_USER_PORT_KEY attribute: %m");
299 if (b
->ad_actor_system
) {
300 r
= sd_netlink_message_append_ether_addr(m
, IFLA_BOND_AD_ACTOR_SYSTEM
, b
->ad_actor_system
);
302 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_ACTOR_SYSTEM attribute: %m");
305 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
307 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
309 if (b
->tlb_dynamic_lb
>= 0) {
310 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_TLB_DYNAMIC_LB
, b
->tlb_dynamic_lb
);
312 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_TLB_DYNAMIC_LB attribute: %m");
315 if (b
->arp_interval
> 0 && b
->n_arp_ip_targets
> 0) {
316 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
318 return log_netdev_error_errno(netdev
, r
, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
320 LIST_FOREACH(arp_ip_target
, target
, b
->arp_ip_targets
) {
321 r
= sd_netlink_message_append_u32(m
, i
++, target
->ip
.in
.s_addr
);
323 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
326 r
= sd_netlink_message_close_container(m
);
328 return log_netdev_error_errno(netdev
, r
, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
334 int config_parse_arp_ip_target_address(const char *unit
,
335 const char *filename
,
338 unsigned section_line
,
353 _cleanup_free_ ArpIpTarget
*buffer
= NULL
;
354 _cleanup_free_
char *n
= NULL
;
357 r
= extract_first_word(&rvalue
, &n
, NULL
, 0);
359 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue
);
366 buffer
= new0(ArpIpTarget
, 1);
370 r
= in_addr_from_string_auto(n
, &f
, &buffer
->ip
);
372 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
377 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
381 LIST_PREPEND(arp_ip_target
, b
->arp_ip_targets
, TAKE_PTR(buffer
));
382 b
->n_arp_ip_targets
++;
385 if (b
->n_arp_ip_targets
> NETDEV_BOND_ARP_TARGETS_MAX
)
386 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
387 "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
388 b
->n_arp_ip_targets
, NETDEV_BOND_ARP_TARGETS_MAX
);
393 int config_parse_ad_actor_sys_prio(const char *unit
,
394 const char *filename
,
397 unsigned section_line
,
412 r
= safe_atou16(rvalue
, &v
);
414 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse actor system priority '%s', ignoring: %m", rvalue
);
419 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse actor system priority '%s'. Range is [1,65535], ignoring.", rvalue
);
423 b
->ad_actor_sys_prio
= v
;
428 int config_parse_ad_user_port_key(const char *unit
,
429 const char *filename
,
432 unsigned section_line
,
447 r
= safe_atou16(rvalue
, &v
);
449 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse user port key '%s', ignoring: %m", rvalue
);
454 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse user port key '%s'. Range is [0,1023], ignoring.", rvalue
);
458 b
->ad_user_port_key
= v
;
463 int config_parse_ad_actor_system(const char *unit
,
464 const char *filename
,
467 unsigned section_line
,
474 _cleanup_free_
struct ether_addr
*n
= NULL
;
482 n
= new0(struct ether_addr
, 1);
486 r
= ether_addr_from_string(rvalue
, n
);
488 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Not a valid MAC address %s. Ignoring assignment: %m", rvalue
);
492 if (ether_addr_is_null(n
) || (n
->ether_addr_octet
[0] & 0x01)) {
493 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Not a valid MAC address %s, can not be null or multicast. Ignoring assignment.", rvalue
);
497 free_and_replace(b
->ad_actor_system
, n
);
502 static void bond_done(NetDev
*netdev
) {
503 ArpIpTarget
*t
= NULL
, *n
= NULL
;
512 free(b
->ad_actor_system
);
514 LIST_FOREACH_SAFE(arp_ip_target
, t
, n
, b
->arp_ip_targets
)
517 b
->arp_ip_targets
= NULL
;
520 static void bond_init(NetDev
*netdev
) {
529 b
->mode
= _NETDEV_BOND_MODE_INVALID
;
530 b
->xmit_hash_policy
= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
;
531 b
->lacp_rate
= _NETDEV_BOND_LACP_RATE_INVALID
;
532 b
->ad_select
= _NETDEV_BOND_AD_SELECT_INVALID
;
533 b
->fail_over_mac
= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
;
534 b
->arp_validate
= _NETDEV_BOND_ARP_VALIDATE_INVALID
;
535 b
->arp_all_targets
= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
;
536 b
->primary_reselect
= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
;
538 b
->all_slaves_active
= false;
539 b
->tlb_dynamic_lb
= -1;
541 b
->resend_igmp
= RESEND_IGMP_DEFAULT
;
542 b
->packets_per_slave
= PACKETS_PER_SLAVE_DEFAULT
;
543 b
->num_grat_arp
= GRATUITOUS_ARP_DEFAULT
;
544 b
->lp_interval
= LEARNING_PACKETS_INTERVAL_MIN_SEC
;
546 LIST_HEAD_INIT(b
->arp_ip_targets
);
547 b
->n_arp_ip_targets
= 0;
550 const NetDevVTable bond_vtable
= {
551 .object_size
= sizeof(Bond
),
554 .sections
= "Match\0NetDev\0Bond\0",
555 .fill_message_create
= netdev_bond_fill_message_create
,
556 .create_type
= NETDEV_CREATE_MASTER
,