1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Tom Gundersen <teg@jklm.no>
4 Copyright © 2014 Susant Sahani
7 #include <netinet/ether.h>
8 #include <linux/if_bonding.h>
10 #include "sd-netlink.h"
12 #include "alloc-util.h"
13 #include "conf-parser.h"
14 #include "extract-word.h"
16 #include "netdev/bond.h"
17 #include "string-table.h"
18 #include "string-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 static const char* const bond_mode_table
[_NETDEV_BOND_MODE_MAX
] = {
52 [NETDEV_BOND_MODE_BALANCE_RR
] = "balance-rr",
53 [NETDEV_BOND_MODE_ACTIVE_BACKUP
] = "active-backup",
54 [NETDEV_BOND_MODE_BALANCE_XOR
] = "balance-xor",
55 [NETDEV_BOND_MODE_BROADCAST
] = "broadcast",
56 [NETDEV_BOND_MODE_802_3AD
] = "802.3ad",
57 [NETDEV_BOND_MODE_BALANCE_TLB
] = "balance-tlb",
58 [NETDEV_BOND_MODE_BALANCE_ALB
] = "balance-alb",
61 DEFINE_STRING_TABLE_LOOKUP(bond_mode
, BondMode
);
62 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
, "Failed to parse bond mode");
64 static const char* const bond_xmit_hash_policy_table
[_NETDEV_BOND_XMIT_HASH_POLICY_MAX
] = {
65 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
] = "layer2",
66 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
] = "layer3+4",
67 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
] = "layer2+3",
68 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
] = "encap2+3",
69 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
] = "encap3+4",
72 DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy
, BondXmitHashPolicy
);
73 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
74 bond_xmit_hash_policy
,
76 "Failed to parse bond transmit hash policy")
78 static const char* const bond_lacp_rate_table
[_NETDEV_BOND_LACP_RATE_MAX
] = {
79 [NETDEV_BOND_LACP_RATE_SLOW
] = "slow",
80 [NETDEV_BOND_LACP_RATE_FAST
] = "fast",
83 DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate
, BondLacpRate
);
84 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
, "Failed to parse bond lacp rate")
86 static const char* const bond_ad_select_table
[_NETDEV_BOND_AD_SELECT_MAX
] = {
87 [NETDEV_BOND_AD_SELECT_STABLE
] = "stable",
88 [NETDEV_BOND_AD_SELECT_BANDWIDTH
] = "bandwidth",
89 [NETDEV_BOND_AD_SELECT_COUNT
] = "count",
92 DEFINE_STRING_TABLE_LOOKUP(bond_ad_select
, BondAdSelect
);
93 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
, "Failed to parse bond AD select");
95 static const char* const bond_fail_over_mac_table
[_NETDEV_BOND_FAIL_OVER_MAC_MAX
] = {
96 [NETDEV_BOND_FAIL_OVER_MAC_NONE
] = "none",
97 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE
] = "active",
98 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW
] = "follow",
101 DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac
, BondFailOverMac
);
102 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
, "Failed to parse bond fail over MAC");
104 static const char *const bond_arp_validate_table
[_NETDEV_BOND_ARP_VALIDATE_MAX
] = {
105 [NETDEV_BOND_ARP_VALIDATE_NONE
] = "none",
106 [NETDEV_BOND_ARP_VALIDATE_ACTIVE
]= "active",
107 [NETDEV_BOND_ARP_VALIDATE_BACKUP
]= "backup",
108 [NETDEV_BOND_ARP_VALIDATE_ALL
]= "all",
111 DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate
, BondArpValidate
);
112 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
, "Failed to parse bond arp validate");
114 static const char *const bond_arp_all_targets_table
[_NETDEV_BOND_ARP_ALL_TARGETS_MAX
] = {
115 [NETDEV_BOND_ARP_ALL_TARGETS_ANY
] = "any",
116 [NETDEV_BOND_ARP_ALL_TARGETS_ALL
] = "all",
119 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets
, BondArpAllTargets
);
120 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
, "Failed to parse bond Arp all targets");
122 static const char *bond_primary_reselect_table
[_NETDEV_BOND_PRIMARY_RESELECT_MAX
] = {
123 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS
] = "always",
124 [NETDEV_BOND_PRIMARY_RESELECT_BETTER
]= "better",
125 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE
]= "failure",
128 DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect
, BondPrimaryReselect
);
129 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
, "Failed to parse bond primary reselect");
131 static uint8_t bond_mode_to_kernel(BondMode mode
) {
133 case NETDEV_BOND_MODE_BALANCE_RR
:
134 return BOND_MODE_ROUNDROBIN
;
135 case NETDEV_BOND_MODE_ACTIVE_BACKUP
:
136 return BOND_MODE_ACTIVEBACKUP
;
137 case NETDEV_BOND_MODE_BALANCE_XOR
:
138 return BOND_MODE_XOR
;
139 case NETDEV_BOND_MODE_BROADCAST
:
140 return BOND_MODE_BROADCAST
;
141 case NETDEV_BOND_MODE_802_3AD
:
142 return BOND_MODE_8023AD
;
143 case NETDEV_BOND_MODE_BALANCE_TLB
:
144 return BOND_MODE_TLB
;
145 case NETDEV_BOND_MODE_BALANCE_ALB
:
146 return BOND_MODE_ALB
;
152 static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy
) {
154 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
:
155 return BOND_XMIT_POLICY_LAYER2
;
156 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
:
157 return BOND_XMIT_POLICY_LAYER34
;
158 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
:
159 return BOND_XMIT_POLICY_LAYER23
;
160 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
:
161 return BOND_XMIT_POLICY_ENCAP23
;
162 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
:
163 return BOND_XMIT_POLICY_ENCAP34
;
169 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
171 ArpIpTarget
*target
= NULL
;
182 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
) {
183 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
,
184 bond_mode_to_kernel(b
->mode
));
186 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MODE attribute: %m");
189 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
190 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
,
191 bond_xmit_hash_policy_to_kernel(b
->xmit_hash_policy
));
193 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
196 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
197 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
198 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
200 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
203 if (b
->miimon
!= 0) {
204 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
206 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
209 if (b
->downdelay
!= 0) {
210 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
212 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
215 if (b
->updelay
!= 0) {
216 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
218 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_UPDELAY attribute: %m");
221 if (b
->arp_interval
!= 0) {
222 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
224 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
226 if ((b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
) &&
227 (b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
)) {
228 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
230 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
234 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
235 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
236 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
238 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
241 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
242 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
) {
243 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
245 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
248 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
249 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
251 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
254 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
255 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
257 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
260 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
261 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_PRIMARY_RESELECT
, b
->primary_reselect
);
263 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PRIMARY_RESELECT attribute: %m");
266 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
267 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
269 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
272 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
273 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
274 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
276 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
279 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
280 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
282 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
285 if (b
->min_links
!= 0) {
286 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
288 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
291 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
293 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
295 if (b
->arp_interval
> 0) {
296 if (b
->n_arp_ip_targets
> 0) {
298 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
300 return log_netdev_error_errno(netdev
, r
, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
302 LIST_FOREACH(arp_ip_target
, target
, b
->arp_ip_targets
) {
303 r
= sd_netlink_message_append_u32(m
, i
++, target
->ip
.in
.s_addr
);
305 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
308 r
= sd_netlink_message_close_container(m
);
310 return log_netdev_error_errno(netdev
, r
, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
317 int config_parse_arp_ip_target_address(const char *unit
,
318 const char *filename
,
321 unsigned section_line
,
336 _cleanup_free_ ArpIpTarget
*buffer
= NULL
;
337 _cleanup_free_
char *n
= NULL
;
340 r
= extract_first_word(&rvalue
, &n
, NULL
, 0);
342 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue
);
349 buffer
= new0(ArpIpTarget
, 1);
353 r
= in_addr_from_string_auto(n
, &f
, &buffer
->ip
);
355 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
360 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
364 LIST_PREPEND(arp_ip_target
, b
->arp_ip_targets
, buffer
);
365 b
->n_arp_ip_targets
++;
370 if (b
->n_arp_ip_targets
> NETDEV_BOND_ARP_TARGETS_MAX
)
371 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
372 "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
373 b
->n_arp_ip_targets
, NETDEV_BOND_ARP_TARGETS_MAX
);
378 static void bond_done(NetDev
*netdev
) {
379 ArpIpTarget
*t
= NULL
, *n
= NULL
;
388 LIST_FOREACH_SAFE(arp_ip_target
, t
, n
, b
->arp_ip_targets
)
391 b
->arp_ip_targets
= NULL
;
394 static void bond_init(NetDev
*netdev
) {
403 b
->mode
= _NETDEV_BOND_MODE_INVALID
;
404 b
->xmit_hash_policy
= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
;
405 b
->lacp_rate
= _NETDEV_BOND_LACP_RATE_INVALID
;
406 b
->ad_select
= _NETDEV_BOND_AD_SELECT_INVALID
;
407 b
->fail_over_mac
= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
;
408 b
->arp_validate
= _NETDEV_BOND_ARP_VALIDATE_INVALID
;
409 b
->arp_all_targets
= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
;
410 b
->primary_reselect
= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
;
412 b
->all_slaves_active
= false;
414 b
->resend_igmp
= RESEND_IGMP_DEFAULT
;
415 b
->packets_per_slave
= PACKETS_PER_SLAVE_DEFAULT
;
416 b
->num_grat_arp
= GRATUITOUS_ARP_DEFAULT
;
417 b
->lp_interval
= LEARNING_PACKETS_INTERVAL_MIN_SEC
;
419 LIST_HEAD_INIT(b
->arp_ip_targets
);
420 b
->n_arp_ip_targets
= 0;
423 const NetDevVTable bond_vtable
= {
424 .object_size
= sizeof(Bond
),
427 .sections
= "Match\0NetDev\0Bond\0",
428 .fill_message_create
= netdev_bond_fill_message_create
,
429 .create_type
= NETDEV_CREATE_MASTER
,