1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/if_arp.h>
4 #include <netinet/in.h>
6 #include "sd-netlink.h"
8 #include "alloc-util.h"
10 #include "bond-util.h"
11 #include "conf-parser.h"
12 #include "ether-addr-util.h"
13 #include "extract-word.h"
14 #include "in-addr-util.h"
15 #include "networkd-link.h"
16 #include "ordered-set.h"
18 #include "string-util.h"
19 #include "time-util.h"
21 * Number of seconds between instances where the bonding
22 * driver sends learning packets to each slaves peer switch
24 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
25 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
27 /* Number of IGMP membership reports to be issued after
30 #define RESEND_IGMP_MIN 0
31 #define RESEND_IGMP_MAX 255
32 #define RESEND_IGMP_DEFAULT 1
35 * Number of packets to transmit through a slave before
36 * moving to the next one.
38 #define PACKETS_PER_SLAVE_MIN 0
39 #define PACKETS_PER_SLAVE_MAX 65535
40 #define PACKETS_PER_SLAVE_DEFAULT 1
43 * Number of peer notifications (gratuitous ARPs and
44 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
47 #define GRATUITOUS_ARP_MIN 0
48 #define GRATUITOUS_ARP_MAX 255
49 #define GRATUITOUS_ARP_DEFAULT 1
51 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
);
52 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
53 bond_xmit_hash_policy
,
55 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
);
56 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
);
57 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
);
58 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
);
59 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
);
60 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
);
62 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
63 Bond
*b
= BOND(netdev
);
66 assert(netdev
->manager
);
70 if (netdev
->ifindex
> 0) {
71 r
= link_get_by_index(netdev
->manager
, netdev
->ifindex
, &link
);
76 bool up
= link
&& FLAGS_SET(link
->flags
, IFF_UP
);
77 bool has_slaves
= link
&& !set_isempty(link
->slaves
);
79 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
&& !up
&& !has_slaves
) {
80 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
, b
->mode
);
85 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
86 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
, b
->xmit_hash_policy
);
91 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
92 b
->mode
== NETDEV_BOND_MODE_802_3AD
&&
94 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
100 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
105 if (b
->peer_notify_delay
!= 0) {
106 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PEER_NOTIF_DELAY
, b
->peer_notify_delay
/ USEC_PER_MSEC
);
111 if (b
->downdelay
!= 0) {
112 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
117 if (b
->updelay
!= 0) {
118 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
123 if (b
->arp_interval
!= 0) {
124 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
128 if (b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
&&
129 b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
) {
130 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
136 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
137 b
->mode
== NETDEV_BOND_MODE_802_3AD
&&
139 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
144 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
145 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
&&
147 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
152 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
153 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
158 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
159 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
164 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
165 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_PRIMARY_RESELECT
, b
->primary_reselect
);
170 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
171 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
176 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
177 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
178 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
183 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
184 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
189 if (b
->min_links
!= 0) {
190 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
195 if (b
->ad_actor_sys_prio
!= 0) {
196 r
= sd_netlink_message_append_u16(m
, IFLA_BOND_AD_ACTOR_SYS_PRIO
, b
->ad_actor_sys_prio
);
201 if (b
->ad_user_port_key
!= 0 && !up
) {
202 r
= sd_netlink_message_append_u16(m
, IFLA_BOND_AD_USER_PORT_KEY
, b
->ad_user_port_key
);
207 if (!ether_addr_is_null(&b
->ad_actor_system
)) {
208 r
= sd_netlink_message_append_ether_addr(m
, IFLA_BOND_AD_ACTOR_SYSTEM
, &b
->ad_actor_system
);
213 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
217 if (b
->tlb_dynamic_lb
>= 0 && !up
) {
218 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_TLB_DYNAMIC_LB
, b
->tlb_dynamic_lb
);
223 if (b
->arp_missed_max
> 0) {
224 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MISSED_MAX
, b
->arp_missed_max
);
229 if (b
->arp_interval
> 0 && !ordered_set_isempty(b
->arp_ip_targets
)) {
233 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
237 ORDERED_SET_FOREACH(val
, b
->arp_ip_targets
) {
238 r
= sd_netlink_message_append_u32(m
, n
++, PTR_TO_UINT32(val
));
243 r
= sd_netlink_message_close_container(m
);
251 int config_parse_arp_ip_target_address(
253 const char *filename
,
256 unsigned section_line
,
268 Bond
*b
= BOND(userdata
);
271 if (isempty(rvalue
)) {
272 b
->arp_ip_targets
= ordered_set_free(b
->arp_ip_targets
);
276 for (const char *p
= rvalue
;;) {
277 _cleanup_free_
char *n
= NULL
;
278 union in_addr_union ip
;
280 r
= extract_first_word(&p
, &n
, NULL
, 0);
284 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
285 "Failed to parse Bond ARP IP target address, ignoring assignment: %s",
292 r
= in_addr_from_string(AF_INET
, n
, &ip
);
294 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
295 "Bond ARP IP target address is invalid, ignoring assignment: %s", n
);
299 if (ordered_set_size(b
->arp_ip_targets
) >= NETDEV_BOND_ARP_TARGETS_MAX
) {
300 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
301 "Too many ARP IP targets are specified. The maximum number is %d. Ignoring assignment: %s",
302 NETDEV_BOND_ARP_TARGETS_MAX
, n
);
306 r
= ordered_set_ensure_put(&b
->arp_ip_targets
, NULL
, UINT32_TO_PTR(ip
.in
.s_addr
));
310 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
311 "Bond ARP IP target address is duplicated, ignoring assignment: %s", n
);
313 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
314 "Failed to store bond ARP IP target address '%s', ignoring assignment: %m", n
);
318 int config_parse_ad_actor_sys_prio(
320 const char *filename
,
323 unsigned section_line
,
335 Bond
*b
= ASSERT_PTR(userdata
);
337 return config_parse_uint16_bounded(
338 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
340 &b
->ad_actor_sys_prio
);
343 int config_parse_ad_user_port_key(
345 const char *filename
,
348 unsigned section_line
,
360 Bond
*b
= ASSERT_PTR(userdata
);
362 return config_parse_uint16_bounded(
363 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
364 0, 1023, /* ignoring= */ true,
365 &b
->ad_user_port_key
);
368 int config_parse_ad_actor_system(
370 const char *filename
,
373 unsigned section_line
,
388 r
= parse_ether_addr(rvalue
, &n
);
390 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
391 "Not a valid MAC address %s. Ignoring assignment: %m",
395 if (ether_addr_is_null(&n
) || (n
.ether_addr_octet
[0] & 0x01)) {
396 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
397 "Not an appropriate MAC address %s, cannot be null or multicast. Ignoring assignment.",
402 b
->ad_actor_system
= n
;
407 static void bond_done(NetDev
*netdev
) {
408 Bond
*b
= BOND(netdev
);
410 ordered_set_free(b
->arp_ip_targets
);
413 static void bond_init(NetDev
*netdev
) {
414 Bond
*b
= BOND(netdev
);
416 b
->mode
= _NETDEV_BOND_MODE_INVALID
;
417 b
->xmit_hash_policy
= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
;
418 b
->lacp_rate
= _NETDEV_BOND_LACP_RATE_INVALID
;
419 b
->ad_select
= _NETDEV_BOND_AD_SELECT_INVALID
;
420 b
->fail_over_mac
= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
;
421 b
->arp_validate
= _NETDEV_BOND_ARP_VALIDATE_INVALID
;
422 b
->arp_all_targets
= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
;
423 b
->primary_reselect
= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
;
425 b
->all_slaves_active
= false;
426 b
->tlb_dynamic_lb
= -1;
428 b
->resend_igmp
= RESEND_IGMP_DEFAULT
;
429 b
->packets_per_slave
= PACKETS_PER_SLAVE_DEFAULT
;
430 b
->num_grat_arp
= GRATUITOUS_ARP_DEFAULT
;
431 b
->lp_interval
= LEARNING_PACKETS_INTERVAL_MIN_SEC
;
434 const NetDevVTable bond_vtable
= {
435 .object_size
= sizeof(Bond
),
438 .sections
= NETDEV_COMMON_SECTIONS
"Bond\0",
439 .fill_message_create
= netdev_bond_fill_message_create
,
440 .create_type
= NETDEV_CREATE_INDEPENDENT
,
441 .iftype
= ARPHRD_ETHER
,
442 .generate_mac
= true,