]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/link-config.c
ethtool: add several new link modes
[thirdparty/systemd.git] / src / udev / net / link-config.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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-util.h"
15 #include "ethtool-util.h"
16 #include "fd-util.h"
17 #include "link-config.h"
18 #include "log.h"
19 #include "memory-util.h"
20 #include "netif-naming-scheme.h"
21 #include "netlink-util.h"
22 #include "network-internal.h"
23 #include "parse-util.h"
24 #include "path-lookup.h"
25 #include "path-util.h"
26 #include "proc-cmdline.h"
27 #include "random-util.h"
28 #include "stat-util.h"
29 #include "string-table.h"
30 #include "string-util.h"
31 #include "strv.h"
32
33 struct link_config_ctx {
34 LIST_HEAD(link_config, links);
35
36 int ethtool_fd;
37
38 bool enable_name_policy;
39
40 sd_netlink *rtnl;
41
42 usec_t network_dirs_ts_usec;
43 };
44
45 static void link_config_free(link_config *link) {
46 if (!link)
47 return;
48
49 free(link->filename);
50
51 set_free_free(link->match_mac);
52 set_free_free(link->match_permanent_mac);
53 strv_free(link->match_path);
54 strv_free(link->match_driver);
55 strv_free(link->match_type);
56 strv_free(link->match_name);
57 strv_free(link->match_property);
58 condition_free_list(link->conditions);
59
60 free(link->description);
61 free(link->mac);
62 free(link->name_policy);
63 free(link->name);
64 strv_free(link->alternative_names);
65 free(link->alternative_names_policy);
66 free(link->alias);
67
68 free(link);
69 }
70
71 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
72
73 static void link_configs_free(link_config_ctx *ctx) {
74 link_config *link, *link_next;
75
76 if (!ctx)
77 return;
78
79 LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
80 link_config_free(link);
81 }
82
83 void link_config_ctx_free(link_config_ctx *ctx) {
84 if (!ctx)
85 return;
86
87 safe_close(ctx->ethtool_fd);
88
89 sd_netlink_unref(ctx->rtnl);
90
91 link_configs_free(ctx);
92
93 free(ctx);
94
95 return;
96 }
97
98 int link_config_ctx_new(link_config_ctx **ret) {
99 _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
100
101 if (!ret)
102 return -EINVAL;
103
104 ctx = new0(link_config_ctx, 1);
105 if (!ctx)
106 return -ENOMEM;
107
108 LIST_HEAD_INIT(ctx->links);
109
110 ctx->ethtool_fd = -1;
111
112 ctx->enable_name_policy = true;
113
114 *ret = TAKE_PTR(ctx);
115
116 return 0;
117 }
118
119 int link_load_one(link_config_ctx *ctx, const char *filename) {
120 _cleanup_(link_config_freep) link_config *link = NULL;
121 _cleanup_fclose_ FILE *file = NULL;
122 _cleanup_free_ char *name = NULL;
123 size_t i;
124 int r;
125
126 assert(ctx);
127 assert(filename);
128
129 file = fopen(filename, "re");
130 if (!file)
131 return errno == ENOENT ? 0 : -errno;
132
133 if (null_or_empty_fd(fileno(file))) {
134 log_debug("Skipping empty file: %s", filename);
135 return 0;
136 }
137
138 name = strdup(filename);
139 if (!name)
140 return -ENOMEM;
141
142 link = new(link_config, 1);
143 if (!link)
144 return -ENOMEM;
145
146 *link = (link_config) {
147 .filename = TAKE_PTR(name),
148 .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
149 .wol = _WOL_INVALID,
150 .duplex = _DUP_INVALID,
151 .port = _NET_DEV_PORT_INVALID,
152 .autonegotiation = -1,
153 .rx_flow_control = -1,
154 .tx_flow_control = -1,
155 .autoneg_flow_control = -1,
156 };
157
158 for (i = 0; i < ELEMENTSOF(link->features); i++)
159 link->features[i] = -1;
160
161 r = config_parse(NULL, filename, file,
162 "Match\0Link\0",
163 config_item_perf_lookup, link_config_gperf_lookup,
164 CONFIG_PARSE_WARN, link,
165 NULL);
166 if (r < 0)
167 return r;
168
169 if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) &&
170 strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
171 strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions) {
172 log_warning("%s: No valid settings found in the [Match] section, ignoring file. "
173 "To match all interfaces, add OriginalName=* in the [Match] section.",
174 filename);
175 return 0;
176 }
177
178 if (!condition_test_list(link->conditions, environ, NULL, NULL, NULL)) {
179 log_debug("%s: Conditions do not match the system environment, skipping.", filename);
180 return 0;
181 }
182
183 log_debug("Parsed configuration file %s", filename);
184
185 LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
186 return 0;
187 }
188
189 static bool enable_name_policy(void) {
190 bool b;
191
192 return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
193 }
194
195 static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
196 const char *s;
197 int r;
198
199 r = sd_device_get_sysattr_value(device, attr, &s);
200 if (r < 0)
201 return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
202
203 r = safe_atou(s, type);
204 if (r < 0)
205 return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
206
207 log_device_debug(device, "Device has %s=%u", attr, *type);
208 return 0;
209 }
210
211 int link_config_load(link_config_ctx *ctx) {
212 _cleanup_strv_free_ char **files = NULL;
213 char **f;
214 int r;
215
216 link_configs_free(ctx);
217
218 if (!enable_name_policy()) {
219 ctx->enable_name_policy = false;
220 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
221 }
222
223 /* update timestamp */
224 paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
225
226 r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
227 if (r < 0)
228 return log_error_errno(r, "failed to enumerate link files: %m");
229
230 STRV_FOREACH_BACKWARDS(f, files) {
231 r = link_load_one(ctx, *f);
232 if (r < 0)
233 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
234 }
235
236 return 0;
237 }
238
239 bool link_config_should_reload(link_config_ctx *ctx) {
240 return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
241 }
242
243 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
244 struct ether_addr permanent_mac = {};
245 unsigned short iftype = 0;
246 link_config *link;
247 const char *name;
248 int ifindex, r;
249
250 assert(ctx);
251 assert(device);
252 assert(ret);
253
254 r = sd_device_get_sysname(device, &name);
255 if (r < 0)
256 return r;
257
258 r = sd_device_get_ifindex(device, &ifindex);
259 if (r < 0)
260 return r;
261
262 r = rtnl_get_link_iftype(&ctx->rtnl, ifindex, &iftype);
263 if (r < 0)
264 return r;
265
266 r = ethtool_get_permanent_macaddr(&ctx->ethtool_fd, name, &permanent_mac);
267 if (r < 0)
268 log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
269
270 LIST_FOREACH(links, link, ctx->links) {
271 if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
272 link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
273 device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) {
274 if (link->match_name && !strv_contains(link->match_name, "*")) {
275 unsigned name_assign_type = NET_NAME_UNKNOWN;
276
277 (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
278
279 if (name_assign_type == NET_NAME_ENUM) {
280 log_device_warning(device, "Config file %s applies to device based on potentially unpredictable interface name",
281 link->filename);
282 *ret = link;
283
284 return 0;
285 } else if (name_assign_type == NET_NAME_RENAMED) {
286 log_device_warning(device, "Config file %s matches device based on renamed interface name, ignoring",
287 link->filename);
288
289 continue;
290 }
291 }
292
293 log_device_debug(device, "Config file %s is applied", link->filename);
294
295 *ret = link;
296 return 0;
297 }
298 }
299
300 *ret = NULL;
301 return -ENOENT;
302 }
303
304 static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
305 unsigned addr_type;
306 bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
307 int r;
308
309 assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
310
311 r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
312 if (r < 0)
313 return r;
314 switch (addr_type) {
315 case NET_ADDR_SET:
316 return log_device_debug(device, "MAC on the device already set by userspace");
317 case NET_ADDR_STOLEN:
318 return log_device_debug(device, "MAC on the device already set based on another device");
319 case NET_ADDR_RANDOM:
320 case NET_ADDR_PERM:
321 break;
322 default:
323 log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
324 return 0;
325 }
326
327 if (want_random == (addr_type == NET_ADDR_RANDOM))
328 return log_device_debug(device, "MAC on the device already matches policy *%s*",
329 mac_address_policy_to_string(policy));
330
331 if (want_random) {
332 log_device_debug(device, "Using random bytes to generate MAC");
333
334 /* We require genuine randomness here, since we want to make sure we won't collide with other
335 * systems booting up at the very same time. We do allow RDRAND however, since this is not
336 * cryptographic key material. */
337 r = genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND);
338 if (r < 0)
339 return log_device_error_errno(device, r, "Failed to acquire random data to generate MAC: %m");
340 } else {
341 uint64_t result;
342
343 r = net_get_unique_predictable_data(device,
344 naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
345 &result);
346 if (r < 0)
347 return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
348
349 log_device_debug(device, "Using generated persistent MAC address");
350 assert_cc(ETH_ALEN <= sizeof(result));
351 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
352 }
353
354 /* see eth_random_addr in the kernel */
355 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
356 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
357 return 1;
358 }
359
360 int link_config_apply(link_config_ctx *ctx, link_config *config,
361 sd_device *device, const char **name) {
362 _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
363 struct ether_addr generated_mac;
364 struct ether_addr *mac = NULL;
365 const char *new_name = NULL;
366 const char *old_name;
367 unsigned speed, name_type = NET_NAME_UNKNOWN;
368 NamePolicy policy;
369 int r, ifindex;
370
371 assert(ctx);
372 assert(config);
373 assert(device);
374 assert(name);
375
376 r = sd_device_get_sysname(device, &old_name);
377 if (r < 0)
378 return r;
379
380 r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name,
381 config->autonegotiation, config->advertise,
382 config->speed, config->duplex, config->port);
383 if (r < 0) {
384
385 if (config->port != _NET_DEV_PORT_INVALID)
386 log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
387
388 if (!eqzero(config->advertise))
389 log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
390
391 if (config->speed) {
392 speed = DIV_ROUND_UP(config->speed, 1000000);
393 if (r == -EOPNOTSUPP) {
394 r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
395 if (r < 0)
396 log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
397 }
398 }
399
400 if (config->duplex != _DUP_INVALID)
401 log_warning_errno(r, "Could not set duplex of %s to %s: %m", old_name, duplex_to_string(config->duplex));
402 }
403
404 r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
405 if (r < 0)
406 log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
407 old_name, wol_to_string(config->wol));
408
409 r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
410 if (r < 0)
411 log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
412
413 if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
414 r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
415 if (r < 0)
416 log_warning_errno(r, "Could not set channels of %s: %m", old_name);
417 }
418
419 if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
420 r = ethtool_set_nic_buffer_size(&ctx->ethtool_fd, old_name, &config->ring);
421 if (r < 0)
422 log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
423 }
424
425 if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
426 r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
427 if (r < 0)
428 log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
429 }
430
431 r = sd_device_get_ifindex(device, &ifindex);
432 if (r < 0)
433 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
434
435 (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
436
437 if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
438 && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
439 log_device_debug(device, "Device already has a name given by userspace, not renaming.");
440 goto no_rename;
441 }
442
443 if (ctx->enable_name_policy && config->name_policy)
444 for (NamePolicy *p = config->name_policy; *p != _NAMEPOLICY_INVALID; p++) {
445 policy = *p;
446
447 switch (policy) {
448 case NAMEPOLICY_KERNEL:
449 if (name_type != NET_NAME_PREDICTABLE)
450 continue;
451
452 /* The kernel claims to have given a predictable name, keep it. */
453 log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
454 name_policy_to_string(policy));
455 goto no_rename;
456 case NAMEPOLICY_KEEP:
457 if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
458 continue;
459
460 log_device_debug(device, "Policy *%s*: keeping existing userspace name",
461 name_policy_to_string(policy));
462 goto no_rename;
463 case NAMEPOLICY_DATABASE:
464 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
465 break;
466 case NAMEPOLICY_ONBOARD:
467 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
468 break;
469 case NAMEPOLICY_SLOT:
470 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
471 break;
472 case NAMEPOLICY_PATH:
473 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
474 break;
475 case NAMEPOLICY_MAC:
476 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
477 break;
478 default:
479 assert_not_reached("invalid policy");
480 }
481 if (ifname_valid(new_name))
482 break;
483 }
484
485 if (new_name)
486 log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
487 else if (config->name) {
488 new_name = config->name;
489 log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
490 } else
491 log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
492 no_rename:
493
494 if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
495 if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
496 mac = &generated_mac;
497 } else
498 mac = config->mac;
499
500 r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
501 if (r < 0)
502 return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
503
504 if (config->alternative_names) {
505 altnames = strv_copy(config->alternative_names);
506 if (!altnames)
507 return log_oom();
508 }
509
510 if (config->alternative_names_policy)
511 for (NamePolicy *p = config->alternative_names_policy; *p != _NAMEPOLICY_INVALID; p++) {
512 const char *n = NULL;
513
514 switch (*p) {
515 case NAMEPOLICY_DATABASE:
516 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &n);
517 break;
518 case NAMEPOLICY_ONBOARD:
519 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &n);
520 break;
521 case NAMEPOLICY_SLOT:
522 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &n);
523 break;
524 case NAMEPOLICY_PATH:
525 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &n);
526 break;
527 case NAMEPOLICY_MAC:
528 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &n);
529 break;
530 default:
531 assert_not_reached("invalid policy");
532 }
533 if (!isempty(n)) {
534 r = strv_extend(&altnames, n);
535 if (r < 0)
536 return log_oom();
537 }
538 }
539
540 if (new_name)
541 strv_remove(altnames, new_name);
542 strv_remove(altnames, old_name);
543
544 r = rtnl_get_link_alternative_names(&ctx->rtnl, ifindex, &current_altnames);
545 if (r < 0)
546 log_debug_errno(r, "Failed to get alternative names on %s, ignoring: %m", old_name);
547
548 char **p;
549 STRV_FOREACH(p, current_altnames)
550 strv_remove(altnames, *p);
551
552 strv_uniq(altnames);
553 strv_sort(altnames);
554 r = rtnl_set_link_alternative_names(&ctx->rtnl, ifindex, altnames);
555 if (r == -EOPNOTSUPP)
556 log_debug_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s, ignoring: %m", old_name);
557 else if (r < 0)
558 return log_warning_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s: %m", old_name);
559
560 *name = new_name;
561
562 return 0;
563 }
564
565 int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
566 const char *name;
567 char *driver = NULL;
568 int r;
569
570 r = sd_device_get_sysname(device, &name);
571 if (r < 0)
572 return r;
573
574 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
575 if (r < 0)
576 return r;
577
578 *ret = driver;
579 return 0;
580 }
581
582 static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
583 [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
584 [MAC_ADDRESS_POLICY_RANDOM] = "random",
585 [MAC_ADDRESS_POLICY_NONE] = "none",
586 };
587
588 DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
589 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_address_policy, mac_address_policy, MACAddressPolicy,
590 "Failed to parse MAC address policy");
591
592 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
593 [NAMEPOLICY_KERNEL] = "kernel",
594 [NAMEPOLICY_KEEP] = "keep",
595 [NAMEPOLICY_DATABASE] = "database",
596 [NAMEPOLICY_ONBOARD] = "onboard",
597 [NAMEPOLICY_SLOT] = "slot",
598 [NAMEPOLICY_PATH] = "path",
599 [NAMEPOLICY_MAC] = "mac",
600 };
601
602 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
603 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
604 _NAMEPOLICY_INVALID,
605 "Failed to parse interface name policy");
606
607 static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
608 [NAMEPOLICY_DATABASE] = "database",
609 [NAMEPOLICY_ONBOARD] = "onboard",
610 [NAMEPOLICY_SLOT] = "slot",
611 [NAMEPOLICY_PATH] = "path",
612 [NAMEPOLICY_MAC] = "mac",
613 };
614
615 DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);
616 DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy, alternative_names_policy, NamePolicy,
617 _NAMEPOLICY_INVALID,
618 "Failed to parse alternative names policy");