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