]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/link-config.c
pkgconfig: define variables relative to ${prefix}/${rootprefix}/${sysconfdir}
[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
73 free(link);
74 }
75
76 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
77
78 static void link_configs_free(link_config_ctx *ctx) {
79 link_config *link, *link_next;
80
81 if (!ctx)
82 return;
83
84 LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
85 link_config_free(link);
86 }
87
88 void link_config_ctx_free(link_config_ctx *ctx) {
89 if (!ctx)
90 return;
91
92 safe_close(ctx->ethtool_fd);
93
94 sd_netlink_unref(ctx->rtnl);
95
96 link_configs_free(ctx);
97
98 free(ctx);
99
100 return;
101 }
102
103 DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
104
105 int link_config_ctx_new(link_config_ctx **ret) {
106 _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
107
108 if (!ret)
109 return -EINVAL;
110
111 ctx = new0(link_config_ctx, 1);
112 if (!ctx)
113 return -ENOMEM;
114
115 LIST_HEAD_INIT(ctx->links);
116
117 ctx->ethtool_fd = -1;
118
119 ctx->enable_name_policy = true;
120
121 *ret = TAKE_PTR(ctx);
122
123 return 0;
124 }
125
126 static int load_link(link_config_ctx *ctx, const char *filename) {
127 _cleanup_(link_config_freep) link_config *link = NULL;
128 _cleanup_fclose_ FILE *file = NULL;
129 int i;
130 int r;
131
132 assert(ctx);
133 assert(filename);
134
135 file = fopen(filename, "re");
136 if (!file) {
137 if (errno == ENOENT)
138 return 0;
139 else
140 return -errno;
141 }
142
143 if (null_or_empty_fd(fileno(file))) {
144 log_debug("Skipping empty file: %s", filename);
145 return 0;
146 }
147
148 link = new0(link_config, 1);
149 if (!link)
150 return log_oom();
151
152 link->mac_policy = _MACPOLICY_INVALID;
153 link->wol = _WOL_INVALID;
154 link->duplex = _DUP_INVALID;
155 link->port = _NET_DEV_PORT_INVALID;
156 link->autonegotiation = -1;
157
158 for (i = 0; i < (int)ELEMENTSOF(link->features); i++)
159 link->features[i] = -1;
160
161 r = config_parse(NULL, filename, file,
162 "Match\0Link\0Ethernet\0",
163 config_item_perf_lookup, link_config_gperf_lookup,
164 CONFIG_PARSE_WARN, link);
165 if (r < 0)
166 return r;
167 else
168 log_debug("Parsed configuration file %s", filename);
169
170 if (link->speed > UINT_MAX)
171 return -ERANGE;
172
173 link->filename = strdup(filename);
174 if (!link->filename)
175 return log_oom();
176
177 LIST_PREPEND(links, ctx->links, link);
178 link = NULL;
179
180 return 0;
181 }
182
183 static bool enable_name_policy(void) {
184 bool b;
185
186 return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
187 }
188
189 int link_config_load(link_config_ctx *ctx) {
190 _cleanup_strv_free_ char **files;
191 char **f;
192 int r;
193
194 link_configs_free(ctx);
195
196 if (!enable_name_policy()) {
197 ctx->enable_name_policy = false;
198 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
199 }
200
201 /* update timestamp */
202 paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
203
204 r = conf_files_list_strv(&files, ".link", NULL, 0, link_dirs);
205 if (r < 0)
206 return log_error_errno(r, "failed to enumerate link files: %m");
207
208 STRV_FOREACH_BACKWARDS(f, files) {
209 r = load_link(ctx, *f);
210 if (r < 0)
211 return r;
212 }
213
214 return 0;
215 }
216
217 bool link_config_should_reload(link_config_ctx *ctx) {
218 return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
219 }
220
221 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
222 link_config *link;
223
224 assert(ctx);
225 assert(device);
226 assert(ret);
227
228 LIST_FOREACH(links, link, ctx->links) {
229 const char *address = NULL, *id_path = NULL, *parent_driver = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
230 sd_device *parent;
231
232 (void) sd_device_get_sysattr_value(device, "address", &address);
233 (void) sd_device_get_property_value(device, "ID_PATH", &id_path);
234 if (sd_device_get_parent(device, &parent) >= 0)
235 (void) sd_device_get_driver(parent, &parent_driver);
236 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver);
237 (void) sd_device_get_devtype(device, &devtype);
238 (void) sd_device_get_sysname(device, &sysname);
239
240 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
241 link->match_type, link->match_name, link->match_host,
242 link->match_virt, link->match_kernel_cmdline,
243 link->match_kernel_version, link->match_arch,
244 address ? ether_aton(address) : NULL,
245 id_path,
246 parent_driver,
247 id_net_driver,
248 devtype,
249 sysname)) {
250 if (link->match_name) {
251 unsigned char name_assign_type = NET_NAME_UNKNOWN;
252 const char *attr_value;
253
254 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr_value) >= 0)
255 (void) safe_atou8(attr_value, &name_assign_type);
256
257 if (name_assign_type == NET_NAME_ENUM) {
258 log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
259 link->filename, sysname);
260 *ret = link;
261
262 return 0;
263 } else if (name_assign_type == NET_NAME_RENAMED) {
264 log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
265 link->filename, sysname);
266
267 continue;
268 }
269 }
270
271 log_debug("Config file %s applies to device %s",
272 link->filename, sysname);
273
274 *ret = link;
275
276 return 0;
277 }
278 }
279
280 *ret = NULL;
281
282 return -ENOENT;
283 }
284
285 static bool mac_is_random(sd_device *device) {
286 const char *s;
287 unsigned type;
288 int r;
289
290 /* if we can't get the assign type, assume it is not random */
291 if (sd_device_get_sysattr_value(device, "addr_assign_type", &s) < 0)
292 return false;
293
294 r = safe_atou(s, &type);
295 if (r < 0)
296 return false;
297
298 return type == NET_ADDR_RANDOM;
299 }
300
301 static bool should_rename(sd_device *device, bool respect_predictable) {
302 const char *s;
303 unsigned type;
304 int r;
305
306 /* if we can't get the assgin type, assume we should rename */
307 if (sd_device_get_sysattr_value(device, "name_assign_type", &s) < 0)
308 return true;
309
310 r = safe_atou(s, &type);
311 if (r < 0)
312 return true;
313
314 switch (type) {
315 case NET_NAME_PREDICTABLE:
316 /* the kernel claims to have given a predictable name */
317 if (respect_predictable)
318 return false;
319 _fallthrough_;
320 default:
321 /* the name is known to be bad, or of an unknown type */
322 return true;
323 }
324 }
325
326 static int get_mac(sd_device *device, bool want_random,
327 struct ether_addr *mac) {
328 int r;
329
330 if (want_random)
331 random_bytes(mac->ether_addr_octet, ETH_ALEN);
332 else {
333 uint64_t result;
334
335 r = net_get_unique_predictable_data(device, &result);
336 if (r < 0)
337 return r;
338
339 assert_cc(ETH_ALEN <= sizeof(result));
340 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
341 }
342
343 /* see eth_random_addr in the kernel */
344 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
345 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
346
347 return 0;
348 }
349
350 int link_config_apply(link_config_ctx *ctx, link_config *config,
351 sd_device *device, const char **name) {
352 bool respect_predictable = false;
353 struct ether_addr generated_mac;
354 struct ether_addr *mac = NULL;
355 const char *new_name = NULL;
356 const char *old_name;
357 unsigned speed;
358 int r, ifindex;
359
360 assert(ctx);
361 assert(config);
362 assert(device);
363 assert(name);
364
365 r = sd_device_get_sysname(device, &old_name);
366 if (r < 0)
367 return r;
368
369 r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name, config);
370 if (r < 0) {
371
372 if (config->port != _NET_DEV_PORT_INVALID)
373 log_warning_errno(r, "Could not set port (%s) of %s: %m", port_to_string(config->port), old_name);
374
375 if (config->advertise)
376 log_warning_errno(r, "Could not set advertise mode to 0x%X: %m", config->advertise);
377
378 if (config->speed) {
379
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");