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