]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev-bond.c
Merge pull request #3156 from keszybz/duid-settings
[thirdparty/systemd.git] / src / network / networkd-netdev-bond.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Tom Gundersen <teg@jklm.no>
5 Copyright 2014 Susant Sahani
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <netinet/ether.h>
22 #include <linux/if_bonding.h>
23
24 #include "sd-netlink.h"
25
26 #include "alloc-util.h"
27 #include "conf-parser.h"
28 #include "extract-word.h"
29 #include "missing.h"
30 #include "networkd-netdev-bond.h"
31 #include "string-table.h"
32 #include "string-util.h"
33
34 /*
35 * Number of seconds between instances where the bonding
36 * driver sends learning packets to each slaves peer switch
37 */
38 #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
39 #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
40
41 /* Number of IGMP membership reports to be issued after
42 * a failover event.
43 */
44 #define RESEND_IGMP_MIN 0
45 #define RESEND_IGMP_MAX 255
46 #define RESEND_IGMP_DEFAULT 1
47
48 /*
49 * Number of packets to transmit through a slave before
50 * moving to the next one.
51 */
52 #define PACKETS_PER_SLAVE_MIN 0
53 #define PACKETS_PER_SLAVE_MAX 65535
54 #define PACKETS_PER_SLAVE_DEFAULT 1
55
56 /*
57 * Number of peer notifications (gratuitous ARPs and
58 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
59 * failover event.
60 */
61 #define GRATUITOUS_ARP_MIN 0
62 #define GRATUITOUS_ARP_MAX 255
63 #define GRATUITOUS_ARP_DEFAULT 1
64
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",
73 };
74
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");
77
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",
84 };
85
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,
89 BondXmitHashPolicy,
90 "Failed to parse bond transmit hash policy")
91
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",
95 };
96
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")
99
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",
104 };
105
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");
108
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",
113 };
114
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");
117
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",
123 };
124
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");
127
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",
131 };
132
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");
135
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",
140 };
141
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");
144
145 static uint8_t bond_mode_to_kernel(BondMode mode) {
146 switch (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;
161 default:
162 return (uint8_t) -1;
163 }
164 }
165
166 static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
167 switch (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;
178 default:
179 return (uint8_t) -1;
180 }
181 }
182
183 static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
184 Bond *b;
185 ArpIpTarget *target = NULL;
186 int r, i = 0;
187
188 assert(netdev);
189 assert(!link);
190 assert(m);
191
192 b = BOND(netdev);
193
194 assert(b);
195
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));
199 if (r < 0)
200 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
201 }
202
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));
206 if (r < 0)
207 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
208 }
209
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 );
213 if (r < 0)
214 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
215 }
216
217 if (b->miimon != 0) {
218 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
219 if (r < 0)
220 log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
221 }
222
223 if (b->downdelay != 0) {
224 r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
225 if (r < 0)
226 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
227 }
228
229 if (b->updelay != 0) {
230 r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
231 if (r < 0)
232 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_UPDELAY attribute: %m");
233 }
234
235 if (b->arp_interval != 0) {
236 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
237 if (r < 0)
238 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
239
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);
243 if (r < 0)
244 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
245 }
246 }
247
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);
251 if (r < 0)
252 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
253 }
254
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);
258 if (r < 0)
259 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
260 }
261
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);
264 if (r < 0)
265 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
266 }
267
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);
270 if (r < 0)
271 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
272 }
273
274 if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
275 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect);
276 if (r < 0)
277 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
278 }
279
280 if (b->resend_igmp <= RESEND_IGMP_MAX) {
281 r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
282 if (r < 0)
283 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
284 }
285
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);
289 if (r < 0)
290 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
291 }
292
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);
295 if (r < 0)
296 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
297 }
298
299 if (b->min_links != 0) {
300 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
301 if (r < 0)
302 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
303 }
304
305 r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
306 if (r < 0)
307 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
308
309 if (b->arp_interval > 0) {
310 if (b->n_arp_ip_targets > 0) {
311
312 r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
313 if (r < 0)
314 return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
315
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);
318 if (r < 0)
319 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
320 }
321
322 r = sd_netlink_message_close_container(m);
323 if (r < 0)
324 return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
325 }
326 }
327
328 return 0;
329 }
330
331 int config_parse_arp_ip_target_address(const char *unit,
332 const char *filename,
333 unsigned line,
334 const char *section,
335 unsigned section_line,
336 const char *lvalue,
337 int ltype,
338 const char *rvalue,
339 void *data,
340 void *userdata) {
341 Bond *b = userdata;
342 int r;
343
344 assert(filename);
345 assert(lvalue);
346 assert(rvalue);
347 assert(data);
348
349 for (;;) {
350 _cleanup_free_ ArpIpTarget *buffer = NULL;
351 _cleanup_free_ char *n = NULL;
352 int f;
353
354 r = extract_first_word(&rvalue, &n, NULL, 0);
355 if (r < 0) {
356 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue);
357 return 0;
358 }
359
360 if (r == 0)
361 break;
362
363 buffer = new0(ArpIpTarget, 1);
364 if (!buffer)
365 return -ENOMEM;
366
367 r = in_addr_from_string_auto(n, &f, &buffer->ip);
368 if (r < 0) {
369 log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
370 return 0;
371 }
372
373 if (f != AF_INET) {
374 log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
375 return 0;
376 }
377
378 LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
379 b->n_arp_ip_targets++;
380
381 buffer = NULL;
382 }
383
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);
388
389 return 0;
390 }
391
392 static void bond_done(NetDev *netdev) {
393 ArpIpTarget *t = NULL, *n = NULL;
394 Bond *b;
395
396 assert(netdev);
397
398 b = BOND(netdev);
399
400 assert(b);
401
402 LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
403 free(t);
404
405 b->arp_ip_targets = NULL;
406 }
407
408 static void bond_init(NetDev *netdev) {
409 Bond *b;
410
411 assert(netdev);
412
413 b = BOND(netdev);
414
415 assert(b);
416
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;
425
426 b->all_slaves_active = false;
427
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;
432
433 LIST_HEAD_INIT(b->arp_ip_targets);
434 b->n_arp_ip_targets = 0;
435 }
436
437 const NetDevVTable bond_vtable = {
438 .object_size = sizeof(Bond),
439 .init = bond_init,
440 .done = bond_done,
441 .sections = "Match\0NetDev\0Bond\0",
442 .fill_message_create = netdev_bond_fill_message_create,
443 .create_type = NETDEV_CREATE_MASTER,
444 };