]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/bond.c
analyze: fix typo
[thirdparty/systemd.git] / src / network / netdev / bond.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
fe8ac65b 2
9f0cf80d 3#include <linux/if_arp.h>
1cf40697 4#include <netinet/in.h>
9f0cf80d 5
baa3fadf
DDM
6#include "sd-netlink.h"
7
b5efdb8a 8#include "alloc-util.h"
f2000933 9#include "bond.h"
5fe5908e 10#include "bond-util.h"
07630cea 11#include "conf-parser.h"
99f68ef0 12#include "ether-addr-util.h"
634f0f98 13#include "extract-word.h"
baa3fadf
DDM
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"
81bd37a8
SS
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
42efe5be 51DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode);
227cdf2c
SS
52DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
53 bond_xmit_hash_policy,
42efe5be
YW
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);
81bd37a8 61
1c4baffc 62static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
69bd661a
YW
63 Bond *b = BOND(netdev);
64 int r;
65
66 assert(netdev->manager);
aa9f1140 67 assert(!link);
fe8ac65b
SS
68 assert(m);
69
69bd661a
YW
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);
ae185f48 78
69bd661a 79 if (b->mode != _NETDEV_BOND_MODE_INVALID && !up && !has_slaves) {
f2000933 80 r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, b->mode);
a668086e 81 if (r < 0)
5b80ecea 82 return r;
fe8ac65b
SS
83 }
84
227cdf2c 85 if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
f2000933 86 r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY, b->xmit_hash_policy);
a668086e 87 if (r < 0)
5b80ecea 88 return r;
227cdf2c
SS
89 }
90
fb1021a2 91 if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
69bd661a
YW
92 b->mode == NETDEV_BOND_MODE_802_3AD &&
93 !up) {
3f7cc080 94 r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate);
ece174c5 95 if (r < 0)
5b80ecea 96 return r;
fb1021a2
SS
97 }
98
d9c52fa0 99 if (b->miimon != 0) {
1c4baffc 100 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
a668086e 101 if (r < 0)
5b80ecea 102 return r;
d9c52fa0
SS
103 }
104
00386d5b
SS
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
d9c52fa0 111 if (b->downdelay != 0) {
1c4baffc 112 r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
a668086e 113 if (r < 0)
5b80ecea 114 return r;
d9c52fa0
SS
115 }
116
117 if (b->updelay != 0) {
1c4baffc 118 r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
a668086e 119 if (r < 0)
5b80ecea 120 return r;
d9c52fa0
SS
121 }
122
81bd37a8 123 if (b->arp_interval != 0) {
1c4baffc 124 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
a668086e 125 if (r < 0)
5b80ecea 126 return r;
a668086e 127
3f7cc080
YW
128 if (b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC &&
129 b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC) {
1c4baffc 130 r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
a668086e 131 if (r < 0)
5b80ecea 132 return r;
81bd37a8
SS
133 }
134 }
135
136 if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
69bd661a
YW
137 b->mode == NETDEV_BOND_MODE_802_3AD &&
138 !up) {
1c4baffc 139 r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
a668086e 140 if (r < 0)
5b80ecea 141 return r;
81bd37a8
SS
142 }
143
144 if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
69bd661a
YW
145 b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP &&
146 !has_slaves) {
1c4baffc 147 r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
a668086e 148 if (r < 0)
5b80ecea 149 return r;
81bd37a8
SS
150 }
151
152 if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
1c4baffc 153 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
a668086e 154 if (r < 0)
5b80ecea 155 return r;
81bd37a8
SS
156 }
157
158 if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
1c4baffc 159 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
a668086e 160 if (r < 0)
5b80ecea 161 return r;
81bd37a8
SS
162 }
163
164 if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
e59ace18 165 r = sd_netlink_message_append_u8(m, IFLA_BOND_PRIMARY_RESELECT, b->primary_reselect);
a668086e 166 if (r < 0)
5b80ecea 167 return r;
81bd37a8
SS
168 }
169
170 if (b->resend_igmp <= RESEND_IGMP_MAX) {
1c4baffc 171 r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
a668086e 172 if (r < 0)
5b80ecea 173 return r;
81bd37a8
SS
174 }
175
76f0a567
TG
176 if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX &&
177 b->mode == NETDEV_BOND_MODE_BALANCE_RR) {
1c4baffc 178 r = sd_netlink_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
a668086e 179 if (r < 0)
5b80ecea 180 return r;
81bd37a8
SS
181 }
182
183 if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
1c4baffc 184 r = sd_netlink_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
a668086e 185 if (r < 0)
5b80ecea 186 return r;
81bd37a8
SS
187 }
188
189 if (b->min_links != 0) {
1c4baffc 190 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
a668086e 191 if (r < 0)
5b80ecea 192 return r;
81bd37a8
SS
193 }
194
99f68ef0
TJ
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)
5b80ecea 198 return r;
99f68ef0
TJ
199 }
200
69bd661a 201 if (b->ad_user_port_key != 0 && !up) {
99f68ef0
TJ
202 r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_USER_PORT_KEY, b->ad_user_port_key);
203 if (r < 0)
5b80ecea 204 return r;
99f68ef0
TJ
205 }
206
1e2a490e
YW
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);
99f68ef0 209 if (r < 0)
5b80ecea 210 return r;
99f68ef0
TJ
211 }
212
1c4baffc 213 r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
a668086e 214 if (r < 0)
5b80ecea 215 return r;
81bd37a8 216
69bd661a 217 if (b->tlb_dynamic_lb >= 0 && !up) {
fde60a42
SS
218 r = sd_netlink_message_append_u8(m, IFLA_BOND_TLB_DYNAMIC_LB, b->tlb_dynamic_lb);
219 if (r < 0)
5b80ecea 220 return r;
fde60a42
SS
221 }
222
b33bba04
SS
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
674c96fc 229 if (b->arp_interval > 0 && !ordered_set_isempty(b->arp_ip_targets)) {
674c96fc
YW
230 void *val;
231 int n = 0;
232
3f7cc080
YW
233 r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
234 if (r < 0)
5b80ecea 235 return r;
81bd37a8 236
90e74a66 237 ORDERED_SET_FOREACH(val, b->arp_ip_targets) {
674c96fc 238 r = sd_netlink_message_append_u32(m, n++, PTR_TO_UINT32(val));
a668086e 239 if (r < 0)
5b80ecea 240 return r;
81bd37a8 241 }
3f7cc080
YW
242
243 r = sd_netlink_message_close_container(m);
244 if (r < 0)
5b80ecea 245 return r;
81bd37a8
SS
246 }
247
aa9f1140
TG
248 return 0;
249}
fe8ac65b 250
674c96fc
YW
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
81bd37a8
SS
263 assert(filename);
264 assert(lvalue);
265 assert(rvalue);
266 assert(data);
267
117843fe 268 Bond *b = BOND(userdata);
257cebb6
ZJS
269 int r;
270
674c96fc
YW
271 if (isempty(rvalue)) {
272 b->arp_ip_targets = ordered_set_free(b->arp_ip_targets);
273 return 0;
274 }
275
d96edb2c 276 for (const char *p = rvalue;;) {
81bd37a8 277 _cleanup_free_ char *n = NULL;
674c96fc 278 union in_addr_union ip;
81bd37a8 279
d96edb2c
YW
280 r = extract_first_word(&p, &n, NULL, 0);
281 if (r == -ENOMEM)
282 return log_oom();
022833c8 283 if (r < 0) {
d96edb2c 284 log_syntax(unit, LOG_WARNING, filename, line, r,
0da425df 285 "Failed to parse Bond ARP IP target address, ignoring assignment: %s",
674c96fc 286 rvalue);
022833c8
SS
287 return 0;
288 }
022833c8 289 if (r == 0)
674c96fc 290 return 0;
81bd37a8 291
674c96fc 292 r = in_addr_from_string(AF_INET, n, &ip);
81bd37a8 293 if (r < 0) {
d96edb2c 294 log_syntax(unit, LOG_WARNING, filename, line, r,
0da425df 295 "Bond ARP IP target address is invalid, ignoring assignment: %s", n);
674c96fc 296 continue;
81bd37a8
SS
297 }
298
674c96fc
YW
299 if (ordered_set_size(b->arp_ip_targets) >= NETDEV_BOND_ARP_TARGETS_MAX) {
300 log_syntax(unit, LOG_WARNING, filename, line, 0,
0da425df 301 "Too many ARP IP targets are specified. The maximum number is %d. Ignoring assignment: %s",
674c96fc
YW
302 NETDEV_BOND_ARP_TARGETS_MAX, n);
303 continue;
81bd37a8
SS
304 }
305
d1ce8359
SS
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();
674c96fc
YW
309 if (r == -EEXIST)
310 log_syntax(unit, LOG_WARNING, filename, line, r,
0da425df 311 "Bond ARP IP target address is duplicated, ignoring assignment: %s", n);
674c96fc 312 if (r < 0)
d96edb2c 313 log_syntax(unit, LOG_WARNING, filename, line, r,
0da425df 314 "Failed to store bond ARP IP target address '%s', ignoring assignment: %m", n);
81bd37a8 315 }
81bd37a8
SS
316}
317
3e8afae5
YW
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) {
99f68ef0
TJ
329
330 assert(filename);
331 assert(lvalue);
332 assert(rvalue);
333 assert(data);
334
851cdffd 335 Bond *b = ASSERT_PTR(userdata);
99f68ef0 336
851cdffd
ZJS
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);
99f68ef0
TJ
341}
342
3e8afae5
YW
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) {
99f68ef0
TJ
354
355 assert(filename);
356 assert(lvalue);
357 assert(rvalue);
358 assert(data);
359
851cdffd 360 Bond *b = ASSERT_PTR(userdata);
99f68ef0 361
851cdffd
ZJS
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);
99f68ef0
TJ
366}
367
1e2a490e
YW
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) {
99f68ef0 379 Bond *b = userdata;
1e2a490e 380 struct ether_addr n;
99f68ef0
TJ
381 int r;
382
383 assert(filename);
384 assert(lvalue);
385 assert(rvalue);
386 assert(data);
387
227e9ce2 388 r = parse_ether_addr(rvalue, &n);
99f68ef0 389 if (r < 0) {
d96edb2c 390 log_syntax(unit, LOG_WARNING, filename, line, r,
1e2a490e
YW
391 "Not a valid MAC address %s. Ignoring assignment: %m",
392 rvalue);
99f68ef0
TJ
393 return 0;
394 }
1e2a490e 395 if (ether_addr_is_null(&n) || (n.ether_addr_octet[0] & 0x01)) {
d96edb2c 396 log_syntax(unit, LOG_WARNING, filename, line, 0,
7ad41997 397 "Not an appropriate MAC address %s, cannot be null or multicast. Ignoring assignment.",
1e2a490e 398 rvalue);
99f68ef0
TJ
399 return 0;
400 }
401
1e2a490e 402 b->ad_actor_system = n;
99f68ef0
TJ
403
404 return 0;
405}
406
81bd37a8 407static void bond_done(NetDev *netdev) {
117843fe 408 Bond *b = BOND(netdev);
81bd37a8 409
674c96fc 410 ordered_set_free(b->arp_ip_targets);
81bd37a8
SS
411}
412
aa9f1140 413static void bond_init(NetDev *netdev) {
117843fe 414 Bond *b = BOND(netdev);
fe8ac65b 415
aa9f1140 416 b->mode = _NETDEV_BOND_MODE_INVALID;
227cdf2c 417 b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
fb1021a2 418 b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
81bd37a8
SS
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;
fde60a42 426 b->tlb_dynamic_lb = -1;
81bd37a8
SS
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;
fe8ac65b
SS
432}
433
3be1d7e0 434const NetDevVTable bond_vtable = {
aa9f1140
TG
435 .object_size = sizeof(Bond),
436 .init = bond_init,
81bd37a8 437 .done = bond_done,
130b812f 438 .sections = NETDEV_COMMON_SECTIONS "Bond\0",
3be1d7e0 439 .fill_message_create = netdev_bond_fill_message_create,
97b2bc35 440 .create_type = NETDEV_CREATE_INDEPENDENT,
9f0cf80d 441 .iftype = ARPHRD_ETHER,
daf0f8ca 442 .generate_mac = true,
3be1d7e0 443};