]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/link-config.c
Merge pull request #10408 from keszybz/analyze-cat-presets
[thirdparty/systemd.git] / src / udev / net / link-config.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netinet/ether.h>
4
5 #include "sd-device.h"
6 #include "sd-netlink.h"
7
8 #include "alloc-util.h"
9 #include "conf-files.h"
10 #include "conf-parser.h"
11 #include "def.h"
12 #include "device-util.h"
13 #include "ethtool-util.h"
14 #include "fd-util.h"
15 #include "link-config.h"
16 #include "log.h"
17 #include "missing_network.h"
18 #include "naming-scheme.h"
19 #include "netlink-util.h"
20 #include "network-internal.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "proc-cmdline.h"
24 #include "random-util.h"
25 #include "stat-util.h"
26 #include "string-table.h"
27 #include "string-util.h"
28 #include "strv.h"
29 #include "util.h"
30
31 struct link_config_ctx {
32 LIST_HEAD(link_config, links);
33
34 int ethtool_fd;
35
36 bool enable_name_policy;
37
38 sd_netlink *rtnl;
39
40 usec_t network_dirs_ts_usec;
41 };
42
43 static void link_config_free(link_config *link) {
44 if (!link)
45 return;
46
47 free(link->filename);
48
49 set_free_free(link->match_mac);
50 strv_free(link->match_path);
51 strv_free(link->match_driver);
52 strv_free(link->match_type);
53 free(link->match_name);
54 free(link->match_host);
55 free(link->match_virt);
56 free(link->match_kernel_cmdline);
57 free(link->match_kernel_version);
58 free(link->match_arch);
59
60 free(link->description);
61 free(link->mac);
62 free(link->name_policy);
63 free(link->name);
64 free(link->alias);
65
66 free(link);
67 }
68
69 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
70
71 static void link_configs_free(link_config_ctx *ctx) {
72 link_config *link, *link_next;
73
74 if (!ctx)
75 return;
76
77 LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
78 link_config_free(link);
79 }
80
81 void link_config_ctx_free(link_config_ctx *ctx) {
82 if (!ctx)
83 return;
84
85 safe_close(ctx->ethtool_fd);
86
87 sd_netlink_unref(ctx->rtnl);
88
89 link_configs_free(ctx);
90
91 free(ctx);
92
93 return;
94 }
95
96 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
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 static int load_link(link_config_ctx *ctx, const char *filename) {
120 _cleanup_(link_config_freep) link_config *link = NULL;
121 _cleanup_fclose_ FILE *file = NULL;
122 int i;
123 int r;
124
125 assert(ctx);
126 assert(filename);
127
128 file = fopen(filename, "re");
129 if (!file) {
130 if (errno == ENOENT)
131 return 0;
132 else
133 return -errno;
134 }
135
136 if (null_or_empty_fd(fileno(file))) {
137 log_debug("Skipping empty file: %s", filename);
138 return 0;
139 }
140
141 link = new0(link_config, 1);
142 if (!link)
143 return log_oom();
144
145 link->mac_policy = _MACPOLICY_INVALID;
146 link->wol = _WOL_INVALID;
147 link->duplex = _DUP_INVALID;
148 link->port = _NET_DEV_PORT_INVALID;
149 link->autonegotiation = -1;
150
151 for (i = 0; i < (int)ELEMENTSOF(link->features); i++)
152 link->features[i] = -1;
153
154 r = config_parse(NULL, filename, file,
155 "Match\0Link\0Ethernet\0",
156 config_item_perf_lookup, link_config_gperf_lookup,
157 CONFIG_PARSE_WARN, link);
158 if (r < 0)
159 return r;
160 else
161 log_debug("Parsed configuration file %s", filename);
162
163 if (link->speed > UINT_MAX)
164 return -ERANGE;
165
166 link->filename = strdup(filename);
167 if (!link->filename)
168 return log_oom();
169
170 LIST_PREPEND(links, ctx->links, link);
171 link = NULL;
172
173 return 0;
174 }
175
176 static bool enable_name_policy(void) {
177 bool b;
178
179 return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
180 }
181
182 static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
183 const char *s;
184 int r;
185
186 r = sd_device_get_sysattr_value(device, attr, &s);
187 if (r < 0)
188 return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
189
190 r = safe_atou(s, type);
191 if (r < 0)
192 return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
193
194 log_device_debug(device, "Device has %s=%u", attr, *type);
195 return 0;
196 }
197
198 int link_config_load(link_config_ctx *ctx) {
199 _cleanup_strv_free_ char **files;
200 char **f;
201 int r;
202
203 link_configs_free(ctx);
204
205 if (!enable_name_policy()) {
206 ctx->enable_name_policy = false;
207 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
208 }
209
210 /* update timestamp */
211 paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
212
213 r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
214 if (r < 0)
215 return log_error_errno(r, "failed to enumerate link files: %m");
216
217 STRV_FOREACH_BACKWARDS(f, files) {
218 r = load_link(ctx, *f);
219 if (r < 0)
220 return r;
221 }
222
223 return 0;
224 }
225
226 bool link_config_should_reload(link_config_ctx *ctx) {
227 return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
228 }
229
230 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
231 link_config *link;
232
233 assert(ctx);
234 assert(device);
235 assert(ret);
236
237 LIST_FOREACH(links, link, ctx->links) {
238 const char *address = NULL, *id_path = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
239
240 (void) sd_device_get_sysattr_value(device, "address", &address);
241 (void) sd_device_get_property_value(device, "ID_PATH", &id_path);
242 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver);
243 (void) sd_device_get_devtype(device, &devtype);
244 (void) sd_device_get_sysname(device, &sysname);
245
246 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
247 link->match_type, link->match_name, link->match_host,
248 link->match_virt, link->match_kernel_cmdline,
249 link->match_kernel_version, link->match_arch,
250 address ? ether_aton(address) : NULL,
251 id_path,
252 id_net_driver,
253 devtype,
254 sysname)) {
255 if (link->match_name) {
256 unsigned name_assign_type = NET_NAME_UNKNOWN;
257
258 (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
259
260 if (name_assign_type == NET_NAME_ENUM) {
261 log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
262 link->filename, sysname);
263 *ret = link;
264
265 return 0;
266 } else if (name_assign_type == NET_NAME_RENAMED) {
267 log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
268 link->filename, sysname);
269
270 continue;
271 }
272 }
273
274 log_debug("Config file %s applies to device %s",
275 link->filename, sysname);
276
277 *ret = link;
278 return 0;
279 }
280 }
281
282 *ret = NULL;
283 return -ENOENT;
284 }
285
286 static int get_mac(sd_device *device, MACPolicy policy, struct ether_addr *mac) {
287 unsigned addr_type;
288 bool want_random = policy == MACPOLICY_RANDOM;
289 int r;
290
291 assert(IN_SET(policy, MACPOLICY_RANDOM, MACPOLICY_PERSISTENT));
292
293 r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
294 if (r < 0)
295 return r;
296 switch (addr_type) {
297 case NET_ADDR_SET:
298 return log_device_debug(device, "MAC on the device already set by userspace");
299 case NET_ADDR_STOLEN:
300 return log_device_debug(device, "MAC on the device already set based on another device");
301 case NET_ADDR_RANDOM:
302 case NET_ADDR_PERM:
303 break;
304 default:
305 return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
306 }
307
308 if (want_random == (addr_type == NET_ADDR_RANDOM))
309 return log_device_debug(device, "MAC on the device already matches policy *%s*",
310 mac_policy_to_string(policy));
311
312 if (want_random) {
313 log_device_debug(device, "Using random bytes to generate MAC");
314 random_bytes(mac->ether_addr_octet, ETH_ALEN);
315 } else {
316 uint64_t result;
317
318 r = net_get_unique_predictable_data(device, &result);
319 if (r < 0)
320 return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
321
322 assert_cc(ETH_ALEN <= sizeof(result));
323 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
324 }
325
326 /* see eth_random_addr in the kernel */
327 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
328 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
329 return 1;
330 }
331
332 int link_config_apply(link_config_ctx *ctx, link_config *config,
333 sd_device *device, const char **name) {
334 struct ether_addr generated_mac;
335 struct ether_addr *mac = NULL;
336 const char *new_name = NULL;
337 const char *old_name;
338 unsigned speed, name_type = NET_NAME_UNKNOWN;
339 NamePolicy policy;
340 int r, ifindex;
341
342 assert(ctx);
343 assert(config);
344 assert(device);
345 assert(name);
346
347 r = sd_device_get_sysname(device, &old_name);
348 if (r < 0)
349 return r;
350
351 r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name, config);
352 if (r < 0) {
353
354 if (config->port != _NET_DEV_PORT_INVALID)
355 log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
356
357 if (!eqzero(config->advertise))
358 log_warning_errno(r, "Could not set advertise mode: %m"); /* TODO: include modes in the log message. */
359
360 if (config->speed) {
361 speed = DIV_ROUND_UP(config->speed, 1000000);
362 if (r == -EOPNOTSUPP) {
363 r = ethtool_set_speed(&ctx->ethtool_fd, old_name, speed, config->duplex);
364 if (r < 0)
365 log_warning_errno(r, "Could not set speed of %s to %u Mbps: %m", old_name, speed);
366 }
367 }
368
369 if (config->duplex !=_DUP_INVALID)
370 log_warning_errno(r, "Could not set duplex of %s to (%s): %m", old_name, duplex_to_string(config->duplex));
371 }
372
373 r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
374 if (r < 0)
375 log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
376 old_name, wol_to_string(config->wol));
377
378 r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
379 if (r < 0)
380 log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
381
382 if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
383 r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
384 if (r < 0)
385 log_warning_errno(r, "Could not set channels of %s: %m", old_name);
386 }
387
388 r = sd_device_get_ifindex(device, &ifindex);
389 if (r < 0)
390 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
391
392
393 (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
394
395 if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
396 && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
397 log_device_debug(device, "Device already has a name given by userspace, not renaming.");
398 goto no_rename;
399 }
400
401 if (ctx->enable_name_policy && config->name_policy)
402 for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
403 policy = *p;
404
405 switch (policy) {
406 case NAMEPOLICY_KERNEL:
407 if (name_type != NET_NAME_PREDICTABLE)
408 continue;
409
410 /* The kernel claims to have given a predictable name, keep it. */
411 log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
412 name_policy_to_string(policy));
413 goto no_rename;
414 case NAMEPOLICY_KEEP:
415 if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
416 continue;
417
418 log_device_debug(device, "Policy *%s*: keeping existing userspace name",
419 name_policy_to_string(policy));
420 goto no_rename;
421 case NAMEPOLICY_DATABASE:
422 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
423 break;
424 case NAMEPOLICY_ONBOARD:
425 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
426 break;
427 case NAMEPOLICY_SLOT:
428 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
429 break;
430 case NAMEPOLICY_PATH:
431 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
432 break;
433 case NAMEPOLICY_MAC:
434 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
435 break;
436 default:
437 assert_not_reached("invalid policy");
438 }
439 }
440
441 if (new_name)
442 log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
443 else if (config->name) {
444 new_name = config->name;
445 log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
446 } else
447 log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
448 no_rename:
449
450 if (IN_SET(config->mac_policy, MACPOLICY_PERSISTENT, MACPOLICY_RANDOM)) {
451 if (get_mac(device, config->mac_policy, &generated_mac) > 0)
452 mac = &generated_mac;
453 } else
454 mac = config->mac;
455
456 r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
457 if (r < 0)
458 return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
459
460 *name = new_name;
461
462 return 0;
463 }
464
465 int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
466 const char *name;
467 char *driver = NULL;
468 int r;
469
470 r = sd_device_get_sysname(device, &name);
471 if (r < 0)
472 return r;
473
474 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
475 if (r < 0)
476 return r;
477
478 *ret = driver;
479 return 0;
480 }
481
482 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
483 [MACPOLICY_PERSISTENT] = "persistent",
484 [MACPOLICY_RANDOM] = "random",
485 [MACPOLICY_NONE] = "none",
486 };
487
488 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
489 DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
490 "Failed to parse MAC address policy");
491
492 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
493 [NAMEPOLICY_KERNEL] = "kernel",
494 [NAMEPOLICY_KEEP] = "keep",
495 [NAMEPOLICY_DATABASE] = "database",
496 [NAMEPOLICY_ONBOARD] = "onboard",
497 [NAMEPOLICY_SLOT] = "slot",
498 [NAMEPOLICY_PATH] = "path",
499 [NAMEPOLICY_MAC] = "mac",
500 };
501
502 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
503 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
504 _NAMEPOLICY_INVALID,
505 "Failed to parse interface name policy");