]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-netdev-bond.c
logind,sd-event: drop spurious new-lines
[thirdparty/systemd.git] / src / network / networkd-netdev-bond.c
CommitLineData
fe8ac65b
SS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 Copyright 2014 Susant Sahani
8
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.
13
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.
18
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/>.
21***/
22
23#include <netinet/ether.h>
b621239e 24#include <linux/if_bonding.h>
fe8ac65b
SS
25
26#include "conf-parser.h"
27#include "sd-rtnl.h"
81bd37a8 28#include "rtnl-types.h"
3be1d7e0 29#include "networkd-netdev-bond.h"
fe8ac65b
SS
30#include "missing.h"
31
81bd37a8
SS
32/*
33 * Number of seconds between instances where the bonding
34 * driver sends learning packets to each slaves peer switch
35 */
36#define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
37#define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
38
39/* Number of IGMP membership reports to be issued after
40 * a failover event.
41 */
42#define RESEND_IGMP_MIN 0
43#define RESEND_IGMP_MAX 255
44#define RESEND_IGMP_DEFAULT 1
45
46/*
47 * Number of packets to transmit through a slave before
48 * moving to the next one.
49 */
50#define PACKETS_PER_SLAVE_MIN 0
51#define PACKETS_PER_SLAVE_MAX 65535
52#define PACKETS_PER_SLAVE_DEFAULT 1
53
54/*
55 * Number of peer notifications (gratuitous ARPs and
56 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
57 * failover event.
58 */
59#define GRATUITOUS_ARP_MIN 0
60#define GRATUITOUS_ARP_MAX 255
61#define GRATUITOUS_ARP_DEFAULT 1
62
fe8ac65b
SS
63static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
64 [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
65 [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
66 [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
67 [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
68 [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
69 [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
70 [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
71};
72
73DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
74DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
75
227cdf2c
SS
76static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
77 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
78 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
79 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
80 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
81 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
82};
83
84DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
85DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
86 bond_xmit_hash_policy,
87 BondXmitHashPolicy,
88 "Failed to parse bond transmit hash policy")
89
fb1021a2
SS
90static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
91 [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
92 [NETDEV_BOND_LACP_RATE_FAST] = "fast",
93};
94
95DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
96DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
97
81bd37a8
SS
98static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
99 [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
100 [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
101 [NETDEV_BOND_AD_SELECT_COUNT] = "count",
102};
103
104DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
105DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
106
107static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
108 [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
109 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
110 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
111};
112
113DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
114DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
115
116static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
117 [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
118 [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
119 [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
120 [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
121};
122
123DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
124DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
125
126static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
127 [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
128 [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
129};
130
131DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
132DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
133
134static const char *bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
135 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
136 [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
137 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
138};
139
140DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
141DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
142
b621239e
TG
143static uint8_t bond_mode_to_kernel(BondMode mode) {
144 switch (mode) {
145 case NETDEV_BOND_MODE_BALANCE_RR:
146 return BOND_MODE_ROUNDROBIN;
147 case NETDEV_BOND_MODE_ACTIVE_BACKUP:
148 return BOND_MODE_ACTIVEBACKUP;
149 case NETDEV_BOND_MODE_BALANCE_XOR:
150 return BOND_MODE_XOR;
151 case NETDEV_BOND_MODE_BROADCAST:
152 return BOND_MODE_BROADCAST;
153 case NETDEV_BOND_MODE_802_3AD:
154 return BOND_MODE_8023AD;
155 case NETDEV_BOND_MODE_BALANCE_TLB:
156 return BOND_MODE_TLB;
157 case NETDEV_BOND_MODE_BALANCE_ALB:
158 return BOND_MODE_ALB;
159 default:
160 return (uint8_t) -1;
161 }
162}
163
227cdf2c
SS
164static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
165 switch (policy) {
166 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2:
167 return BOND_XMIT_POLICY_LAYER2;
168 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34:
169 return BOND_XMIT_POLICY_LAYER34;
170 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23:
171 return BOND_XMIT_POLICY_LAYER23;
172 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23:
173 return BOND_XMIT_POLICY_ENCAP23;
174 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34:
175 return BOND_XMIT_POLICY_ENCAP34;
176 default:
177 return (uint8_t) -1;
178 }
179}
180
aa9f1140
TG
181static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
182 Bond *b = BOND(netdev);
81bd37a8
SS
183 ArpIpTarget *target = NULL;
184 int r, i = 0;
fe8ac65b 185
aa9f1140
TG
186 assert(netdev);
187 assert(!link);
188 assert(b);
fe8ac65b
SS
189 assert(m);
190
aa9f1140 191 if (b->mode != _NETDEV_BOND_MODE_INVALID) {
b621239e 192 r = sd_rtnl_message_append_u8(m, IFLA_BOND_MODE,
aa9f1140 193 bond_mode_to_kernel(b->mode));
fe8ac65b 194 if (r < 0) {
79008bdd 195 log_netdev_error(netdev,
fe8ac65b
SS
196 "Could not append IFLA_BOND_MODE attribute: %s",
197 strerror(-r));
198 return r;
199 }
200 }
201
227cdf2c
SS
202 if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
203 r = sd_rtnl_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
204 bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
205 if (r < 0) {
79008bdd 206 log_netdev_error(netdev,
227cdf2c
SS
207 "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %s",
208 strerror(-r));
209 return r;
210 }
211 }
212
fb1021a2
SS
213 if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
214 b->mode == NETDEV_BOND_MODE_802_3AD) {
215 r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
216 if (r < 0) {
79008bdd 217 log_netdev_error(netdev,
fb1021a2
SS
218 "Could not append IFLA_BOND_AD_LACP_RATE attribute: %s",
219 strerror(-r));
220 return r;
221 }
222 }
223
d9c52fa0 224 if (b->miimon != 0) {
c9e738b9 225 r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
d9c52fa0 226 if (r < 0) {
79008bdd 227 log_netdev_error(netdev,
d9c52fa0
SS
228 "Could not append IFLA_BOND_BOND_MIIMON attribute: %s",
229 strerror(-r));
230 return r;
231 }
232 }
233
234 if (b->downdelay != 0) {
c9e738b9 235 r = sd_rtnl_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
d9c52fa0 236 if (r < 0) {
79008bdd 237 log_netdev_error(netdev,
d9c52fa0
SS
238 "Could not append IFLA_BOND_DOWNDELAY attribute: %s",
239 strerror(-r));
240 return r;
241 }
242 }
243
244 if (b->updelay != 0) {
c9e738b9 245 r = sd_rtnl_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
d9c52fa0 246 if (r < 0) {
79008bdd 247 log_netdev_error(netdev,
d9c52fa0
SS
248 "Could not append IFLA_BOND_UPDELAY attribute: %s",
249 strerror(-r));
250 return r;
251 }
252 }
253
81bd37a8
SS
254 if (b->arp_interval != 0) {
255 r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
256 if (r < 0) {
257 log_netdev_error(netdev,
258 "Could not append IFLA_BOND_ARP_INTERVAL attribute: %s",
259 strerror(-r));
260 return r;
261 }
262 }
263
264 if ((b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC) &&
265 (b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC)) {
266 r = sd_rtnl_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
267 if (r < 0) {
268 log_netdev_error(netdev,
269 "Could not append IFLA_BOND_LP_INTERVAL attribute: %s",
270 strerror(-r));
271 return r;
272 }
273 }
274
275 if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
276 b->mode == BOND_MODE_8023AD) {
277 r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
278 if (r < 0) {
279 log_netdev_error(netdev,
280 "Could not append IFLA_BOND_AD_SELECT attribute: %s",
281 strerror(-r));
282 return r;
283 }
284 }
285
286 if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
287 b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) {
288 r = sd_rtnl_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
289 if (r < 0) {
290 log_netdev_error(netdev,
291 "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %s",
292 strerror(-r));
293 return r;
294 }
295 }
296
297 if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
298 r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
299 if (r < 0) {
300 log_netdev_error(netdev,
301 "Could not append IFLA_BOND_ARP_VALIDATE attribute: %s",
302 strerror(-r));
303 return r;
304 }
305 }
306
307 if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
308 r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
309 if (r < 0) {
310 log_netdev_error(netdev,
311 "Could not append IFLA_BOND_ARP_VALIDATE attribute: %s",
312 strerror(-r));
313 return r;
314 }
315 }
316
317 if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
318 r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect);
319 if (r < 0) {
320 log_netdev_error(netdev,
321 "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %s",
322 strerror(-r));
323 return r;
324 }
325 }
326
327 if (b->resend_igmp <= RESEND_IGMP_MAX) {
328 r = sd_rtnl_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
329 if (r < 0) {
330 log_netdev_error(netdev,
331 "Could not append IFLA_BOND_RESEND_IGMP attribute: %s",
332 strerror(-r));
333 return r;
334 }
335 }
336
337 if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX) {
338 r = sd_rtnl_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
339 if (r < 0) {
340 log_netdev_error(netdev,
341 "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %s",
342 strerror(-r));
343 return r;
344 }
345 }
346
347 if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
348 r = sd_rtnl_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
349 if (r < 0) {
350 log_netdev_error(netdev,
351 "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %s",
352 strerror(-r));
353 return r;
354 }
355 }
356
357 if (b->min_links != 0) {
358 r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
359 if (r < 0) {
360 log_netdev_error(netdev,
361 "Could not append IFLA_BOND_MIN_LINKS attribute: %s",
362 strerror(-r));
363 return r;
364 }
365 }
366
367 r = sd_rtnl_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
368 if (r < 0) {
369 log_netdev_error(netdev,
370 "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %s",
371 strerror(-r));
372 return r;
373 }
374
375 if (b->arp_interval > 0) {
376 if (b->n_arp_ip_targets > 0) {
377
378 r = sd_rtnl_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
379 if (r < 0) {
380 log_netdev_error(netdev,
381 "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %s",
382 strerror(-r));
383 return r;
384 }
385
386 LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
387 r = sd_rtnl_message_append_u32(m, i++, target->ip.in.s_addr);
388 if (r < 0) {
389 log_netdev_error(netdev,
390 "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %s",
391 strerror(-r));
392 return r;
393 }
394 }
395
396 r = sd_rtnl_message_close_container(m);
397 if (r < 0) {
398 log_netdev_error(netdev,
399 "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %s",
400 strerror(-r));
401 return r;
402 }
403 }
404 }
405
aa9f1140
TG
406 return 0;
407}
fe8ac65b 408
81bd37a8
SS
409int config_parse_arp_ip_target_address(const char *unit,
410 const char *filename,
411 unsigned line,
412 const char *section,
413 unsigned section_line,
414 const char *lvalue,
415 int ltype,
416 const char *rvalue,
417 void *data,
418 void *userdata) {
419 Bond *b = userdata;
420 const char *word, *state;
421 size_t l;
422 int r;
423
424 assert(filename);
425 assert(lvalue);
426 assert(rvalue);
427 assert(data);
428
429 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
430 _cleanup_free_ ArpIpTarget *buffer = NULL;
431 _cleanup_free_ char *n = NULL;
432 int f;
433
434 n = strndup(word, l);
435 if (!n)
436 return -ENOMEM;
437
438 buffer = new0(ArpIpTarget, 1);
439 if (!buffer)
440 return -ENOMEM;
441
442 r = in_addr_from_string_auto(n, &f, &buffer->ip);
443 if (r < 0) {
444 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
445 return 0;
446 }
447
448 if (f != AF_INET) {
449 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
450 return 0;
451 }
452
453 LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
454 b->n_arp_ip_targets ++;
455
456 buffer = NULL;
457
458 if (b->n_arp_ip_targets > BOND_ARP_TARGETS_MAX)
459 break;
460 }
461
462 return 0;
463}
464
465static void bond_done(NetDev *netdev) {
466 ArpIpTarget *t = NULL, *n = NULL;
467 Bond *b = BOND(netdev);
468
469 assert(netdev);
470 assert(b);
471
472 LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
473 free(t);
474
475 b->arp_ip_targets = NULL;
476}
477
aa9f1140
TG
478static void bond_init(NetDev *netdev) {
479 Bond *b = BOND(netdev);
480
481 assert(netdev);
482 assert(b);
fe8ac65b 483
aa9f1140 484 b->mode = _NETDEV_BOND_MODE_INVALID;
227cdf2c 485 b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
fb1021a2 486 b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
81bd37a8
SS
487 b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID;
488 b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID;
489 b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID;
490 b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID;
491 b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
492
493 b->all_slaves_active = false;
494
495 b->resend_igmp = RESEND_IGMP_DEFAULT;
496 b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
497 b->num_grat_arp = GRATUITOUS_ARP_DEFAULT;
498 b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC;
499
500 LIST_HEAD_INIT(b->arp_ip_targets);
501 b->n_arp_ip_targets = 0;
fe8ac65b
SS
502}
503
3be1d7e0 504const NetDevVTable bond_vtable = {
aa9f1140
TG
505 .object_size = sizeof(Bond),
506 .init = bond_init,
81bd37a8 507 .done = bond_done,
aa9f1140 508 .sections = "Match\0NetDev\0Bond\0",
3be1d7e0 509 .fill_message_create = netdev_bond_fill_message_create,
aa9f1140 510 .create_type = NETDEV_CREATE_MASTER,
3be1d7e0 511};