]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/net/link-config.c
link-config: make MACAddressPolicy= accept an empty string
[thirdparty/systemd.git] / src / udev / net / link-config.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
af6f0d42 2
01234e1f 3#include <linux/netdevice.h>
43b3a5ef 4#include <netinet/ether.h>
a0b191b7 5#include <unistd.h>
43b3a5ef 6
e5eadf53 7#include "sd-device.h"
07630cea 8#include "sd-netlink.h"
af6f0d42 9
b5efdb8a 10#include "alloc-util.h"
07630cea
LP
11#include "conf-files.h"
12#include "conf-parser.h"
dc0d4078 13#include "def.h"
e0e789c1 14#include "device-private.h"
b220632c 15#include "device-util.h"
a5010333 16#include "ethtool-util.h"
3ffd4af2 17#include "fd-util.h"
07630cea 18#include "link-config.h"
af6f0d42 19#include "log.h"
0a970718 20#include "memory-util.h"
b355d0c9 21#include "netif-naming-scheme.h"
1c4baffc 22#include "netlink-util.h"
c6f7c917 23#include "network-internal.h"
6bedfcbb 24#include "parse-util.h"
b0c82192 25#include "path-lookup.h"
07630cea 26#include "path-util.h"
4e731273 27#include "proc-cmdline.h"
3df3e884 28#include "random-util.h"
8fcde012 29#include "stat-util.h"
8b43440b 30#include "string-table.h"
07630cea
LP
31#include "string-util.h"
32#include "strv.h"
af6f0d42
TG
33
34struct link_config_ctx {
35 LIST_HEAD(link_config, links);
36
a5010333
TG
37 int ethtool_fd;
38
f6194225
TG
39 bool enable_name_policy;
40
1c4baffc 41 sd_netlink *rtnl;
43b3a5ef 42
dc0d4078 43 usec_t network_dirs_ts_usec;
af6f0d42
TG
44};
45
9a4b012e
TG
46static void link_config_free(link_config *link) {
47 if (!link)
48 return;
5b9d4dc0 49
9a4b012e
TG
50 free(link->filename);
51
e90d0374 52 set_free_free(link->match_mac);
4bb7cc82 53 set_free_free(link->match_permanent_mac);
43d60b77
TG
54 strv_free(link->match_path);
55 strv_free(link->match_driver);
56 strv_free(link->match_type);
391f6bc1 57 strv_free(link->match_name);
44005bfb 58 strv_free(link->match_property);
c4f58dea 59 condition_free_list(link->conditions);
9a4b012e
TG
60
61 free(link->description);
62 free(link->mac);
63 free(link->name_policy);
64 free(link->name);
a5053a15 65 strv_free(link->alternative_names);
ef1d2c07 66 free(link->alternative_names_policy);
9a4b012e
TG
67 free(link->alias);
68
69 free(link);
af6f0d42
TG
70}
71
9a4b012e
TG
72DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
73
af6f0d42
TG
74static void link_configs_free(link_config_ctx *ctx) {
75 link_config *link, *link_next;
76
77 if (!ctx)
78 return;
79
9a4b012e
TG
80 LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
81 link_config_free(link);
af6f0d42
TG
82}
83
84void link_config_ctx_free(link_config_ctx *ctx) {
85 if (!ctx)
86 return;
87
03e334a1 88 safe_close(ctx->ethtool_fd);
43b3a5ef 89
1c4baffc 90 sd_netlink_unref(ctx->rtnl);
43b3a5ef 91
af6f0d42
TG
92 link_configs_free(ctx);
93
94 free(ctx);
95
96 return;
97}
98
9a4b012e
TG
99int link_config_ctx_new(link_config_ctx **ret) {
100 _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
101
102 if (!ret)
103 return -EINVAL;
104
105 ctx = new0(link_config_ctx, 1);
106 if (!ctx)
107 return -ENOMEM;
108
109 LIST_HEAD_INIT(ctx->links);
110
111 ctx->ethtool_fd = -1;
112
113 ctx->enable_name_policy = true;
114
1cc6c93a 115 *ret = TAKE_PTR(ctx);
9a4b012e
TG
116
117 return 0;
118}
119
a378400b 120int link_load_one(link_config_ctx *ctx, const char *filename) {
9a4b012e 121 _cleanup_(link_config_freep) link_config *link = NULL;
6e37cd2f 122 _cleanup_fclose_ FILE *file = NULL;
6cdab9f1 123 _cleanup_free_ char *name = NULL;
79a60834 124 size_t i;
af6f0d42
TG
125 int r;
126
187dc6e5
TA
127 assert(ctx);
128 assert(filename);
129
af6f0d42 130 file = fopen(filename, "re");
f2d251cd
YW
131 if (!file)
132 return errno == ENOENT ? 0 : -errno;
af6f0d42 133
ed88bcfb
ZJS
134 if (null_or_empty_fd(fileno(file))) {
135 log_debug("Skipping empty file: %s", filename);
136 return 0;
137 }
138
6cdab9f1
YW
139 name = strdup(filename);
140 if (!name)
141 return -ENOMEM;
142
143 link = new(link_config, 1);
ecb08ec6 144 if (!link)
e8a42907 145 return -ENOMEM;
af6f0d42 146
6cdab9f1
YW
147 *link = (link_config) {
148 .filename = TAKE_PTR(name),
54ed9f88 149 .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
6cdab9f1
YW
150 .wol = _WOL_INVALID,
151 .duplex = _DUP_INVALID,
152 .port = _NET_DEV_PORT_INVALID,
153 .autonegotiation = -1,
a34811e4
YW
154 .rx_flow_control = -1,
155 .tx_flow_control = -1,
156 .autoneg_flow_control = -1,
6cdab9f1 157 };
5fde13d7 158
79a60834 159 for (i = 0; i < ELEMENTSOF(link->features); i++)
cc2ff878 160 link->features[i] = -1;
50725d10 161
e9f3d2d5 162 r = config_parse(NULL, filename, file,
c6b3370a 163 "Match\0Link\0",
e9f3d2d5 164 config_item_perf_lookup, link_config_gperf_lookup,
4f9ff96a
LP
165 CONFIG_PARSE_WARN, link,
166 NULL);
36f822c4 167 if (r < 0)
ecb08ec6 168 return r;
af6f0d42 169
4bb7cc82
YW
170 if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) &&
171 strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
dade7349
ZJS
172 strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions) {
173 log_warning("%s: No valid settings found in the [Match] section, ignoring file. "
174 "To match all interfaces, add OriginalName=* in the [Match] section.",
84ea567e 175 filename);
dade7349
ZJS
176 return 0;
177 }
84ea567e 178
a0b191b7 179 if (!condition_test_list(link->conditions, environ, NULL, NULL, NULL)) {
176d9c0e
YW
180 log_debug("%s: Conditions do not match the system environment, skipping.", filename);
181 return 0;
182 }
183
6cdab9f1 184 log_debug("Parsed configuration file %s", filename);
af6f0d42 185
4b4a6c9b 186 LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
af6f0d42 187 return 0;
af6f0d42
TG
188}
189
f6194225 190static bool enable_name_policy(void) {
1d84ad94 191 bool b;
f6194225 192
1d84ad94 193 return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
f6194225
TG
194}
195
015b097c 196static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
0b189e8f
ZJS
197 const char *s;
198 int r;
199
015b097c 200 r = sd_device_get_sysattr_value(device, attr, &s);
0b189e8f 201 if (r < 0)
015b097c 202 return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
0b189e8f
ZJS
203
204 r = safe_atou(s, type);
205 if (r < 0)
015b097c 206 return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
0b189e8f 207
015b097c 208 log_device_debug(device, "Device has %s=%u", attr, *type);
0b189e8f
ZJS
209 return 0;
210}
211
af6f0d42 212int link_config_load(link_config_ctx *ctx) {
b9c54c46 213 _cleanup_strv_free_ char **files = NULL;
edf029b7 214 char **f;
a39f92d3 215 int r;
af6f0d42
TG
216
217 link_configs_free(ctx);
218
f6194225
TG
219 if (!enable_name_policy()) {
220 ctx->enable_name_policy = false;
3f85ef0f 221 log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
f6194225
TG
222 }
223
97f2d76d 224 /* update timestamp */
dc0d4078 225 paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
af6f0d42 226
dc0d4078 227 r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
f647962d
MS
228 if (r < 0)
229 return log_error_errno(r, "failed to enumerate link files: %m");
af6f0d42
TG
230
231 STRV_FOREACH_BACKWARDS(f, files) {
a378400b 232 r = link_load_one(ctx, *f);
af6f0d42 233 if (r < 0)
e8a42907 234 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
af6f0d42
TG
235 }
236
237 return 0;
238}
239
240bool link_config_should_reload(link_config_ctx *ctx) {
dc0d4078 241 return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
af6f0d42
TG
242}
243
e5eadf53 244int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
f5767302 245 unsigned name_assign_type = NET_NAME_UNKNOWN;
4bb7cc82 246 struct ether_addr permanent_mac = {};
ef62949a 247 unsigned short iftype = 0;
af6f0d42 248 link_config *link;
4bb7cc82 249 const char *name;
ef62949a 250 int ifindex, r;
af6f0d42 251
3b64e4d4
TG
252 assert(ctx);
253 assert(device);
254 assert(ret);
255
4bb7cc82
YW
256 r = sd_device_get_sysname(device, &name);
257 if (r < 0)
258 return r;
259
ef62949a
YW
260 r = sd_device_get_ifindex(device, &ifindex);
261 if (r < 0)
262 return r;
263
264 r = rtnl_get_link_iftype(&ctx->rtnl, ifindex, &iftype);
265 if (r < 0)
266 return r;
267
4bb7cc82
YW
268 r = ethtool_get_permanent_macaddr(&ctx->ethtool_fd, name, &permanent_mac);
269 if (r < 0)
270 log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
271
f5767302
YW
272 (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
273
af6f0d42 274 LIST_FOREACH(links, link, ctx->links) {
4bb7cc82 275 if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
78404d22 276 link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
c643bda5 277 device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) {
32bc8adc 278
f5767302
YW
279 if (link->match_name && !strv_contains(link->match_name, "*") && name_assign_type == NET_NAME_ENUM)
280 log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.",
281 link->filename);
282 else
283 log_device_debug(device, "Config file %s is applied", link->filename);
32bc8adc 284
ca6038b8 285 *ret = link;
ca6038b8 286 return 0;
af6f0d42
TG
287 }
288 }
289
290 return -ENOENT;
291}
292
2e17fed5
YW
293static int link_config_apply_ethtool_settings(int *ethtool_fd, const link_config *config, sd_device *device) {
294 const char *name;
295 int r;
296
297 assert(ethtool_fd);
298 assert(config);
299 assert(device);
300
301 r = sd_device_get_sysname(device, &name);
302 if (r < 0)
303 return log_device_error_errno(device, r, "Failed to get sysname: %m");
304
305 r = ethtool_set_glinksettings(ethtool_fd, name,
306 config->autonegotiation, config->advertise,
307 config->speed, config->duplex, config->port);
308 if (r < 0) {
309 if (config->port != _NET_DEV_PORT_INVALID)
310 log_device_warning_errno(device, r, "Could not set port '%s', ignoring: %m", port_to_string(config->port));
311
312 if (!eqzero(config->advertise))
313 log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); /* TODO: include modes in the log message. */
314
315 if (config->speed) {
316 unsigned speed = DIV_ROUND_UP(config->speed, 1000000);
317 if (r == -EOPNOTSUPP) {
318 r = ethtool_set_speed(ethtool_fd, name, speed, config->duplex);
319 if (r < 0)
320 log_device_warning_errno(device, r, "Could not set speed to %uMbps, ignoring: %m", speed);
321 }
322 }
323
324 if (config->duplex != _DUP_INVALID)
325 log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", duplex_to_string(config->duplex));
326 }
327
328 r = ethtool_set_wol(ethtool_fd, name, config->wol);
329 if (r < 0)
330 log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m", wol_to_string(config->wol));
331
332 r = ethtool_set_features(ethtool_fd, name, config->features);
333 if (r < 0)
334 log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m");
335
336 if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
337 r = ethtool_set_channels(ethtool_fd, name, &config->channels);
338 if (r < 0)
339 log_device_warning_errno(device, r, "Could not set channels, ignoring: %m");
340 }
341
342 if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
343 r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring);
344 if (r < 0)
345 log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m");
346 }
347
348 if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
349 r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
350 if (r < 0)
351 log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m");
352 }
353
354 return 0;
355}
356
54ed9f88 357static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
015b097c 358 unsigned addr_type;
54ed9f88 359 bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
f1ac7002 360 int r;
16b9b87a 361
54ed9f88 362 assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
3c9b8860 363
015b097c 364 r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
f1ac7002 365 if (r < 0)
015b097c
ZJS
366 return r;
367 switch (addr_type) {
368 case NET_ADDR_SET:
369 return log_device_debug(device, "MAC on the device already set by userspace");
370 case NET_ADDR_STOLEN:
371 return log_device_debug(device, "MAC on the device already set based on another device");
372 case NET_ADDR_RANDOM:
373 case NET_ADDR_PERM:
374 break;
375 default:
09c69eca
YW
376 log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
377 return 0;
015b097c 378 }
04b67d49 379
015b097c
ZJS
380 if (want_random == (addr_type == NET_ADDR_RANDOM))
381 return log_device_debug(device, "MAC on the device already matches policy *%s*",
54ed9f88 382 mac_address_policy_to_string(policy));
16b9b87a 383
015b097c
ZJS
384 if (want_random) {
385 log_device_debug(device, "Using random bytes to generate MAC");
550c8784
LP
386
387 /* We require genuine randomness here, since we want to make sure we won't collide with other
388 * systems booting up at the very same time. We do allow RDRAND however, since this is not
389 * cryptographic key material. */
a745117d
LP
390 r = genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND);
391 if (r < 0)
392 return log_device_error_errno(device, r, "Failed to acquire random data to generate MAC: %m");
015b097c 393 } else {
dbe81cbd 394 uint64_t result;
9bf3b535 395
96848152
ZJS
396 r = net_get_unique_predictable_data(device,
397 naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
398 &result);
16b9b87a 399 if (r < 0)
015b097c 400 return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
16b9b87a 401
96848152 402 log_device_debug(device, "Using generated persistent MAC address");
9bf3b535 403 assert_cc(ETH_ALEN <= sizeof(result));
dbe81cbd 404 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
16b9b87a
TG
405 }
406
407 /* see eth_random_addr in the kernel */
3c9b8860
TG
408 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
409 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
015b097c 410 return 1;
16b9b87a
TG
411}
412
2e17fed5
YW
413static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config *config, sd_device *device) {
414 struct ether_addr generated_mac, *mac = NULL;
415 int ifindex, r;
af6f0d42 416
2e17fed5 417 assert(rtnl);
3e137a1b
TG
418 assert(config);
419 assert(device);
3e137a1b 420
2e17fed5 421 r = sd_device_get_ifindex(device, &ifindex);
e5eadf53 422 if (r < 0)
2e17fed5 423 return log_device_error_errno(device, r, "Could not find ifindex: %m");
af6f0d42 424
2e17fed5
YW
425 if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
426 if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
427 mac = &generated_mac;
428 } else
429 mac = config->mac;
af6f0d42 430
2e17fed5 431 r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, config->mtu);
50725d10 432 if (r < 0)
2e17fed5 433 log_device_warning_errno(device, r, "Could not set Alias=, MACAddress= or MTU=, ignoring: %m");
50725d10 434
2e17fed5
YW
435 return 0;
436}
224ded67 437
2e17fed5
YW
438static int link_config_generate_new_name(const link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
439 unsigned name_type = NET_NAME_UNKNOWN;
440 const char *new_name = NULL;
441 NamePolicy policy;
442 int r;
a34811e4 443
2e17fed5
YW
444 assert(ctx);
445 assert(config);
446 assert(device);
447 assert(ret_name);
43b3a5ef 448
015b097c 449 (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
0b189e8f 450
73d2bb08
ZJS
451 if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
452 && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
453 log_device_debug(device, "Device already has a name given by userspace, not renaming.");
454 goto no_rename;
455 }
456
0b189e8f 457 if (ctx->enable_name_policy && config->name_policy)
78f8849f 458 for (NamePolicy *p = config->name_policy; *p != _NAMEPOLICY_INVALID; p++) {
0b189e8f
ZJS
459 policy = *p;
460
461 switch (policy) {
462 case NAMEPOLICY_KERNEL:
463 if (name_type != NET_NAME_PREDICTABLE)
464 continue;
465
466 /* The kernel claims to have given a predictable name, keep it. */
467 log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
468 name_policy_to_string(policy));
469 goto no_rename;
3907446f
ZJS
470 case NAMEPOLICY_KEEP:
471 if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
472 continue;
473
474 log_device_debug(device, "Policy *%s*: keeping existing userspace name",
475 name_policy_to_string(policy));
476 goto no_rename;
0b189e8f
ZJS
477 case NAMEPOLICY_DATABASE:
478 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
479 break;
480 case NAMEPOLICY_ONBOARD:
481 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
482 break;
483 case NAMEPOLICY_SLOT:
484 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
485 break;
486 case NAMEPOLICY_PATH:
487 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
488 break;
489 case NAMEPOLICY_MAC:
490 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
491 break;
492 default:
493 assert_not_reached("invalid policy");
5fde13d7 494 }
78f8849f
YW
495 if (ifname_valid(new_name))
496 break;
daeb71a3 497 }
daeb71a3 498
2e17fed5 499 if (new_name) {
0b189e8f 500 log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
2e17fed5
YW
501 *ret_name = new_name;
502 return 0;
503 }
04b67d49 504
2e17fed5
YW
505 if (config->name) {
506 log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name);
507 *ret_name = config->name;
508 return 0;
509 }
16b9b87a 510
2e17fed5
YW
511 log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
512no_rename:
513 r = sd_device_get_sysname(device, ret_name);
f647962d 514 if (r < 0)
2e17fed5
YW
515 return log_device_error_errno(device, r, "Failed to get sysname: %m");
516
517 return 0;
518}
519
520static int link_config_apply_alternative_names(sd_netlink **rtnl, const link_config *config, sd_device *device, const char *new_name) {
521 _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
522 const char *current_name;
523 int ifindex, r;
524
525 assert(rtnl);
526 assert(config);
527 assert(device);
528
529 r = sd_device_get_sysname(device, &current_name);
530 if (r < 0)
531 return log_device_error_errno(device, r, "Failed to get sysname: %m");
532
533 r = sd_device_get_ifindex(device, &ifindex);
534 if (r < 0)
535 return log_device_error_errno(device, r, "Could not find ifindex: %m");
43b3a5ef 536
ef1d2c07
YW
537 if (config->alternative_names) {
538 altnames = strv_copy(config->alternative_names);
539 if (!altnames)
540 return log_oom();
541 }
542
543 if (config->alternative_names_policy)
544 for (NamePolicy *p = config->alternative_names_policy; *p != _NAMEPOLICY_INVALID; p++) {
61fd7d67 545 const char *n = NULL;
ef1d2c07
YW
546
547 switch (*p) {
548 case NAMEPOLICY_DATABASE:
549 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &n);
550 break;
551 case NAMEPOLICY_ONBOARD:
552 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &n);
553 break;
554 case NAMEPOLICY_SLOT:
555 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &n);
556 break;
557 case NAMEPOLICY_PATH:
558 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &n);
559 break;
560 case NAMEPOLICY_MAC:
561 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &n);
562 break;
563 default:
564 assert_not_reached("invalid policy");
565 }
566 if (!isempty(n)) {
567 r = strv_extend(&altnames, n);
568 if (r < 0)
569 return log_oom();
570 }
571 }
572
573 if (new_name)
574 strv_remove(altnames, new_name);
2e17fed5 575 strv_remove(altnames, current_name);
97fdae33 576
2e17fed5 577 r = rtnl_get_link_alternative_names(rtnl, ifindex, &current_altnames);
97fdae33 578 if (r < 0)
2e17fed5 579 log_device_debug_errno(device, r, "Failed to get alternative names, ignoring: %m");
97fdae33
YW
580
581 char **p;
582 STRV_FOREACH(p, current_altnames)
583 strv_remove(altnames, *p);
584
ef1d2c07 585 strv_uniq(altnames);
4d016e96 586 strv_sort(altnames);
2e17fed5
YW
587 r = rtnl_set_link_alternative_names(rtnl, ifindex, altnames);
588 if (r < 0)
589 log_device_full_errno(device, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
590 "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
591
592 return 0;
593}
a5053a15 594
2e17fed5
YW
595int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) {
596 const char *new_name;
e0e789c1 597 DeviceAction a;
2e17fed5
YW
598 int r;
599
600 assert(ctx);
601 assert(config);
602 assert(device);
603 assert(ret_name);
604
e0e789c1
YW
605 r = device_get_action(device, &a);
606 if (r < 0)
607 return log_device_error_errno(device, r, "Failed to get ACTION= property: %m");
608
609 if (!IN_SET(a, DEVICE_ACTION_ADD, DEVICE_ACTION_BIND, DEVICE_ACTION_MOVE)) {
610 log_device_debug(device, "Skipping to apply .link settings on '%s' uevent.", device_action_to_string(a));
611
612 r = sd_device_get_sysname(device, ret_name);
613 if (r < 0)
614 return log_device_error_errno(device, r, "Failed to get sysname: %m");
615
616 return 0;
617 }
618
2e17fed5
YW
619 r = link_config_apply_ethtool_settings(&ctx->ethtool_fd, config, device);
620 if (r < 0)
621 return r;
622
623 r = link_config_apply_rtnl_settings(&ctx->rtnl, config, device);
624 if (r < 0)
625 return r;
626
e0e789c1
YW
627 if (a == DEVICE_ACTION_MOVE) {
628 log_device_debug(device, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", device_action_to_string(a));
629
630 r = sd_device_get_sysname(device, &new_name);
631 if (r < 0)
632 return log_device_error_errno(device, r, "Failed to get sysname: %m");
633 } else {
634 r = link_config_generate_new_name(ctx, config, device, &new_name);
635 if (r < 0)
636 return r;
637 }
2e17fed5
YW
638
639 r = link_config_apply_alternative_names(&ctx->rtnl, config, device, new_name);
640 if (r < 0)
641 return r;
d95b83b8 642
2e17fed5 643 *ret_name = new_name;
af6f0d42
TG
644 return 0;
645}
be32eb9b 646
e5eadf53 647int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
847a8a5f 648 const char *name;
a7f7d1bd 649 char *driver = NULL;
847a8a5f
TG
650 int r;
651
e5eadf53
YW
652 r = sd_device_get_sysname(device, &name);
653 if (r < 0)
654 return r;
847a8a5f 655
aedca892 656 r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
847a8a5f
TG
657 if (r < 0)
658 return r;
659
660 *ret = driver;
661 return 0;
662}
663
54ed9f88
ZJS
664static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
665 [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
666 [MAC_ADDRESS_POLICY_RANDOM] = "random",
667 [MAC_ADDRESS_POLICY_NONE] = "none",
be32eb9b
TG
668};
669
54ed9f88 670DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
d03cb6b8
YW
671DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(
672 config_parse_mac_address_policy,
673 mac_address_policy,
674 MACAddressPolicy,
675 MAC_ADDRESS_POLICY_NONE,
676 "Failed to parse MAC address policy");
be32eb9b 677
2c5859af 678static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
04b67d49 679 [NAMEPOLICY_KERNEL] = "kernel",
3907446f 680 [NAMEPOLICY_KEEP] = "keep",
e51660ae 681 [NAMEPOLICY_DATABASE] = "database",
be32eb9b
TG
682 [NAMEPOLICY_ONBOARD] = "onboard",
683 [NAMEPOLICY_SLOT] = "slot",
684 [NAMEPOLICY_PATH] = "path",
3907446f 685 [NAMEPOLICY_MAC] = "mac",
be32eb9b
TG
686};
687
688DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
464cf22f
TG
689DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
690 _NAMEPOLICY_INVALID,
691 "Failed to parse interface name policy");
ef1d2c07
YW
692
693static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
694 [NAMEPOLICY_DATABASE] = "database",
695 [NAMEPOLICY_ONBOARD] = "onboard",
696 [NAMEPOLICY_SLOT] = "slot",
697 [NAMEPOLICY_PATH] = "path",
698 [NAMEPOLICY_MAC] = "mac",
699};
700
701DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);
702DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy, alternative_names_policy, NamePolicy,
703 _NAMEPOLICY_INVALID,
704 "Failed to parse alternative names policy");