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