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