1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
4 #include <linux/if_arp.h>
6 #include "alloc-util.h"
9 #include "conf-parser.h"
10 #include "ether-addr-util.h"
11 #include "extract-word.h"
12 #include "netlink-util.h"
13 #include "networkd-manager.h"
14 #include "string-table.h"
17 * Number of seconds between instances where the bonding
18 * driver sends learning packets to each slaves peer switch
20 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
21 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
23 /* Number of IGMP membership reports to be issued after
26 #define RESEND_IGMP_MIN 0
27 #define RESEND_IGMP_MAX 255
28 #define RESEND_IGMP_DEFAULT 1
31 * Number of packets to transmit through a slave before
32 * moving to the next one.
34 #define PACKETS_PER_SLAVE_MIN 0
35 #define PACKETS_PER_SLAVE_MAX 65535
36 #define PACKETS_PER_SLAVE_DEFAULT 1
39 * Number of peer notifications (gratuitous ARPs and
40 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
43 #define GRATUITOUS_ARP_MIN 0
44 #define GRATUITOUS_ARP_MAX 255
45 #define GRATUITOUS_ARP_DEFAULT 1
47 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
, "Failed to parse bond mode");
48 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
49 bond_xmit_hash_policy
,
51 "Failed to parse bond transmit hash policy");
52 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
, "Failed to parse bond lacp rate");
53 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
, "Failed to parse bond AD select");
54 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
, "Failed to parse bond fail over MAC");
55 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
, "Failed to parse bond arp validate");
56 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
, "Failed to parse bond Arp all targets");
57 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
, "Failed to parse bond primary reselect");
59 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
63 Bond
*b
= BOND(netdev
);
66 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
) {
67 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
, b
->mode
);
72 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
73 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
, b
->xmit_hash_policy
);
78 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
79 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
80 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
86 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
91 if (b
->peer_notify_delay
!= 0) {
92 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PEER_NOTIF_DELAY
, b
->peer_notify_delay
/ USEC_PER_MSEC
);
97 if (b
->downdelay
!= 0) {
98 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
103 if (b
->updelay
!= 0) {
104 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
109 if (b
->arp_interval
!= 0) {
110 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
114 if (b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
&&
115 b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
) {
116 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
122 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
123 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
124 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
129 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
130 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
) {
131 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
136 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
137 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
142 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
143 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
148 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
149 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_PRIMARY_RESELECT
, b
->primary_reselect
);
154 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
155 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
160 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
161 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
162 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
167 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
168 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
173 if (b
->min_links
!= 0) {
174 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
179 if (b
->ad_actor_sys_prio
!= 0) {
180 r
= sd_netlink_message_append_u16(m
, IFLA_BOND_AD_ACTOR_SYS_PRIO
, b
->ad_actor_sys_prio
);
185 if (b
->ad_user_port_key
!= 0) {
186 r
= sd_netlink_message_append_u16(m
, IFLA_BOND_AD_USER_PORT_KEY
, b
->ad_user_port_key
);
191 if (!ether_addr_is_null(&b
->ad_actor_system
)) {
192 r
= sd_netlink_message_append_ether_addr(m
, IFLA_BOND_AD_ACTOR_SYSTEM
, &b
->ad_actor_system
);
197 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
201 if (b
->tlb_dynamic_lb
>= 0) {
202 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_TLB_DYNAMIC_LB
, b
->tlb_dynamic_lb
);
207 if (b
->arp_missed_max
> 0) {
208 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MISSED_MAX
, b
->arp_missed_max
);
213 if (b
->arp_interval
> 0 && !ordered_set_isempty(b
->arp_ip_targets
)) {
217 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
221 ORDERED_SET_FOREACH(val
, b
->arp_ip_targets
) {
222 r
= sd_netlink_message_append_u32(m
, n
++, PTR_TO_UINT32(val
));
227 r
= sd_netlink_message_close_container(m
);
235 int config_parse_arp_ip_target_address(
237 const char *filename
,
240 unsigned section_line
,
252 Bond
*b
= BOND(userdata
);
255 if (isempty(rvalue
)) {
256 b
->arp_ip_targets
= ordered_set_free(b
->arp_ip_targets
);
260 for (const char *p
= rvalue
;;) {
261 _cleanup_free_
char *n
= NULL
;
262 union in_addr_union ip
;
264 r
= extract_first_word(&p
, &n
, NULL
, 0);
268 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
269 "Failed to parse Bond ARP IP target address, ignoring assignment: %s",
276 r
= in_addr_from_string(AF_INET
, n
, &ip
);
278 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
279 "Bond ARP IP target address is invalid, ignoring assignment: %s", n
);
283 if (ordered_set_size(b
->arp_ip_targets
) >= NETDEV_BOND_ARP_TARGETS_MAX
) {
284 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
285 "Too many ARP IP targets are specified. The maximum number is %d. Ignoring assignment: %s",
286 NETDEV_BOND_ARP_TARGETS_MAX
, n
);
290 r
= ordered_set_ensure_put(&b
->arp_ip_targets
, NULL
, UINT32_TO_PTR(ip
.in
.s_addr
));
294 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
295 "Bond ARP IP target address is duplicated, ignoring assignment: %s", n
);
297 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
298 "Failed to store bond ARP IP target address '%s', ignoring assignment: %m", n
);
302 int config_parse_ad_actor_sys_prio(
304 const char *filename
,
307 unsigned section_line
,
319 Bond
*b
= ASSERT_PTR(userdata
);
321 return config_parse_uint16_bounded(
322 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
324 &b
->ad_actor_sys_prio
);
327 int config_parse_ad_user_port_key(
329 const char *filename
,
332 unsigned section_line
,
344 Bond
*b
= ASSERT_PTR(userdata
);
346 return config_parse_uint16_bounded(
347 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
348 0, 1023, /* ignoring= */ true,
349 &b
->ad_user_port_key
);
352 int config_parse_ad_actor_system(
354 const char *filename
,
357 unsigned section_line
,
372 r
= parse_ether_addr(rvalue
, &n
);
374 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
375 "Not a valid MAC address %s. Ignoring assignment: %m",
379 if (ether_addr_is_null(&n
) || (n
.ether_addr_octet
[0] & 0x01)) {
380 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
381 "Not an appropriate MAC address %s, cannot be null or multicast. Ignoring assignment.",
386 b
->ad_actor_system
= n
;
391 static void bond_done(NetDev
*netdev
) {
392 Bond
*b
= BOND(netdev
);
394 ordered_set_free(b
->arp_ip_targets
);
397 static void bond_init(NetDev
*netdev
) {
398 Bond
*b
= BOND(netdev
);
400 b
->mode
= _NETDEV_BOND_MODE_INVALID
;
401 b
->xmit_hash_policy
= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
;
402 b
->lacp_rate
= _NETDEV_BOND_LACP_RATE_INVALID
;
403 b
->ad_select
= _NETDEV_BOND_AD_SELECT_INVALID
;
404 b
->fail_over_mac
= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
;
405 b
->arp_validate
= _NETDEV_BOND_ARP_VALIDATE_INVALID
;
406 b
->arp_all_targets
= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
;
407 b
->primary_reselect
= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
;
409 b
->all_slaves_active
= false;
410 b
->tlb_dynamic_lb
= -1;
412 b
->resend_igmp
= RESEND_IGMP_DEFAULT
;
413 b
->packets_per_slave
= PACKETS_PER_SLAVE_DEFAULT
;
414 b
->num_grat_arp
= GRATUITOUS_ARP_DEFAULT
;
415 b
->lp_interval
= LEARNING_PACKETS_INTERVAL_MIN_SEC
;
418 const NetDevVTable bond_vtable
= {
419 .object_size
= sizeof(Bond
),
422 .sections
= NETDEV_COMMON_SECTIONS
"Bond\0",
423 .fill_message_create
= netdev_bond_fill_message_create
,
424 .create_type
= NETDEV_CREATE_INDEPENDENT
,
425 .iftype
= ARPHRD_ETHER
,
426 .generate_mac
= true,