]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev-bond.c
Merge pull request #84 from blueyed/zsh-optimize-filter_units_by_property
[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 "conf-parser.h"
27 #include "sd-rtnl.h"
28 #include "rtnl-types.h"
29 #include "networkd-netdev-bond.h"
30 #include "missing.h"
31
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
63 static 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
73 DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
74 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
75
76 static 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
84 DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
85 DEFINE_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
90 static 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
95 DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
96 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
97
98 static 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
104 DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
105 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
106
107 static 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
113 DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
114 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
115
116 static 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
123 DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
124 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
125
126 static 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
131 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
132 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
133
134 static 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
140 DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
141 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
142
143 static 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
164 static 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
181 static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
182 Bond *b = BOND(netdev);
183 ArpIpTarget *target = NULL;
184 int r, i = 0;
185
186 assert(netdev);
187 assert(!link);
188 assert(b);
189 assert(m);
190
191 if (b->mode != _NETDEV_BOND_MODE_INVALID) {
192 r = sd_rtnl_message_append_u8(m, IFLA_BOND_MODE,
193 bond_mode_to_kernel(b->mode));
194 if (r < 0)
195 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
196 }
197
198 if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
199 r = sd_rtnl_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
200 bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
201 if (r < 0)
202 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
203 }
204
205 if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
206 b->mode == NETDEV_BOND_MODE_802_3AD) {
207 r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
208 if (r < 0) {
209 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
210 }
211 }
212
213 if (b->miimon != 0) {
214 r = sd_rtnl_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_rtnl_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_rtnl_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_rtnl_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_rtnl_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 == BOND_MODE_8023AD) {
246 r = sd_rtnl_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_rtnl_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_rtnl_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_rtnl_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_rtnl_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_rtnl_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 r = sd_rtnl_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
284 if (r < 0)
285 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
286 }
287
288 if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
289 r = sd_rtnl_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
290 if (r < 0)
291 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
292 }
293
294 if (b->min_links != 0) {
295 r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
296 if (r < 0)
297 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
298 }
299
300 r = sd_rtnl_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
301 if (r < 0)
302 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
303
304 if (b->arp_interval > 0) {
305 if (b->n_arp_ip_targets > 0) {
306
307 r = sd_rtnl_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
308 if (r < 0)
309 return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
310
311 LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
312 r = sd_rtnl_message_append_u32(m, i++, target->ip.in.s_addr);
313 if (r < 0)
314 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
315 }
316
317 r = sd_rtnl_message_close_container(m);
318 if (r < 0)
319 return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
320 }
321 }
322
323 return 0;
324 }
325
326 int config_parse_arp_ip_target_address(const char *unit,
327 const char *filename,
328 unsigned line,
329 const char *section,
330 unsigned section_line,
331 const char *lvalue,
332 int ltype,
333 const char *rvalue,
334 void *data,
335 void *userdata) {
336 Bond *b = userdata;
337 const char *word, *state;
338 size_t l;
339 int r;
340
341 assert(filename);
342 assert(lvalue);
343 assert(rvalue);
344 assert(data);
345
346 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
347 _cleanup_free_ ArpIpTarget *buffer = NULL;
348 _cleanup_free_ char *n = NULL;
349 int f;
350
351 n = strndup(word, l);
352 if (!n)
353 return -ENOMEM;
354
355 buffer = new0(ArpIpTarget, 1);
356 if (!buffer)
357 return -ENOMEM;
358
359 r = in_addr_from_string_auto(n, &f, &buffer->ip);
360 if (r < 0) {
361 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
362 return 0;
363 }
364
365 if (f != AF_INET) {
366 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
367 return 0;
368 }
369
370 LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
371 b->n_arp_ip_targets ++;
372
373 buffer = NULL;
374
375 if (b->n_arp_ip_targets > BOND_ARP_TARGETS_MAX)
376 break;
377 }
378
379 return 0;
380 }
381
382 static void bond_done(NetDev *netdev) {
383 ArpIpTarget *t = NULL, *n = NULL;
384 Bond *b = BOND(netdev);
385
386 assert(netdev);
387 assert(b);
388
389 LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
390 free(t);
391
392 b->arp_ip_targets = NULL;
393 }
394
395 static void bond_init(NetDev *netdev) {
396 Bond *b = BOND(netdev);
397
398 assert(netdev);
399 assert(b);
400
401 b->mode = _NETDEV_BOND_MODE_INVALID;
402 b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
403 b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
404 b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID;
405 b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID;
406 b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID;
407 b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID;
408 b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
409
410 b->all_slaves_active = false;
411
412 b->resend_igmp = RESEND_IGMP_DEFAULT;
413 b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
414 b->num_grat_arp = GRATUITOUS_ARP_DEFAULT;
415 b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC;
416
417 LIST_HEAD_INIT(b->arp_ip_targets);
418 b->n_arp_ip_targets = 0;
419 }
420
421 const NetDevVTable bond_vtable = {
422 .object_size = sizeof(Bond),
423 .init = bond_init,
424 .done = bond_done,
425 .sections = "Match\0NetDev\0Bond\0",
426 .fill_message_create = netdev_bond_fill_message_create,
427 .create_type = NETDEV_CREATE_MASTER,
428 };