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