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