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