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