1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 Copyright 2014 Susant Sahani
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <netinet/ether.h>
24 #include <linux/if_bonding.h>
26 #include "sd-netlink.h"
28 #include "alloc-util.h"
29 #include "conf-parser.h"
31 #include "networkd-netdev-bond.h"
32 #include "string-table.h"
33 #include "string-util.h"
36 * Number of seconds between instances where the bonding
37 * driver sends learning packets to each slaves peer switch
39 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
40 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
42 /* Number of IGMP membership reports to be issued after
45 #define RESEND_IGMP_MIN 0
46 #define RESEND_IGMP_MAX 255
47 #define RESEND_IGMP_DEFAULT 1
50 * Number of packets to transmit through a slave before
51 * moving to the next one.
53 #define PACKETS_PER_SLAVE_MIN 0
54 #define PACKETS_PER_SLAVE_MAX 65535
55 #define PACKETS_PER_SLAVE_DEFAULT 1
58 * Number of peer notifications (gratuitous ARPs and
59 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
62 #define GRATUITOUS_ARP_MIN 0
63 #define GRATUITOUS_ARP_MAX 255
64 #define GRATUITOUS_ARP_DEFAULT 1
66 static const char* const bond_mode_table
[_NETDEV_BOND_MODE_MAX
] = {
67 [NETDEV_BOND_MODE_BALANCE_RR
] = "balance-rr",
68 [NETDEV_BOND_MODE_ACTIVE_BACKUP
] = "active-backup",
69 [NETDEV_BOND_MODE_BALANCE_XOR
] = "balance-xor",
70 [NETDEV_BOND_MODE_BROADCAST
] = "broadcast",
71 [NETDEV_BOND_MODE_802_3AD
] = "802.3ad",
72 [NETDEV_BOND_MODE_BALANCE_TLB
] = "balance-tlb",
73 [NETDEV_BOND_MODE_BALANCE_ALB
] = "balance-alb",
76 DEFINE_STRING_TABLE_LOOKUP(bond_mode
, BondMode
);
77 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
, "Failed to parse bond mode");
79 static const char* const bond_xmit_hash_policy_table
[_NETDEV_BOND_XMIT_HASH_POLICY_MAX
] = {
80 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
] = "layer2",
81 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
] = "layer3+4",
82 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
] = "layer2+3",
83 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
] = "encap2+3",
84 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
] = "encap3+4",
87 DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy
, BondXmitHashPolicy
);
88 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
89 bond_xmit_hash_policy
,
91 "Failed to parse bond transmit hash policy")
93 static const char* const bond_lacp_rate_table
[_NETDEV_BOND_LACP_RATE_MAX
] = {
94 [NETDEV_BOND_LACP_RATE_SLOW
] = "slow",
95 [NETDEV_BOND_LACP_RATE_FAST
] = "fast",
98 DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate
, BondLacpRate
);
99 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
, "Failed to parse bond lacp rate")
101 static const char* const bond_ad_select_table
[_NETDEV_BOND_AD_SELECT_MAX
] = {
102 [NETDEV_BOND_AD_SELECT_STABLE
] = "stable",
103 [NETDEV_BOND_AD_SELECT_BANDWIDTH
] = "bandwidth",
104 [NETDEV_BOND_AD_SELECT_COUNT
] = "count",
107 DEFINE_STRING_TABLE_LOOKUP(bond_ad_select
, BondAdSelect
);
108 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
, "Failed to parse bond AD select");
110 static const char* const bond_fail_over_mac_table
[_NETDEV_BOND_FAIL_OVER_MAC_MAX
] = {
111 [NETDEV_BOND_FAIL_OVER_MAC_NONE
] = "none",
112 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE
] = "active",
113 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW
] = "follow",
116 DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac
, BondFailOverMac
);
117 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
, "Failed to parse bond fail over MAC");
119 static const char *const bond_arp_validate_table
[_NETDEV_BOND_ARP_VALIDATE_MAX
] = {
120 [NETDEV_BOND_ARP_VALIDATE_NONE
] = "none",
121 [NETDEV_BOND_ARP_VALIDATE_ACTIVE
]= "active",
122 [NETDEV_BOND_ARP_VALIDATE_BACKUP
]= "backup",
123 [NETDEV_BOND_ARP_VALIDATE_ALL
]= "all",
126 DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate
, BondArpValidate
);
127 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
, "Failed to parse bond arp validate");
129 static const char *const bond_arp_all_targets_table
[_NETDEV_BOND_ARP_ALL_TARGETS_MAX
] = {
130 [NETDEV_BOND_ARP_ALL_TARGETS_ANY
] = "any",
131 [NETDEV_BOND_ARP_ALL_TARGETS_ALL
] = "all",
134 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets
, BondArpAllTargets
);
135 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
, "Failed to parse bond Arp all targets");
137 static const char *bond_primary_reselect_table
[_NETDEV_BOND_PRIMARY_RESELECT_MAX
] = {
138 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS
] = "always",
139 [NETDEV_BOND_PRIMARY_RESELECT_BETTER
]= "better",
140 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE
]= "failure",
143 DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect
, BondPrimaryReselect
);
144 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
, "Failed to parse bond primary reselect");
146 static uint8_t bond_mode_to_kernel(BondMode mode
) {
148 case NETDEV_BOND_MODE_BALANCE_RR
:
149 return BOND_MODE_ROUNDROBIN
;
150 case NETDEV_BOND_MODE_ACTIVE_BACKUP
:
151 return BOND_MODE_ACTIVEBACKUP
;
152 case NETDEV_BOND_MODE_BALANCE_XOR
:
153 return BOND_MODE_XOR
;
154 case NETDEV_BOND_MODE_BROADCAST
:
155 return BOND_MODE_BROADCAST
;
156 case NETDEV_BOND_MODE_802_3AD
:
157 return BOND_MODE_8023AD
;
158 case NETDEV_BOND_MODE_BALANCE_TLB
:
159 return BOND_MODE_TLB
;
160 case NETDEV_BOND_MODE_BALANCE_ALB
:
161 return BOND_MODE_ALB
;
167 static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy
) {
169 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
:
170 return BOND_XMIT_POLICY_LAYER2
;
171 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
:
172 return BOND_XMIT_POLICY_LAYER34
;
173 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
:
174 return BOND_XMIT_POLICY_LAYER23
;
175 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
:
176 return BOND_XMIT_POLICY_ENCAP23
;
177 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
:
178 return BOND_XMIT_POLICY_ENCAP34
;
184 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
186 ArpIpTarget
*target
= NULL
;
197 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
) {
198 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
,
199 bond_mode_to_kernel(b
->mode
));
201 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MODE attribute: %m");
204 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
205 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
,
206 bond_xmit_hash_policy_to_kernel(b
->xmit_hash_policy
));
208 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
211 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
212 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
213 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
215 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
218 if (b
->miimon
!= 0) {
219 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
221 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
224 if (b
->downdelay
!= 0) {
225 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
227 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
230 if (b
->updelay
!= 0) {
231 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
233 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_UPDELAY attribute: %m");
236 if (b
->arp_interval
!= 0) {
237 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
239 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
241 if ((b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
) &&
242 (b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
)) {
243 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
245 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
249 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
250 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
251 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
253 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
256 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
257 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
) {
258 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
260 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
263 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
264 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
266 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
269 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
270 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
272 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
275 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
276 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->primary_reselect
);
278 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
281 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
282 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
284 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
287 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
288 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
289 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
291 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
294 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
295 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
297 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
300 if (b
->min_links
!= 0) {
301 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
303 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
306 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
308 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
310 if (b
->arp_interval
> 0) {
311 if (b
->n_arp_ip_targets
> 0) {
313 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
315 return log_netdev_error_errno(netdev
, r
, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
317 LIST_FOREACH(arp_ip_target
, target
, b
->arp_ip_targets
) {
318 r
= sd_netlink_message_append_u32(m
, i
++, target
->ip
.in
.s_addr
);
320 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
323 r
= sd_netlink_message_close_container(m
);
325 return log_netdev_error_errno(netdev
, r
, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
332 int config_parse_arp_ip_target_address(const char *unit
,
333 const char *filename
,
336 unsigned section_line
,
351 _cleanup_free_ ArpIpTarget
*buffer
= NULL
;
352 _cleanup_free_
char *n
= NULL
;
355 r
= extract_first_word(&rvalue
, &n
, NULL
, 0);
357 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue
);
364 buffer
= new0(ArpIpTarget
, 1);
368 r
= in_addr_from_string_auto(n
, &f
, &buffer
->ip
);
370 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
375 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
379 LIST_PREPEND(arp_ip_target
, b
->arp_ip_targets
, buffer
);
380 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 static void bond_done(NetDev
*netdev
) {
394 ArpIpTarget
*t
= NULL
, *n
= NULL
;
403 LIST_FOREACH_SAFE(arp_ip_target
, t
, n
, b
->arp_ip_targets
)
406 b
->arp_ip_targets
= NULL
;
409 static void bond_init(NetDev
*netdev
) {
418 b
->mode
= _NETDEV_BOND_MODE_INVALID
;
419 b
->xmit_hash_policy
= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
;
420 b
->lacp_rate
= _NETDEV_BOND_LACP_RATE_INVALID
;
421 b
->ad_select
= _NETDEV_BOND_AD_SELECT_INVALID
;
422 b
->fail_over_mac
= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
;
423 b
->arp_validate
= _NETDEV_BOND_ARP_VALIDATE_INVALID
;
424 b
->arp_all_targets
= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
;
425 b
->primary_reselect
= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
;
427 b
->all_slaves_active
= false;
429 b
->resend_igmp
= RESEND_IGMP_DEFAULT
;
430 b
->packets_per_slave
= PACKETS_PER_SLAVE_DEFAULT
;
431 b
->num_grat_arp
= GRATUITOUS_ARP_DEFAULT
;
432 b
->lp_interval
= LEARNING_PACKETS_INTERVAL_MIN_SEC
;
434 LIST_HEAD_INIT(b
->arp_ip_targets
);
435 b
->n_arp_ip_targets
= 0;
438 const NetDevVTable bond_vtable
= {
439 .object_size
= sizeof(Bond
),
442 .sections
= "Match\0NetDev\0Bond\0",
443 .fill_message_create
= netdev_bond_fill_message_create
,
444 .create_type
= NETDEV_CREATE_MASTER
,