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 "conf-parser.h"
27 #include "sd-netlink.h"
28 #include "networkd-netdev-bond.h"
32 * Number of seconds between instances where the bonding
33 * driver sends learning packets to each slaves peer switch
35 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
36 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
38 /* Number of IGMP membership reports to be issued after
41 #define RESEND_IGMP_MIN 0
42 #define RESEND_IGMP_MAX 255
43 #define RESEND_IGMP_DEFAULT 1
46 * Number of packets to transmit through a slave before
47 * moving to the next one.
49 #define PACKETS_PER_SLAVE_MIN 0
50 #define PACKETS_PER_SLAVE_MAX 65535
51 #define PACKETS_PER_SLAVE_DEFAULT 1
54 * Number of peer notifications (gratuitous ARPs and
55 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
58 #define GRATUITOUS_ARP_MIN 0
59 #define GRATUITOUS_ARP_MAX 255
60 #define GRATUITOUS_ARP_DEFAULT 1
62 static const char* const bond_mode_table
[_NETDEV_BOND_MODE_MAX
] = {
63 [NETDEV_BOND_MODE_BALANCE_RR
] = "balance-rr",
64 [NETDEV_BOND_MODE_ACTIVE_BACKUP
] = "active-backup",
65 [NETDEV_BOND_MODE_BALANCE_XOR
] = "balance-xor",
66 [NETDEV_BOND_MODE_BROADCAST
] = "broadcast",
67 [NETDEV_BOND_MODE_802_3AD
] = "802.3ad",
68 [NETDEV_BOND_MODE_BALANCE_TLB
] = "balance-tlb",
69 [NETDEV_BOND_MODE_BALANCE_ALB
] = "balance-alb",
72 DEFINE_STRING_TABLE_LOOKUP(bond_mode
, BondMode
);
73 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
, "Failed to parse bond mode");
75 static const char* const bond_xmit_hash_policy_table
[_NETDEV_BOND_XMIT_HASH_POLICY_MAX
] = {
76 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
] = "layer2",
77 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
] = "layer3+4",
78 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
] = "layer2+3",
79 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
] = "encap2+3",
80 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
] = "encap3+4",
83 DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy
, BondXmitHashPolicy
);
84 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
85 bond_xmit_hash_policy
,
87 "Failed to parse bond transmit hash policy")
89 static const char* const bond_lacp_rate_table
[_NETDEV_BOND_LACP_RATE_MAX
] = {
90 [NETDEV_BOND_LACP_RATE_SLOW
] = "slow",
91 [NETDEV_BOND_LACP_RATE_FAST
] = "fast",
94 DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate
, BondLacpRate
);
95 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
, "Failed to parse bond lacp rate")
97 static const char* const bond_ad_select_table
[_NETDEV_BOND_AD_SELECT_MAX
] = {
98 [NETDEV_BOND_AD_SELECT_STABLE
] = "stable",
99 [NETDEV_BOND_AD_SELECT_BANDWIDTH
] = "bandwidth",
100 [NETDEV_BOND_AD_SELECT_COUNT
] = "count",
103 DEFINE_STRING_TABLE_LOOKUP(bond_ad_select
, BondAdSelect
);
104 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
, "Failed to parse bond AD select");
106 static const char* const bond_fail_over_mac_table
[_NETDEV_BOND_FAIL_OVER_MAC_MAX
] = {
107 [NETDEV_BOND_FAIL_OVER_MAC_NONE
] = "none",
108 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE
] = "active",
109 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW
] = "follow",
112 DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac
, BondFailOverMac
);
113 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
, "Failed to parse bond fail over MAC");
115 static const char *const bond_arp_validate_table
[_NETDEV_BOND_ARP_VALIDATE_MAX
] = {
116 [NETDEV_BOND_ARP_VALIDATE_NONE
] = "none",
117 [NETDEV_BOND_ARP_VALIDATE_ACTIVE
]= "active",
118 [NETDEV_BOND_ARP_VALIDATE_BACKUP
]= "backup",
119 [NETDEV_BOND_ARP_VALIDATE_ALL
]= "all",
122 DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate
, BondArpValidate
);
123 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
, "Failed to parse bond arp validate");
125 static const char *const bond_arp_all_targets_table
[_NETDEV_BOND_ARP_ALL_TARGETS_MAX
] = {
126 [NETDEV_BOND_ARP_ALL_TARGETS_ANY
] = "any",
127 [NETDEV_BOND_ARP_ALL_TARGETS_ALL
] = "all",
130 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets
, BondArpAllTargets
);
131 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
, "Failed to parse bond Arp all targets");
133 static const char *bond_primary_reselect_table
[_NETDEV_BOND_PRIMARY_RESELECT_MAX
] = {
134 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS
] = "always",
135 [NETDEV_BOND_PRIMARY_RESELECT_BETTER
]= "better",
136 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE
]= "failure",
139 DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect
, BondPrimaryReselect
);
140 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
, "Failed to parse bond primary reselect");
142 static uint8_t bond_mode_to_kernel(BondMode mode
) {
144 case NETDEV_BOND_MODE_BALANCE_RR
:
145 return BOND_MODE_ROUNDROBIN
;
146 case NETDEV_BOND_MODE_ACTIVE_BACKUP
:
147 return BOND_MODE_ACTIVEBACKUP
;
148 case NETDEV_BOND_MODE_BALANCE_XOR
:
149 return BOND_MODE_XOR
;
150 case NETDEV_BOND_MODE_BROADCAST
:
151 return BOND_MODE_BROADCAST
;
152 case NETDEV_BOND_MODE_802_3AD
:
153 return BOND_MODE_8023AD
;
154 case NETDEV_BOND_MODE_BALANCE_TLB
:
155 return BOND_MODE_TLB
;
156 case NETDEV_BOND_MODE_BALANCE_ALB
:
157 return BOND_MODE_ALB
;
163 static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy
) {
165 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
:
166 return BOND_XMIT_POLICY_LAYER2
;
167 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
:
168 return BOND_XMIT_POLICY_LAYER34
;
169 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
:
170 return BOND_XMIT_POLICY_LAYER23
;
171 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
:
172 return BOND_XMIT_POLICY_ENCAP23
;
173 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
:
174 return BOND_XMIT_POLICY_ENCAP34
;
180 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
181 Bond
*b
= BOND(netdev
);
182 ArpIpTarget
*target
= NULL
;
190 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
) {
191 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
,
192 bond_mode_to_kernel(b
->mode
));
194 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MODE attribute: %m");
197 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
198 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
,
199 bond_xmit_hash_policy_to_kernel(b
->xmit_hash_policy
));
201 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
204 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
205 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
206 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
208 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
211 if (b
->miimon
!= 0) {
212 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
214 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
217 if (b
->downdelay
!= 0) {
218 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
220 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
223 if (b
->updelay
!= 0) {
224 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
226 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_UPDELAY attribute: %m");
229 if (b
->arp_interval
!= 0) {
230 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
232 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
234 if ((b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
) &&
235 (b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
)) {
236 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
238 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
242 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
243 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
244 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
246 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
249 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
250 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
) {
251 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
253 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
256 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
257 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
259 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
262 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
263 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
265 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
268 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
269 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->primary_reselect
);
271 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
274 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
275 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
277 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
280 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
281 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
282 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
284 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
287 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
288 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
290 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
293 if (b
->min_links
!= 0) {
294 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
296 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
299 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
301 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
303 if (b
->arp_interval
> 0) {
304 if (b
->n_arp_ip_targets
> 0) {
306 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
308 return log_netdev_error_errno(netdev
, r
, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
310 LIST_FOREACH(arp_ip_target
, target
, b
->arp_ip_targets
) {
311 r
= sd_netlink_message_append_u32(m
, i
++, target
->ip
.in
.s_addr
);
313 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
316 r
= sd_netlink_message_close_container(m
);
318 return log_netdev_error_errno(netdev
, r
, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
325 int config_parse_arp_ip_target_address(const char *unit
,
326 const char *filename
,
329 unsigned section_line
,
336 const char *word
, *state
;
345 FOREACH_WORD_QUOTED(word
, l
, rvalue
, state
) {
346 _cleanup_free_ ArpIpTarget
*buffer
= NULL
;
347 _cleanup_free_
char *n
= NULL
;
350 n
= strndup(word
, l
);
354 buffer
= new0(ArpIpTarget
, 1);
358 r
= in_addr_from_string_auto(n
, &f
, &buffer
->ip
);
360 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
365 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
369 LIST_PREPEND(arp_ip_target
, b
->arp_ip_targets
, buffer
);
370 b
->n_arp_ip_targets
++;
375 if (b
->n_arp_ip_targets
> NETDEV_BOND_ARP_TARGETS_MAX
)
376 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b
->n_arp_ip_targets
, NETDEV_BOND_ARP_TARGETS_MAX
);
381 static void bond_done(NetDev
*netdev
) {
382 ArpIpTarget
*t
= NULL
, *n
= NULL
;
383 Bond
*b
= BOND(netdev
);
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
) {
395 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;
411 b
->resend_igmp
= RESEND_IGMP_DEFAULT
;
412 b
->packets_per_slave
= PACKETS_PER_SLAVE_DEFAULT
;
413 b
->num_grat_arp
= GRATUITOUS_ARP_DEFAULT
;
414 b
->lp_interval
= LEARNING_PACKETS_INTERVAL_MIN_SEC
;
416 LIST_HEAD_INIT(b
->arp_ip_targets
);
417 b
->n_arp_ip_targets
= 0;
420 const NetDevVTable bond_vtable
= {
421 .object_size
= sizeof(Bond
),
424 .sections
= "Match\0NetDev\0Bond\0",
425 .fill_message_create
= netdev_bond_fill_message_create
,
426 .create_type
= NETDEV_CREATE_MASTER
,