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