]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/network/netdev/bond.c
ukify: fix parsing uname version with '+'
[thirdparty/systemd.git] / src / network / netdev / bond.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <linux/if_arp.h>
4#include <netinet/in.h>
5
6#include "sd-netlink.h"
7
8#include "alloc-util.h"
9#include "bond.h"
10#include "bond-util.h"
11#include "conf-parser.h"
12#include "ether-addr-util.h"
13#include "extract-word.h"
14#include "in-addr-util.h"
15#include "networkd-link.h"
16#include "ordered-set.h"
17#include "set.h"
18#include "string-util.h"
19#include "time-util.h"
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
51DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode);
52DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
53 bond_xmit_hash_policy,
54 BondXmitHashPolicy);
55DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate);
56DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect);
57DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac);
58DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate);
59DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets);
60DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect);
61
62static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
63 Bond *b = BOND(netdev);
64 int r;
65
66 assert(netdev->manager);
67 assert(!link);
68 assert(m);
69
70 if (netdev->ifindex > 0) {
71 r = link_get_by_index(netdev->manager, netdev->ifindex, &link);
72 if (r < 0)
73 return r;
74 }
75
76 bool up = link && FLAGS_SET(link->flags, IFF_UP);
77 bool has_slaves = link && !set_isempty(link->slaves);
78
79 if (b->mode != _NETDEV_BOND_MODE_INVALID && !up && !has_slaves) {
80 r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, b->mode);
81 if (r < 0)
82 return r;
83 }
84
85 if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
86 r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY, b->xmit_hash_policy);
87 if (r < 0)
88 return r;
89 }
90
91 if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
92 b->mode == NETDEV_BOND_MODE_802_3AD &&
93 !up) {
94 r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate);
95 if (r < 0)
96 return r;
97 }
98
99 if (b->miimon != 0) {
100 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
101 if (r < 0)
102 return r;
103 }
104
105 if (b->peer_notify_delay != 0) {
106 r = sd_netlink_message_append_u32(m, IFLA_BOND_PEER_NOTIF_DELAY, b->peer_notify_delay / USEC_PER_MSEC);
107 if (r < 0)
108 return r;
109 }
110
111 if (b->downdelay != 0) {
112 r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
113 if (r < 0)
114 return r;
115 }
116
117 if (b->updelay != 0) {
118 r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
119 if (r < 0)
120 return r;
121 }
122
123 if (b->arp_interval != 0) {
124 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
125 if (r < 0)
126 return r;
127
128 if (b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC &&
129 b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC) {
130 r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
131 if (r < 0)
132 return r;
133 }
134 }
135
136 if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
137 b->mode == NETDEV_BOND_MODE_802_3AD &&
138 !up) {
139 r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
140 if (r < 0)
141 return r;
142 }
143
144 if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
145 b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP &&
146 !has_slaves) {
147 r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
148 if (r < 0)
149 return r;
150 }
151
152 if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
153 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
154 if (r < 0)
155 return r;
156 }
157
158 if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
159 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
160 if (r < 0)
161 return r;
162 }
163
164 if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
165 r = sd_netlink_message_append_u8(m, IFLA_BOND_PRIMARY_RESELECT, b->primary_reselect);
166 if (r < 0)
167 return r;
168 }
169
170 if (b->resend_igmp <= RESEND_IGMP_MAX) {
171 r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
172 if (r < 0)
173 return r;
174 }
175
176 if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX &&
177 b->mode == NETDEV_BOND_MODE_BALANCE_RR) {
178 r = sd_netlink_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
179 if (r < 0)
180 return r;
181 }
182
183 if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
184 r = sd_netlink_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
185 if (r < 0)
186 return r;
187 }
188
189 if (b->min_links != 0) {
190 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
191 if (r < 0)
192 return r;
193 }
194
195 if (b->ad_actor_sys_prio != 0) {
196 r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_ACTOR_SYS_PRIO, b->ad_actor_sys_prio);
197 if (r < 0)
198 return r;
199 }
200
201 if (b->ad_user_port_key != 0 && !up) {
202 r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_USER_PORT_KEY, b->ad_user_port_key);
203 if (r < 0)
204 return r;
205 }
206
207 if (!ether_addr_is_null(&b->ad_actor_system)) {
208 r = sd_netlink_message_append_ether_addr(m, IFLA_BOND_AD_ACTOR_SYSTEM, &b->ad_actor_system);
209 if (r < 0)
210 return r;
211 }
212
213 r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
214 if (r < 0)
215 return r;
216
217 if (b->tlb_dynamic_lb >= 0 && !up) {
218 r = sd_netlink_message_append_u8(m, IFLA_BOND_TLB_DYNAMIC_LB, b->tlb_dynamic_lb);
219 if (r < 0)
220 return r;
221 }
222
223 if (b->arp_missed_max > 0) {
224 r = sd_netlink_message_append_u8(m, IFLA_BOND_MISSED_MAX, b->arp_missed_max);
225 if (r < 0)
226 return r;
227 }
228
229 if (b->arp_interval > 0 && !ordered_set_isempty(b->arp_ip_targets)) {
230 void *val;
231 int n = 0;
232
233 r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
234 if (r < 0)
235 return r;
236
237 ORDERED_SET_FOREACH(val, b->arp_ip_targets) {
238 r = sd_netlink_message_append_u32(m, n++, PTR_TO_UINT32(val));
239 if (r < 0)
240 return r;
241 }
242
243 r = sd_netlink_message_close_container(m);
244 if (r < 0)
245 return r;
246 }
247
248 return 0;
249}
250
251int config_parse_arp_ip_target_address(
252 const char *unit,
253 const char *filename,
254 unsigned line,
255 const char *section,
256 unsigned section_line,
257 const char *lvalue,
258 int ltype,
259 const char *rvalue,
260 void *data,
261 void *userdata) {
262
263 assert(filename);
264 assert(lvalue);
265 assert(rvalue);
266 assert(data);
267
268 Bond *b = BOND(userdata);
269 int r;
270
271 if (isempty(rvalue)) {
272 b->arp_ip_targets = ordered_set_free(b->arp_ip_targets);
273 return 0;
274 }
275
276 for (const char *p = rvalue;;) {
277 _cleanup_free_ char *n = NULL;
278 union in_addr_union ip;
279
280 r = extract_first_word(&p, &n, NULL, 0);
281 if (r == -ENOMEM)
282 return log_oom();
283 if (r < 0) {
284 log_syntax(unit, LOG_WARNING, filename, line, r,
285 "Failed to parse Bond ARP IP target address, ignoring assignment: %s",
286 rvalue);
287 return 0;
288 }
289 if (r == 0)
290 return 0;
291
292 r = in_addr_from_string(AF_INET, n, &ip);
293 if (r < 0) {
294 log_syntax(unit, LOG_WARNING, filename, line, r,
295 "Bond ARP IP target address is invalid, ignoring assignment: %s", n);
296 continue;
297 }
298
299 if (ordered_set_size(b->arp_ip_targets) >= NETDEV_BOND_ARP_TARGETS_MAX) {
300 log_syntax(unit, LOG_WARNING, filename, line, 0,
301 "Too many ARP IP targets are specified. The maximum number is %d. Ignoring assignment: %s",
302 NETDEV_BOND_ARP_TARGETS_MAX, n);
303 continue;
304 }
305
306 r = ordered_set_ensure_put(&b->arp_ip_targets, NULL, UINT32_TO_PTR(ip.in.s_addr));
307 if (r == -ENOMEM)
308 return log_oom();
309 if (r == -EEXIST)
310 log_syntax(unit, LOG_WARNING, filename, line, r,
311 "Bond ARP IP target address is duplicated, ignoring assignment: %s", n);
312 if (r < 0)
313 log_syntax(unit, LOG_WARNING, filename, line, r,
314 "Failed to store bond ARP IP target address '%s', ignoring assignment: %m", n);
315 }
316}
317
318int config_parse_ad_actor_sys_prio(
319 const char *unit,
320 const char *filename,
321 unsigned line,
322 const char *section,
323 unsigned section_line,
324 const char *lvalue,
325 int ltype,
326 const char *rvalue,
327 void *data,
328 void *userdata) {
329
330 assert(filename);
331 assert(lvalue);
332 assert(rvalue);
333 assert(data);
334
335 Bond *b = ASSERT_PTR(userdata);
336
337 return config_parse_uint16_bounded(
338 unit, filename, line, section, section_line, lvalue, rvalue,
339 1, UINT16_MAX, true,
340 &b->ad_actor_sys_prio);
341}
342
343int config_parse_ad_user_port_key(
344 const char *unit,
345 const char *filename,
346 unsigned line,
347 const char *section,
348 unsigned section_line,
349 const char *lvalue,
350 int ltype,
351 const char *rvalue,
352 void *data,
353 void *userdata) {
354
355 assert(filename);
356 assert(lvalue);
357 assert(rvalue);
358 assert(data);
359
360 Bond *b = ASSERT_PTR(userdata);
361
362 return config_parse_uint16_bounded(
363 unit, filename, line, section, section_line, lvalue, rvalue,
364 0, 1023, /* ignoring= */ true,
365 &b->ad_user_port_key);
366}
367
368int config_parse_ad_actor_system(
369 const char *unit,
370 const char *filename,
371 unsigned line,
372 const char *section,
373 unsigned section_line,
374 const char *lvalue,
375 int ltype,
376 const char *rvalue,
377 void *data,
378 void *userdata) {
379 Bond *b = userdata;
380 struct ether_addr n;
381 int r;
382
383 assert(filename);
384 assert(lvalue);
385 assert(rvalue);
386 assert(data);
387
388 r = parse_ether_addr(rvalue, &n);
389 if (r < 0) {
390 log_syntax(unit, LOG_WARNING, filename, line, r,
391 "Not a valid MAC address %s. Ignoring assignment: %m",
392 rvalue);
393 return 0;
394 }
395 if (ether_addr_is_null(&n) || (n.ether_addr_octet[0] & 0x01)) {
396 log_syntax(unit, LOG_WARNING, filename, line, 0,
397 "Not an appropriate MAC address %s, cannot be null or multicast. Ignoring assignment.",
398 rvalue);
399 return 0;
400 }
401
402 b->ad_actor_system = n;
403
404 return 0;
405}
406
407static void bond_done(NetDev *netdev) {
408 Bond *b = BOND(netdev);
409
410 ordered_set_free(b->arp_ip_targets);
411}
412
413static void bond_init(NetDev *netdev) {
414 Bond *b = BOND(netdev);
415
416 b->mode = _NETDEV_BOND_MODE_INVALID;
417 b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
418 b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
419 b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID;
420 b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID;
421 b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID;
422 b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID;
423 b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
424
425 b->all_slaves_active = false;
426 b->tlb_dynamic_lb = -1;
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
434const NetDevVTable bond_vtable = {
435 .object_size = sizeof(Bond),
436 .init = bond_init,
437 .done = bond_done,
438 .sections = NETDEV_COMMON_SECTIONS "Bond\0",
439 .fill_message_create = netdev_bond_fill_message_create,
440 .create_type = NETDEV_CREATE_INDEPENDENT,
441 .iftype = ARPHRD_ETHER,
442 .generate_mac = true,
443};