]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/link-config.c
Merge pull request #18886 from anitazha/shutdownconsole
[thirdparty/systemd.git] / src / udev / net / link-config.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/netdevice.h>
4 #include <netinet/ether.h>
5 #include <unistd.h>
6
7 #include "sd-device.h"
8 #include "sd-netlink.h"
9
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "conf-parser.h"
13 #include "def.h"
14 #include "device-private.h"
15 #include "device-util.h"
16 #include "ethtool-util.h"
17 #include "fd-util.h"
18 #include "link-config.h"
19 #include "log.h"
20 #include "memory-util.h"
21 #include "net-condition.h"
22 #include "netif-naming-scheme.h"
23 #include "netlink-util.h"
24 #include "network-util.h"
25 #include "parse-util.h"
26 #include "path-lookup.h"
27 #include "path-util.h"
28 #include "proc-cmdline.h"
29 #include "random-util.h"
30 #include "stat-util.h"
31 #include "string-table.h"
32 #include "string-util.h"
33 #include "strv.h"
34 #include "utf8.h"
35
36 struct link_config_ctx {
37 LIST_HEAD(link_config, links);
38
39 int ethtool_fd;
40
41 bool enable_name_policy;
42
43 sd_netlink *rtnl;
44
45 usec_t network_dirs_ts_usec;
46 };
47
48 static link_config* link_config_free(link_config *link) {
49 if (!link)
50 return NULL;
51
52 free(link->filename);
53
54 net_match_clear(&link->match);
55 condition_free_list(link->conditions);
56
57 free(link->description);
58 free(link->mac);
59 free(link->name_policy);
60 free(link->name);
61 strv_free(link->alternative_names);
62 free(link->alternative_names_policy);
63 free(link->alias);
64
65 return mfree(link);
66 }
67
68 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
69
70 static void link_configs_free(link_config_ctx *ctx) {
71 link_config *link, *link_next;
72
73 if (!ctx)
74 return;
75
76 LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
77 link_config_free(link);
78 }
79
80 link_config_ctx* link_config_ctx_free(link_config_ctx *ctx) {
81 if (!ctx)
82 return NULL;
83
84 safe_close(ctx->ethtool_fd);
85 sd_netlink_unref(ctx->rtnl);
86 link_configs_free(ctx);
87 return mfree(ctx);
88 }
89
90 int link_config_ctx_new(link_config_ctx **ret) {
91 _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
92
93 if (!ret)
94 return -EINVAL;
95
96 ctx = new0(link_config_ctx, 1);
97 if (!ctx)
98 return -ENOMEM;
99
100 LIST_HEAD_INIT(ctx->links);
101
102 ctx->ethtool_fd = -1;
103
104 ctx->enable_name_policy = true;
105
106 *ret = TAKE_PTR(ctx);
107
108 return 0;
109 }
110
111 int link_load_one(link_config_ctx *ctx, const char *filename) {
112 _cleanup_(link_config_freep) link_config *link = NULL;
113 _cleanup_free_ char *name = NULL;
114 const char *dropin_dirname;
115 size_t i;
116 int r;
117
118 assert(ctx);
119 assert(filename);
120
121 r = null_or_empty_path(filename);
122 if (r == -ENOENT)
123 return 0;
124 if (r < 0)
125 return r;
126 if (r > 0) {
127 log_debug("Skipping empty file: %s", filename);
128 return 0;
129 }
130
131 name = strdup(filename);
132 if (!name)
133 return -ENOMEM;
134
135 link = new(link_config, 1);
136 if (!link)
137 return -ENOMEM;
138
139 *link = (link_config) {
140 .filename = TAKE_PTR(name),
141 .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
142 .wol = _WOL_INVALID,
143 .duplex = _DUP_INVALID,
144 .port = _NET_DEV_PORT_INVALID,
145 .autonegotiation = -1,
146 .rx_flow_control = -1,
147 .tx_flow_control = -1,
148 .autoneg_flow_control = -1,
149 .txqueuelen = UINT32_MAX,
150 };
151
152 for (i = 0; i < ELEMENTSOF(link->features); i++)
153 link->features[i] = -1;
154
155 dropin_dirname = strjoina(basename(filename), ".d");
156 r = config_parse_many(
157 STRV_MAKE_CONST(filename),
158 (const char* const*) CONF_PATHS_STRV("systemd/network"),
159 dropin_dirname,
160 "Match\0Link\0",
161 config_item_perf_lookup, link_config_gperf_lookup,
162 CONFIG_PARSE_WARN, link, NULL);
163 if (r < 0)
164 return r;
165
166 if (net_match_is_empty(&link->match) && !link->conditions) {
167 log_warning("%s: No valid settings found in the [Match] section, ignoring file. "
168 "To match all interfaces, add OriginalName=* in the [Match] section.",
169 filename);
170 return 0;
171 }
172
173 if (!condition_test_list(link->conditions, environ, NULL, NULL, NULL)) {
174 log_debug("%s: Conditions do not match the system environment, skipping.", filename);
175 return 0;
176 }
177
178 if (IN_SET(link->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM) && link->mac) {
179 log_warning("%s: MACAddress= in [Link] section will be ignored when MACAddressPolicy= "
180 "is set to \"persistent\" or \"random\".",
181 filename);
182 link->mac = mfree(link->mac);
183 }
184
185 log_debug("Parsed configuration file %s", filename);
186
187 LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
188 return 0;
189 }
190
191 static bool enable_name_policy(void) {
192 bool b;
193
194 return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
195 }
196
197 static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
198 const char *s;
199 int r;
200
201 r = sd_device_get_sysattr_value(device, attr, &s);
202 if (r < 0)
203 return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
204
205 r = safe_atou(s, type);
206 if (r < 0)
207 return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
208
209 log_device_debug(device, "Device has %s=%u", attr, *type);
210 return 0;
211 }
212
213 int link_config_load(link_config_ctx *ctx) {
214 _cleanup_strv_free_ char **files = NULL;
215 char **f;
216 int r;
217
218 link_configs_free(ctx);
219
220 if (!enable_name_policy()) {
221 ctx->enable_name_policy = false;
222 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
223 }
224
225 /* update timestamp */
226 paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
227
228 r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
229 if (r < 0)
230 return log_error_errno(r, "failed to enumerate link files: %m");
231
232 STRV_FOREACH_BACKWARDS(f, files) {
233 r = link_load_one(ctx, *f);
234 if (r < 0)
235 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
236 }
237
238 return 0;
239 }
240
241 bool link_config_should_reload(link_config_ctx *ctx) {
242 return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
243 }
244
245 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
246 unsigned name_assign_type = NET_NAME_UNKNOWN;
247 struct ether_addr permanent_mac = {};
248 unsigned short iftype = 0;
249 link_config *link;
250 const char *name;
251 int ifindex, r;
252
253 assert(ctx);
254 assert(device);
255 assert(ret);
256
257 r = sd_device_get_sysname(device, &name);
258 if (r < 0)
259 return r;
260
261 r = sd_device_get_ifindex(device, &ifindex);
262 if (r < 0)
263 return r;
264
265 r = rtnl_get_link_iftype(&ctx->rtnl, ifindex, &iftype);
266 if (r < 0)
267 return r;
268
269 r = ethtool_get_permanent_macaddr(&ctx->ethtool_fd, name, &permanent_mac);
270 if (r < 0)
271 log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
272
273 (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
274
275 LIST_FOREACH(links, link, ctx->links) {
276 if (net_match_config(&link->match, device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) {
277 if (link->match.ifname && !strv_contains(link->match.ifname, "*") && name_assign_type == NET_NAME_ENUM)
278 log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.",
279 link->filename);
280 else
281 log_device_debug(device, "Config file %s is applied", link->filename);
282
283 *ret = link;
284 return 0;
285 }
286 }
287
288 return -ENOENT;
289 }
290
291 static int link_config_apply_ethtool_settings(int *ethtool_fd, const link_config *config, sd_device *device) {
292 const char *name;
293 int r;
294
295 assert(ethtool_fd);
296 assert(config);
297 assert(device);
298
299 r = sd_device_get_sysname(device, &name);
300 if (r < 0)
301 return log_device_error_errno(device, r, "Failed to get sysname: %m");
302
303 r = ethtool_set_glinksettings(ethtool_fd, name,
304 config->autonegotiation, config->advertise,
305 config->speed, config->duplex, config->port);
306 if (r < 0) {
307 if (config->port != _NET_DEV_PORT_INVALID)
308 log_device_warning_errno(device, r, "Could not set port '%s', ignoring: %m", port_to_string(config->port));
309
310 if (!eqzero(config->advertise))
311 log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); /* TODO: include modes in the log message. */
312
313 if (config->speed) {
314 unsigned speed = DIV_ROUND_UP(config->speed, 1000000);
315 if (r == -EOPNOTSUPP) {
316 r = ethtool_set_speed(ethtool_fd, name, speed, config->duplex);
317 if (r < 0)
318 log_device_warning_errno(device, r, "Could not set speed to %uMbps, ignoring: %m", speed);
319 }
320 }
321
322 if (config->duplex != _DUP_INVALID)
323 log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", duplex_to_string(config->duplex));
324 }
325
326 r = ethtool_set_wol(ethtool_fd, name, config->wol);
327 if (r < 0)
328 log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m", wol_to_string(config->wol));
329
330 r = ethtool_set_features(ethtool_fd, name, config->features);
331 if (r < 0)
332 log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m");
333
334 if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
335 r = ethtool_set_channels(ethtool_fd, name, &config->channels);
336 if (r < 0)
337 log_device_warning_errno(device, r, "Could not set channels, ignoring: %m");
338 }
339
340 if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
341 r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring);
342 if (r < 0)
343 log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m");
344 }
345
346 if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
347 r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
348 if (r < 0)
349 log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m");
350 }
351
352 return 0;
353 }
354
355 static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
356 unsigned addr_type;
357 bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
358 int r;
359
360 assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
361
362 r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
363 if (r < 0)
364 return r;
365 switch (addr_type) {
366 case NET_ADDR_SET:
367 return log_device_debug(device, "MAC on the device already set by userspace");
368 case NET_ADDR_STOLEN:
369 return log_device_debug(device, "MAC on the device already set based on another device");
370 case NET_ADDR_RANDOM:
371 case NET_ADDR_PERM:
372 break;
373 default:
374 log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
375 return 0;
376 }
377
378 if (want_random == (addr_type == NET_ADDR_RANDOM))
379 return log_device_debug(device, "MAC on the device already matches policy *%s*",
380 mac_address_policy_to_string(policy));
381
382 if (want_random) {
383 log_device_debug(device, "Using random bytes to generate MAC");
384
385 /* We require genuine randomness here, since we want to make sure we won't collide with other
386 * systems booting up at the very same time. We do allow RDRAND however, since this is not
387 * cryptographic key material. */
388 r = genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND);
389 if (r < 0)
390 return log_device_error_errno(device, r, "Failed to acquire random data to generate MAC: %m");
391 } else {
392 uint64_t result;
393
394 r = net_get_unique_predictable_data(device,
395 naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
396 &result);
397 if (r < 0)
398 return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
399
400 log_device_debug(device, "Using generated persistent MAC address");
401 assert_cc(ETH_ALEN <= sizeof(result));
402 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
403 }
404
405 /* see eth_random_addr in the kernel */
406 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
407 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
408 return 1;
409 }
410
411 static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config *config, sd_device *device) {
412 struct ether_addr generated_mac, *mac = NULL;
413 int ifindex, r;
414
415 assert(rtnl);
416 assert(config);
417 assert(device);
418
419 r = sd_device_get_ifindex(device, &ifindex);
420 if (r < 0)
421 return log_device_error_errno(device, r, "Could not find ifindex: %m");
422
423 if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
424 if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
425 mac = &generated_mac;
426 } else
427 mac = config->mac;
428
429 r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac,
430 config->txqueues, config->rxqueues, config->txqueuelen,
431 config->mtu, config->gso_max_size, config->gso_max_segments);
432 if (r < 0)
433 log_device_warning_errno(device, r,
434 "Could not set Alias=, MACAddress=, "
435 "TransmitQueues=, ReceiveQueues=, TransmitQueueLength=, MTU=, "
436 "GenericSegmentOffloadMaxBytes= or GenericSegmentOffloadMaxSegments=, "
437 "ignoring: %m");
438
439 return 0;
440 }
441
442 static int link_config_generate_new_name(const link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
443 unsigned name_type = NET_NAME_UNKNOWN;
444 int r;
445
446 assert(ctx);
447 assert(config);
448 assert(device);
449 assert(ret_name);
450
451 (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
452
453 if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
454 && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
455 log_device_debug(device, "Device already has a name given by userspace, not renaming.");
456 goto no_rename;
457 }
458
459 if (ctx->enable_name_policy && config->name_policy)
460 for (NamePolicy *p = config->name_policy; *p != _NAMEPOLICY_INVALID; p++) {
461 const char *new_name = NULL;
462 NamePolicy policy = *p;
463
464 switch (policy) {
465 case NAMEPOLICY_KERNEL:
466 if (name_type != NET_NAME_PREDICTABLE)
467 continue;
468
469 /* The kernel claims to have given a predictable name, keep it. */
470 log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
471 name_policy_to_string(policy));
472 goto no_rename;
473 case NAMEPOLICY_KEEP:
474 if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
475 continue;
476
477 log_device_debug(device, "Policy *%s*: keeping existing userspace name",
478 name_policy_to_string(policy));
479 goto no_rename;
480 case NAMEPOLICY_DATABASE:
481 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
482 break;
483 case NAMEPOLICY_ONBOARD:
484 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
485 break;
486 case NAMEPOLICY_SLOT:
487 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
488 break;
489 case NAMEPOLICY_PATH:
490 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
491 break;
492 case NAMEPOLICY_MAC:
493 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
494 break;
495 default:
496 assert_not_reached("invalid policy");
497 }
498 if (ifname_valid(new_name)) {
499 log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
500 *ret_name = new_name;
501 return 0;
502 }
503 }
504
505 if (config->name) {
506 log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name);
507 *ret_name = config->name;
508 return 0;
509 }
510
511 log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
512 no_rename:
513 r = sd_device_get_sysname(device, ret_name);
514 if (r < 0)
515 return log_device_error_errno(device, r, "Failed to get sysname: %m");
516
517 return 0;
518 }
519
520 static int link_config_apply_alternative_names(sd_netlink **rtnl, const link_config *config, sd_device *device, const char *new_name) {
521 _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
522 const char *current_name;
523 int ifindex, r;
524
525 assert(rtnl);
526 assert(config);
527 assert(device);
528
529 r = sd_device_get_sysname(device, &current_name);
530 if (r < 0)
531 return log_device_error_errno(device, r, "Failed to get sysname: %m");
532
533 r = sd_device_get_ifindex(device, &ifindex);
534 if (r < 0)
535 return log_device_error_errno(device, r, "Could not find ifindex: %m");
536
537 if (config->alternative_names) {
538 altnames = strv_copy(config->alternative_names);
539 if (!altnames)
540 return log_oom();
541 }
542
543 if (config->alternative_names_policy)
544 for (NamePolicy *p = config->alternative_names_policy; *p != _NAMEPOLICY_INVALID; p++) {
545 const char *n = NULL;
546
547 switch (*p) {
548 case NAMEPOLICY_DATABASE:
549 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &n);
550 break;
551 case NAMEPOLICY_ONBOARD:
552 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &n);
553 break;
554 case NAMEPOLICY_SLOT:
555 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &n);
556 break;
557 case NAMEPOLICY_PATH:
558 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &n);
559 break;
560 case NAMEPOLICY_MAC:
561 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &n);
562 break;
563 default:
564 assert_not_reached("invalid policy");
565 }
566 if (!isempty(n)) {
567 r = strv_extend(&altnames, n);
568 if (r < 0)
569 return log_oom();
570 }
571 }
572
573 if (new_name)
574 strv_remove(altnames, new_name);
575 strv_remove(altnames, current_name);
576
577 r = rtnl_get_link_alternative_names(rtnl, ifindex, &current_altnames);
578 if (r < 0)
579 log_device_debug_errno(device, r, "Failed to get alternative names, ignoring: %m");
580
581 char **p;
582 STRV_FOREACH(p, current_altnames)
583 strv_remove(altnames, *p);
584
585 strv_uniq(altnames);
586 strv_sort(altnames);
587 r = rtnl_set_link_alternative_names(rtnl, ifindex, altnames);
588 if (r < 0)
589 log_device_full_errno(device, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
590 "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
591
592 return 0;
593 }
594
595 int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
596 const char *new_name;
597 sd_device_action_t a;
598 int r;
599
600 assert(ctx);
601 assert(config);
602 assert(device);
603 assert(ret_name);
604
605 r = sd_device_get_action(device, &a);
606 if (r < 0)
607 return log_device_error_errno(device, r, "Failed to get ACTION= property: %m");
608
609 if (!IN_SET(a, SD_DEVICE_ADD, SD_DEVICE_BIND, SD_DEVICE_MOVE)) {
610 log_device_debug(device, "Skipping to apply .link settings on '%s' uevent.", device_action_to_string(a));
611
612 r = sd_device_get_sysname(device, ret_name);
613 if (r < 0)
614 return log_device_error_errno(device, r, "Failed to get sysname: %m");
615
616 return 0;
617 }
618
619 r = link_config_apply_ethtool_settings(&ctx->ethtool_fd, config, device);
620 if (r < 0)
621 return r;
622
623 r = link_config_apply_rtnl_settings(&ctx->rtnl, config, device);
624 if (r < 0)
625 return r;
626
627 if (a == SD_DEVICE_MOVE) {
628 log_device_debug(device, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", device_action_to_string(a));
629
630 r = sd_device_get_sysname(device, &new_name);
631 if (r < 0)
632 return log_device_error_errno(device, r, "Failed to get sysname: %m");
633 } else {
634 r = link_config_generate_new_name(ctx, config, device, &new_name);
635 if (r < 0)
636 return r;
637 }
638
639 r = link_config_apply_alternative_names(&ctx->rtnl, config, device, new_name);
640 if (r < 0)
641 return r;
642
643 *ret_name = new_name;
644 return 0;
645 }
646
647 int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
648 const char *name;
649 char *driver = NULL;
650 int r;
651
652 r = sd_device_get_sysname(device, &name);
653 if (r < 0)
654 return r;
655
656 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
657 if (r < 0)
658 return r;
659
660 *ret = driver;
661 return 0;
662 }
663
664 int config_parse_ifalias(
665 const char *unit,
666 const char *filename,
667 unsigned line,
668 const char *section,
669 unsigned section_line,
670 const char *lvalue,
671 int ltype,
672 const char *rvalue,
673 void *data,
674 void *userdata) {
675
676 char **s = data;
677
678 assert(filename);
679 assert(lvalue);
680 assert(rvalue);
681 assert(data);
682
683 if (!isempty(rvalue)) {
684 *s = mfree(*s);
685 return 0;
686 }
687
688 if (!ascii_is_valid(rvalue)) {
689 log_syntax(unit, LOG_WARNING, filename, line, 0,
690 "Interface alias is not ASCII clean, ignoring assignment: %s", rvalue);
691 return 0;
692 }
693
694 if (strlen(rvalue) >= IFALIASZ) {
695 log_syntax(unit, LOG_WARNING, filename, line, 0,
696 "Interface alias is too long, ignoring assignment: %s", rvalue);
697 return 0;
698 }
699
700 return free_and_strdup_warn(s, rvalue);
701 }
702
703 int config_parse_rx_tx_queues(
704 const char *unit,
705 const char *filename,
706 unsigned line,
707 const char *section,
708 unsigned section_line,
709 const char *lvalue,
710 int ltype,
711 const char *rvalue,
712 void *data,
713 void *userdata) {
714
715 uint32_t k, *v = data;
716 int r;
717
718 if (isempty(rvalue)) {
719 *v = 0;
720 return 0;
721 }
722
723 r = safe_atou32(rvalue, &k);
724 if (r < 0) {
725 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue);
726 return 0;
727 }
728 if (k == 0 || k > 4096) {
729 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s=, ignoring assignment: %s.", lvalue, rvalue);
730 return 0;
731 }
732
733 *v = k;
734 return 0;
735 }
736
737 int config_parse_txqueuelen(
738 const char *unit,
739 const char *filename,
740 unsigned line,
741 const char *section,
742 unsigned section_line,
743 const char *lvalue,
744 int ltype,
745 const char *rvalue,
746 void *data,
747 void *userdata) {
748
749 uint32_t k, *v = data;
750 int r;
751
752 if (isempty(rvalue)) {
753 *v = UINT32_MAX;
754 return 0;
755 }
756
757 r = safe_atou32(rvalue, &k);
758 if (r < 0) {
759 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue);
760 return 0;
761 }
762 if (k == UINT32_MAX) {
763 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s=, ignoring assignment: %s.", lvalue, rvalue);
764 return 0;
765 }
766
767 *v = k;
768 return 0;
769 }
770
771 static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
772 [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
773 [MAC_ADDRESS_POLICY_RANDOM] = "random",
774 [MAC_ADDRESS_POLICY_NONE] = "none",
775 };
776
777 DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
778 DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(
779 config_parse_mac_address_policy,
780 mac_address_policy,
781 MACAddressPolicy,
782 MAC_ADDRESS_POLICY_NONE,
783 "Failed to parse MAC address policy");
784
785 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
786 [NAMEPOLICY_KERNEL] = "kernel",
787 [NAMEPOLICY_KEEP] = "keep",
788 [NAMEPOLICY_DATABASE] = "database",
789 [NAMEPOLICY_ONBOARD] = "onboard",
790 [NAMEPOLICY_SLOT] = "slot",
791 [NAMEPOLICY_PATH] = "path",
792 [NAMEPOLICY_MAC] = "mac",
793 };
794
795 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
796 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
797 _NAMEPOLICY_INVALID,
798 "Failed to parse interface name policy");
799
800 static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
801 [NAMEPOLICY_DATABASE] = "database",
802 [NAMEPOLICY_ONBOARD] = "onboard",
803 [NAMEPOLICY_SLOT] = "slot",
804 [NAMEPOLICY_PATH] = "path",
805 [NAMEPOLICY_MAC] = "mac",
806 };
807
808 DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);
809 DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy, alternative_names_policy, NamePolicy,
810 _NAMEPOLICY_INVALID,
811 "Failed to parse alternative names policy");