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