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