2 This file is part of systemd.
4 Copyright 2014 Tom Gundersen <teg@jklm.no>
5 Copyright 2014 Susant Sahani
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/ether.h>
22 #include <linux/if_bonding.h>
24 #include "sd-netlink.h"
26 #include "alloc-util.h"
27 #include "conf-parser.h"
28 #include "extract-word.h"
30 #include "networkd-netdev-bond.h"
31 #include "string-table.h"
32 #include "string-util.h"
35 * Number of seconds between instances where the bonding
36 * driver sends learning packets to each slaves peer switch
38 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
39 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
41 /* Number of IGMP membership reports to be issued after
44 #define RESEND_IGMP_MIN 0
45 #define RESEND_IGMP_MAX 255
46 #define RESEND_IGMP_DEFAULT 1
49 * Number of packets to transmit through a slave before
50 * moving to the next one.
52 #define PACKETS_PER_SLAVE_MIN 0
53 #define PACKETS_PER_SLAVE_MAX 65535
54 #define PACKETS_PER_SLAVE_DEFAULT 1
57 * Number of peer notifications (gratuitous ARPs and
58 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
61 #define GRATUITOUS_ARP_MIN 0
62 #define GRATUITOUS_ARP_MAX 255
63 #define GRATUITOUS_ARP_DEFAULT 1
65 static const char* const bond_mode_table
[_NETDEV_BOND_MODE_MAX
] = {
66 [NETDEV_BOND_MODE_BALANCE_RR
] = "balance-rr",
67 [NETDEV_BOND_MODE_ACTIVE_BACKUP
] = "active-backup",
68 [NETDEV_BOND_MODE_BALANCE_XOR
] = "balance-xor",
69 [NETDEV_BOND_MODE_BROADCAST
] = "broadcast",
70 [NETDEV_BOND_MODE_802_3AD
] = "802.3ad",
71 [NETDEV_BOND_MODE_BALANCE_TLB
] = "balance-tlb",
72 [NETDEV_BOND_MODE_BALANCE_ALB
] = "balance-alb",
75 DEFINE_STRING_TABLE_LOOKUP(bond_mode
, BondMode
);
76 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode
, bond_mode
, BondMode
, "Failed to parse bond mode");
78 static const char* const bond_xmit_hash_policy_table
[_NETDEV_BOND_XMIT_HASH_POLICY_MAX
] = {
79 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
] = "layer2",
80 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
] = "layer3+4",
81 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
] = "layer2+3",
82 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
] = "encap2+3",
83 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
] = "encap3+4",
86 DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy
, BondXmitHashPolicy
);
87 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy
,
88 bond_xmit_hash_policy
,
90 "Failed to parse bond transmit hash policy")
92 static const char* const bond_lacp_rate_table
[_NETDEV_BOND_LACP_RATE_MAX
] = {
93 [NETDEV_BOND_LACP_RATE_SLOW
] = "slow",
94 [NETDEV_BOND_LACP_RATE_FAST
] = "fast",
97 DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate
, BondLacpRate
);
98 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate
, bond_lacp_rate
, BondLacpRate
, "Failed to parse bond lacp rate")
100 static const char* const bond_ad_select_table
[_NETDEV_BOND_AD_SELECT_MAX
] = {
101 [NETDEV_BOND_AD_SELECT_STABLE
] = "stable",
102 [NETDEV_BOND_AD_SELECT_BANDWIDTH
] = "bandwidth",
103 [NETDEV_BOND_AD_SELECT_COUNT
] = "count",
106 DEFINE_STRING_TABLE_LOOKUP(bond_ad_select
, BondAdSelect
);
107 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select
, bond_ad_select
, BondAdSelect
, "Failed to parse bond AD select");
109 static const char* const bond_fail_over_mac_table
[_NETDEV_BOND_FAIL_OVER_MAC_MAX
] = {
110 [NETDEV_BOND_FAIL_OVER_MAC_NONE
] = "none",
111 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE
] = "active",
112 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW
] = "follow",
115 DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac
, BondFailOverMac
);
116 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac
, bond_fail_over_mac
, BondFailOverMac
, "Failed to parse bond fail over MAC");
118 static const char *const bond_arp_validate_table
[_NETDEV_BOND_ARP_VALIDATE_MAX
] = {
119 [NETDEV_BOND_ARP_VALIDATE_NONE
] = "none",
120 [NETDEV_BOND_ARP_VALIDATE_ACTIVE
]= "active",
121 [NETDEV_BOND_ARP_VALIDATE_BACKUP
]= "backup",
122 [NETDEV_BOND_ARP_VALIDATE_ALL
]= "all",
125 DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate
, BondArpValidate
);
126 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate
, bond_arp_validate
, BondArpValidate
, "Failed to parse bond arp validate");
128 static const char *const bond_arp_all_targets_table
[_NETDEV_BOND_ARP_ALL_TARGETS_MAX
] = {
129 [NETDEV_BOND_ARP_ALL_TARGETS_ANY
] = "any",
130 [NETDEV_BOND_ARP_ALL_TARGETS_ALL
] = "all",
133 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets
, BondArpAllTargets
);
134 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets
, bond_arp_all_targets
, BondArpAllTargets
, "Failed to parse bond Arp all targets");
136 static const char *bond_primary_reselect_table
[_NETDEV_BOND_PRIMARY_RESELECT_MAX
] = {
137 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS
] = "always",
138 [NETDEV_BOND_PRIMARY_RESELECT_BETTER
]= "better",
139 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE
]= "failure",
142 DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect
, BondPrimaryReselect
);
143 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect
, bond_primary_reselect
, BondPrimaryReselect
, "Failed to parse bond primary reselect");
145 static uint8_t bond_mode_to_kernel(BondMode mode
) {
147 case NETDEV_BOND_MODE_BALANCE_RR
:
148 return BOND_MODE_ROUNDROBIN
;
149 case NETDEV_BOND_MODE_ACTIVE_BACKUP
:
150 return BOND_MODE_ACTIVEBACKUP
;
151 case NETDEV_BOND_MODE_BALANCE_XOR
:
152 return BOND_MODE_XOR
;
153 case NETDEV_BOND_MODE_BROADCAST
:
154 return BOND_MODE_BROADCAST
;
155 case NETDEV_BOND_MODE_802_3AD
:
156 return BOND_MODE_8023AD
;
157 case NETDEV_BOND_MODE_BALANCE_TLB
:
158 return BOND_MODE_TLB
;
159 case NETDEV_BOND_MODE_BALANCE_ALB
:
160 return BOND_MODE_ALB
;
166 static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy
) {
168 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2
:
169 return BOND_XMIT_POLICY_LAYER2
;
170 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34
:
171 return BOND_XMIT_POLICY_LAYER34
;
172 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23
:
173 return BOND_XMIT_POLICY_LAYER23
;
174 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23
:
175 return BOND_XMIT_POLICY_ENCAP23
;
176 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34
:
177 return BOND_XMIT_POLICY_ENCAP34
;
183 static int netdev_bond_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
185 ArpIpTarget
*target
= NULL
;
196 if (b
->mode
!= _NETDEV_BOND_MODE_INVALID
) {
197 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_MODE
,
198 bond_mode_to_kernel(b
->mode
));
200 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MODE attribute: %m");
203 if (b
->xmit_hash_policy
!= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
) {
204 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_XMIT_HASH_POLICY
,
205 bond_xmit_hash_policy_to_kernel(b
->xmit_hash_policy
));
207 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
210 if (b
->lacp_rate
!= _NETDEV_BOND_LACP_RATE_INVALID
&&
211 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
212 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_LACP_RATE
, b
->lacp_rate
);
214 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
217 if (b
->miimon
!= 0) {
218 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIIMON
, b
->miimon
/ USEC_PER_MSEC
);
220 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
223 if (b
->downdelay
!= 0) {
224 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_DOWNDELAY
, b
->downdelay
/ USEC_PER_MSEC
);
226 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
229 if (b
->updelay
!= 0) {
230 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_UPDELAY
, b
->updelay
/ USEC_PER_MSEC
);
232 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_UPDELAY attribute: %m");
235 if (b
->arp_interval
!= 0) {
236 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_INTERVAL
, b
->arp_interval
/ USEC_PER_MSEC
);
238 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
240 if ((b
->lp_interval
>= LEARNING_PACKETS_INTERVAL_MIN_SEC
) &&
241 (b
->lp_interval
<= LEARNING_PACKETS_INTERVAL_MAX_SEC
)) {
242 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_LP_INTERVAL
, b
->lp_interval
/ USEC_PER_SEC
);
244 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
248 if (b
->ad_select
!= _NETDEV_BOND_AD_SELECT_INVALID
&&
249 b
->mode
== NETDEV_BOND_MODE_802_3AD
) {
250 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_AD_SELECT
, b
->ad_select
);
252 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
255 if (b
->fail_over_mac
!= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
&&
256 b
->mode
== NETDEV_BOND_MODE_ACTIVE_BACKUP
) {
257 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_FAIL_OVER_MAC
, b
->fail_over_mac
);
259 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
262 if (b
->arp_validate
!= _NETDEV_BOND_ARP_VALIDATE_INVALID
) {
263 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_VALIDATE
, b
->arp_validate
);
265 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
268 if (b
->arp_all_targets
!= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
) {
269 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_ARP_ALL_TARGETS
, b
->arp_all_targets
);
271 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
274 if (b
->primary_reselect
!= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
) {
275 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_PRIMARY_RESELECT
, b
->primary_reselect
);
277 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PRIMARY_RESELECT attribute: %m");
280 if (b
->resend_igmp
<= RESEND_IGMP_MAX
) {
281 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_RESEND_IGMP
, b
->resend_igmp
);
283 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
286 if (b
->packets_per_slave
<= PACKETS_PER_SLAVE_MAX
&&
287 b
->mode
== NETDEV_BOND_MODE_BALANCE_RR
) {
288 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_PACKETS_PER_SLAVE
, b
->packets_per_slave
);
290 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
293 if (b
->num_grat_arp
<= GRATUITOUS_ARP_MAX
) {
294 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_NUM_PEER_NOTIF
, b
->num_grat_arp
);
296 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
299 if (b
->min_links
!= 0) {
300 r
= sd_netlink_message_append_u32(m
, IFLA_BOND_MIN_LINKS
, b
->min_links
);
302 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
305 r
= sd_netlink_message_append_u8(m
, IFLA_BOND_ALL_SLAVES_ACTIVE
, b
->all_slaves_active
);
307 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
309 if (b
->arp_interval
> 0) {
310 if (b
->n_arp_ip_targets
> 0) {
312 r
= sd_netlink_message_open_container(m
, IFLA_BOND_ARP_IP_TARGET
);
314 return log_netdev_error_errno(netdev
, r
, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
316 LIST_FOREACH(arp_ip_target
, target
, b
->arp_ip_targets
) {
317 r
= sd_netlink_message_append_u32(m
, i
++, target
->ip
.in
.s_addr
);
319 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
322 r
= sd_netlink_message_close_container(m
);
324 return log_netdev_error_errno(netdev
, r
, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
331 int config_parse_arp_ip_target_address(const char *unit
,
332 const char *filename
,
335 unsigned section_line
,
350 _cleanup_free_ ArpIpTarget
*buffer
= NULL
;
351 _cleanup_free_
char *n
= NULL
;
354 r
= extract_first_word(&rvalue
, &n
, NULL
, 0);
356 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue
);
363 buffer
= new0(ArpIpTarget
, 1);
367 r
= in_addr_from_string_auto(n
, &f
, &buffer
->ip
);
369 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
374 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n
);
378 LIST_PREPEND(arp_ip_target
, b
->arp_ip_targets
, buffer
);
379 b
->n_arp_ip_targets
++;
384 if (b
->n_arp_ip_targets
> NETDEV_BOND_ARP_TARGETS_MAX
)
385 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
386 "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
387 b
->n_arp_ip_targets
, NETDEV_BOND_ARP_TARGETS_MAX
);
392 static void bond_done(NetDev
*netdev
) {
393 ArpIpTarget
*t
= NULL
, *n
= NULL
;
402 LIST_FOREACH_SAFE(arp_ip_target
, t
, n
, b
->arp_ip_targets
)
405 b
->arp_ip_targets
= NULL
;
408 static void bond_init(NetDev
*netdev
) {
417 b
->mode
= _NETDEV_BOND_MODE_INVALID
;
418 b
->xmit_hash_policy
= _NETDEV_BOND_XMIT_HASH_POLICY_INVALID
;
419 b
->lacp_rate
= _NETDEV_BOND_LACP_RATE_INVALID
;
420 b
->ad_select
= _NETDEV_BOND_AD_SELECT_INVALID
;
421 b
->fail_over_mac
= _NETDEV_BOND_FAIL_OVER_MAC_INVALID
;
422 b
->arp_validate
= _NETDEV_BOND_ARP_VALIDATE_INVALID
;
423 b
->arp_all_targets
= _NETDEV_BOND_ARP_ALL_TARGETS_INVALID
;
424 b
->primary_reselect
= _NETDEV_BOND_PRIMARY_RESELECT_INVALID
;
426 b
->all_slaves_active
= false;
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
;
433 LIST_HEAD_INIT(b
->arp_ip_targets
);
434 b
->n_arp_ip_targets
= 0;
437 const NetDevVTable bond_vtable
= {
438 .object_size
= sizeof(Bond
),
441 .sections
= "Match\0NetDev\0Bond\0",
442 .fill_message_create
= netdev_bond_fill_message_create
,
443 .create_type
= NETDEV_CREATE_MASTER
,