]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/net/link-config.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / udev / net / link-config.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
af6f0d42 2
7b9da386 3#include <linux/netdevice.h>
dc59a151 4#include <net/if_arp.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"
9e2b7763 11#include "arphrd-util.h"
dc59a151 12#include "condition.h"
07630cea
LP
13#include "conf-files.h"
14#include "conf-parser.h"
d3867133 15#include "creds-util.h"
e0e789c1 16#include "device-private.h"
b220632c 17#include "device-util.h"
3e00171d 18#include "escape.h"
dc59a151 19#include "ether-addr-util.h"
a5010333 20#include "ethtool-util.h"
dc59a151 21#include "extract-word.h"
3ffd4af2 22#include "fd-util.h"
d3867133 23#include "fileio.h"
dc59a151 24#include "hashmap.h"
07630cea 25#include "link-config.h"
613701a4 26#include "log-link.h"
0a970718 27#include "memory-util.h"
7e19cc54 28#include "net-condition.h"
dc59a151 29#include "netif-naming-scheme.h"
bd29dfef 30#include "netif-sriov.h"
b5cc5591 31#include "netif-util.h"
1c4baffc 32#include "netlink-util.h"
cd7d732d 33#include "network-util.h"
6bedfcbb 34#include "parse-util.h"
07630cea 35#include "path-util.h"
4e731273 36#include "proc-cmdline.h"
3df3e884 37#include "random-util.h"
dc59a151 38#include "socket-util.h"
046286e8 39#include "specifier.h"
8fcde012 40#include "stat-util.h"
8b43440b 41#include "string-table.h"
07630cea
LP
42#include "string-util.h"
43#include "strv.h"
3e00171d 44#include "udev-builtin.h"
fc27088a 45#include "utf8.h"
af6f0d42 46
046286e8
YW
47static const Specifier link_specifier_table[] = {
48 COMMON_SYSTEM_SPECIFIERS,
49 COMMON_TMP_SPECIFIERS,
50 {}
51};
52
afca7ac1 53struct LinkConfigContext {
418c02c3 54 LIST_HEAD(LinkConfig, configs);
a5010333 55 int ethtool_fd;
bdb2d3c6 56 Hashmap *stats_by_path;
af6f0d42
TG
57};
58
418c02c3
YW
59static LinkConfig* link_config_free(LinkConfig *config) {
60 if (!config)
75db809a 61 return NULL;
5b9d4dc0 62
418c02c3 63 free(config->filename);
a2640646 64 strv_free(config->dropins);
9a4b012e 65
418c02c3
YW
66 net_match_clear(&config->match);
67 condition_free_list(config->conditions);
9a4b012e 68
418c02c3 69 free(config->description);
046286e8
YW
70 strv_free(config->properties);
71 strv_free(config->import_properties);
72 strv_free(config->unset_properties);
418c02c3
YW
73 free(config->name_policy);
74 free(config->name);
75 strv_free(config->alternative_names);
76 free(config->alternative_names_policy);
77 free(config->alias);
78 free(config->wol_password_file);
79 erase_and_free(config->wol_password);
16069d75 80 cpu_set_done(&config->rps_cpu_mask);
9a4b012e 81
d3af116a 82 ordered_hashmap_free(config->sr_iov_by_section);
bd29dfef 83
418c02c3 84 return mfree(config);
af6f0d42
TG
85}
86
ce01c07f 87DEFINE_TRIVIAL_CLEANUP_FUNC(LinkConfig*, link_config_free);
9a4b012e 88
afca7ac1 89static void link_configs_free(LinkConfigContext *ctx) {
af6f0d42
TG
90 if (!ctx)
91 return;
92
bdb2d3c6
YW
93 ctx->stats_by_path = hashmap_free(ctx->stats_by_path);
94
80a226b2 95 LIST_FOREACH(configs, config, ctx->configs)
418c02c3 96 link_config_free(config);
af6f0d42
TG
97}
98
afca7ac1 99LinkConfigContext *link_config_ctx_free(LinkConfigContext *ctx) {
af6f0d42 100 if (!ctx)
75db809a 101 return NULL;
af6f0d42 102
03e334a1 103 safe_close(ctx->ethtool_fd);
af6f0d42 104 link_configs_free(ctx);
75db809a 105 return mfree(ctx);
af6f0d42
TG
106}
107
afca7ac1
YW
108int link_config_ctx_new(LinkConfigContext **ret) {
109 _cleanup_(link_config_ctx_freep) LinkConfigContext *ctx = NULL;
9a4b012e
TG
110
111 if (!ret)
112 return -EINVAL;
113
afca7ac1 114 ctx = new(LinkConfigContext, 1);
9a4b012e
TG
115 if (!ctx)
116 return -ENOMEM;
117
afca7ac1 118 *ctx = (LinkConfigContext) {
254d1313 119 .ethtool_fd = -EBADF,
afca7ac1 120 };
9a4b012e 121
1cc6c93a 122 *ret = TAKE_PTR(ctx);
9a4b012e
TG
123
124 return 0;
125}
126
418c02c3 127static int link_parse_wol_password(LinkConfig *config, const char *str) {
d3867133
YW
128 _cleanup_(erase_and_freep) uint8_t *p = NULL;
129 int r;
130
418c02c3 131 assert(config);
d3867133
YW
132 assert(str);
133
134 assert_cc(sizeof(struct ether_addr) == SOPASS_MAX);
135
136 p = new(uint8_t, SOPASS_MAX);
137 if (!p)
138 return -ENOMEM;
139
227e9ce2
YW
140 /* Reuse parse_ether_addr(), as their formats are equivalent. */
141 r = parse_ether_addr(str, (struct ether_addr*) p);
d3867133
YW
142 if (r < 0)
143 return r;
144
418c02c3
YW
145 erase_and_free(config->wol_password);
146 config->wol_password = TAKE_PTR(p);
d3867133
YW
147 return 0;
148}
149
418c02c3 150static int link_read_wol_password_from_file(LinkConfig *config) {
d3867133
YW
151 _cleanup_(erase_and_freep) char *password = NULL;
152 int r;
153
418c02c3 154 assert(config);
d3867133 155
418c02c3 156 if (!config->wol_password_file)
d3867133
YW
157 return 0;
158
159 r = read_full_file_full(
418c02c3 160 AT_FDCWD, config->wol_password_file, UINT64_MAX, SIZE_MAX,
d3867133
YW
161 READ_FULL_FILE_SECURE | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
162 NULL, &password, NULL);
163 if (r < 0)
164 return r;
165
418c02c3 166 return link_parse_wol_password(config, password);
d3867133
YW
167}
168
418c02c3 169static int link_read_wol_password_from_cred(LinkConfig *config) {
d3867133
YW
170 _cleanup_free_ char *base = NULL, *cred_name = NULL;
171 _cleanup_(erase_and_freep) char *password = NULL;
172 int r;
173
418c02c3
YW
174 assert(config);
175 assert(config->filename);
d3867133 176
418c02c3 177 if (config->wol == UINT32_MAX)
d3867133 178 return 0; /* WakeOnLan= is not specified. */
418c02c3 179 if (!FLAGS_SET(config->wol, WAKE_MAGICSECURE))
d3867133 180 return 0; /* secureon is not specified in WakeOnLan=. */
418c02c3 181 if (config->wol_password)
d3867133 182 return 0; /* WakeOnLanPassword= is specified. */
418c02c3 183 if (config->wol_password_file)
d3867133
YW
184 return 0; /* a file name is specified in WakeOnLanPassword=, but failed to read it. */
185
418c02c3 186 r = path_extract_filename(config->filename, &base);
d3867133
YW
187 if (r < 0)
188 return r;
189
190 cred_name = strjoin(base, ".wol.password");
191 if (!cred_name)
192 return -ENOMEM;
193
194 r = read_credential(cred_name, (void**) &password, NULL);
195 if (r == -ENOENT)
196 r = read_credential("wol.password", (void**) &password, NULL);
197 if (r < 0)
198 return r;
199
418c02c3 200 return link_parse_wol_password(config, password);
d3867133
YW
201}
202
418c02c3 203static int link_adjust_wol_options(LinkConfig *config) {
d3867133
YW
204 int r;
205
418c02c3 206 assert(config);
d3867133 207
418c02c3 208 r = link_read_wol_password_from_file(config);
d3867133
YW
209 if (r == -ENOMEM)
210 return log_oom();
211 if (r < 0)
418c02c3 212 log_warning_errno(r, "Failed to read WakeOnLan password from %s, ignoring: %m", config->wol_password_file);
d3867133 213
418c02c3 214 r = link_read_wol_password_from_cred(config);
d3867133
YW
215 if (r == -ENOMEM)
216 return log_oom();
217 if (r < 0)
218 log_warning_errno(r, "Failed to read WakeOnLan password from credential, ignoring: %m");
219
418c02c3 220 if (config->wol != UINT32_MAX && config->wol_password)
d3867133
YW
221 /* Enable WAKE_MAGICSECURE flag when WakeOnLanPassword=. Note that when
222 * WakeOnLanPassword= is set without WakeOnLan=, then ethtool_set_wol() enables
223 * WAKE_MAGICSECURE flag and other flags are not changed. */
418c02c3 224 config->wol |= WAKE_MAGICSECURE;
d3867133
YW
225
226 return 0;
227}
228
afca7ac1 229int link_load_one(LinkConfigContext *ctx, const char *filename) {
418c02c3 230 _cleanup_(link_config_freep) LinkConfig *config = NULL;
bdb2d3c6 231 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
6b783209 232 _cleanup_free_ char *name = NULL, *file_basename = NULL;
e406e8a2 233 const char *dropin_dirname;
af6f0d42
TG
234 int r;
235
187dc6e5
TA
236 assert(ctx);
237 assert(filename);
238
e8e2788d 239 r = null_or_empty_path(filename);
e8e2788d 240 if (r < 0)
5672bdd3 241 return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
e8e2788d 242 if (r > 0) {
ed88bcfb
ZJS
243 log_debug("Skipping empty file: %s", filename);
244 return 0;
245 }
246
6cdab9f1
YW
247 name = strdup(filename);
248 if (!name)
5672bdd3 249 return log_oom();
6cdab9f1 250
418c02c3
YW
251 config = new(LinkConfig, 1);
252 if (!config)
5672bdd3 253 return log_oom();
af6f0d42 254
418c02c3 255 *config = (LinkConfig) {
6cdab9f1 256 .filename = TAKE_PTR(name),
9e2b7763 257 .mac_address_policy = MAC_ADDRESS_POLICY_NONE,
c50404ae 258 .wol = UINT32_MAX, /* UINT32_MAX means do not change WOL setting. */
6cdab9f1
YW
259 .duplex = _DUP_INVALID,
260 .port = _NET_DEV_PORT_INVALID,
261 .autonegotiation = -1,
a34811e4
YW
262 .rx_flow_control = -1,
263 .tx_flow_control = -1,
264 .autoneg_flow_control = -1,
ef4a91a7 265 .txqueuelen = UINT32_MAX,
ee751240
YW
266 .coalesce.use_adaptive_rx_coalesce = -1,
267 .coalesce.use_adaptive_tx_coalesce = -1,
18f84f8a 268 .mdi = ETH_TP_MDI_INVALID,
41ce9d76 269 .sr_iov_num_vfs = UINT32_MAX,
cdc9be29
YW
270 .eee_enabled = -1,
271 .eee_tx_lpi_enabled = -1,
272 .eee_tx_lpi_timer_usec = USEC_INFINITY,
6cdab9f1 273 };
5fde13d7 274
ddb8a639
I
275 FOREACH_ELEMENT(feature, config->features)
276 *feature = -1;
50725d10 277
6b783209
W
278 r = path_extract_filename(filename, &file_basename);
279 if (r < 0)
280 return log_error_errno(r, "Failed to extract file name of '%s': %m", filename);
281
282 dropin_dirname = strjoina(file_basename, ".d");
e406e8a2
YW
283 r = config_parse_many(
284 STRV_MAKE_CONST(filename),
bdb2d3c6 285 NETWORK_DIRS,
e406e8a2 286 dropin_dirname,
947f59ba 287 /* root = */ NULL,
bd29dfef
YW
288 "Match\0"
289 "Link\0"
86cbb13a
YW
290 "SR-IOV\0"
291 "EnergyEfficientEthernet\0",
e406e8a2 292 config_item_perf_lookup, link_config_gperf_lookup,
ead3a3fc 293 CONFIG_PARSE_WARN, config, &stats_by_path,
a2640646 294 &config->dropins);
36f822c4 295 if (r < 0)
5672bdd3 296 return r; /* config_parse_many() logs internally. */
af6f0d42 297
bdb2d3c6
YW
298 if (ctx->stats_by_path) {
299 r = hashmap_move(ctx->stats_by_path, stats_by_path);
300 if (r < 0)
301 log_warning_errno(r, "Failed to save stats of '%s' and its drop-in configs, ignoring: %m", filename);
302 } else
303 ctx->stats_by_path = TAKE_PTR(stats_by_path);
304
418c02c3 305 if (net_match_is_empty(&config->match) && !config->conditions) {
dade7349
ZJS
306 log_warning("%s: No valid settings found in the [Match] section, ignoring file. "
307 "To match all interfaces, add OriginalName=* in the [Match] section.",
84ea567e 308 filename);
dade7349
ZJS
309 return 0;
310 }
84ea567e 311
418c02c3 312 if (!condition_test_list(config->conditions, environ, NULL, NULL, NULL)) {
176d9c0e
YW
313 log_debug("%s: Conditions do not match the system environment, skipping.", filename);
314 return 0;
315 }
316
9e2b7763
YW
317 if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM) &&
318 config->hw_addr.length > 0)
a7a12bf4
YW
319 log_warning("%s: MACAddress= in [Link] section will be ignored when MACAddressPolicy= "
320 "is set to \"persistent\" or \"random\".",
321 filename);
a7a12bf4 322
418c02c3 323 r = link_adjust_wol_options(config);
d3867133 324 if (r < 0)
5672bdd3 325 return r; /* link_adjust_wol_options() logs internally. */
d3867133 326
41ce9d76 327 r = sr_iov_drop_invalid_sections(config->sr_iov_num_vfs, config->sr_iov_by_section);
bd29dfef 328 if (r < 0)
5672bdd3 329 return r; /* sr_iov_drop_invalid_sections() logs internally. */
bd29dfef 330
5672bdd3 331 log_debug("Parsed configuration file \"%s\"", filename);
af6f0d42 332
418c02c3 333 LIST_PREPEND(configs, ctx->configs, TAKE_PTR(config));
af6f0d42 334 return 0;
af6f0d42
TG
335}
336
afca7ac1 337int link_config_load(LinkConfigContext *ctx) {
b9c54c46 338 _cleanup_strv_free_ char **files = NULL;
a39f92d3 339 int r;
af6f0d42 340
bdb2d3c6 341 assert(ctx);
af6f0d42 342
bdb2d3c6 343 link_configs_free(ctx);
af6f0d42 344
dc0d4078 345 r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
f647962d
MS
346 if (r < 0)
347 return log_error_errno(r, "failed to enumerate link files: %m");
af6f0d42 348
5672bdd3
YW
349 STRV_FOREACH_BACKWARDS(f, files)
350 (void) link_load_one(ctx, *f);
af6f0d42
TG
351
352 return 0;
353}
354
afca7ac1 355bool link_config_should_reload(LinkConfigContext *ctx) {
bdb2d3c6
YW
356 _cleanup_hashmap_free_ Hashmap *stats_by_path = NULL;
357 int r;
358
359 assert(ctx);
360
3f4dfd9d 361 r = config_get_stats_by_path(".link", NULL, 0, NETWORK_DIRS, /* check_dropins = */ true, &stats_by_path);
bdb2d3c6 362 if (r < 0) {
3f4dfd9d 363 log_warning_errno(r, "Failed to get stats of .link files, ignoring: %m");
bdb2d3c6
YW
364 return true;
365 }
366
367 return !stats_by_path_equal(ctx->stats_by_path, stats_by_path);
af6f0d42
TG
368}
369
7ab25935 370Link* link_free(Link *link) {
613701a4
YW
371 if (!link)
372 return NULL;
373
ab70e429 374 udev_event_unref(link->event);
65022cd7 375 free(link->kind);
613701a4
YW
376 return mfree(link);
377}
378
ab70e429
YW
379int link_new(LinkConfigContext *ctx, UdevEvent *event, Link **ret) {
380 sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
613701a4
YW
381 _cleanup_(link_freep) Link *link = NULL;
382 int r;
af6f0d42 383
3b64e4d4 384 assert(ctx);
ab70e429 385 assert(event);
3b64e4d4
TG
386 assert(ret);
387
613701a4
YW
388 link = new(Link, 1);
389 if (!link)
390 return -ENOMEM;
391
392 *link = (Link) {
ab70e429 393 .event = udev_event_ref(event),
613701a4
YW
394 };
395
b15053de 396 r = device_get_ifname(dev, &link->ifname);
4bb7cc82
YW
397 if (r < 0)
398 return r;
399
ab70e429 400 r = sd_device_get_ifindex(dev, &link->ifindex);
ef62949a
YW
401 if (r < 0)
402 return r;
403
ab70e429 404 r = sd_device_get_action(dev, &link->action);
ef62949a
YW
405 if (r < 0)
406 return r;
407
6e316e81 408 r = device_get_sysattr_unsigned(dev, "name_assign_type", &link->name_assign_type);
613701a4
YW
409 if (r < 0)
410 log_link_debug_errno(link, r, "Failed to get \"name_assign_type\" attribute, ignoring: %m");
6e316e81
YW
411 else
412 log_link_debug(link, "Device has name_assign_type attribute: %u", link->name_assign_type);
613701a4 413
6e316e81 414 r = device_get_sysattr_unsigned(dev, "addr_assign_type", &link->addr_assign_type);
613701a4
YW
415 if (r < 0)
416 log_link_debug_errno(link, r, "Failed to get \"addr_assign_type\" attribute, ignoring: %m");
6e316e81
YW
417 else
418 log_link_debug(link, "Device has addr_assign_type attribute: %u", link->addr_assign_type);
70f32a26 419
ab70e429 420 r = rtnl_get_link_info(&event->rtnl, link->ifindex, &link->iftype, &link->flags,
65022cd7 421 &link->kind, &link->hw_addr, &link->permanent_hw_addr);
613701a4
YW
422 if (r < 0)
423 return r;
424
425 if (link->hw_addr.length > 0 && link->permanent_hw_addr.length == 0) {
426 r = ethtool_get_permanent_hw_addr(&ctx->ethtool_fd, link->ifname, &link->permanent_hw_addr);
1de88f30 427 if (r < 0)
613701a4 428 log_link_debug_errno(link, r, "Failed to get permanent hardware address, ignoring: %m");
1de88f30 429 }
4bb7cc82 430
ab70e429 431 r = sd_device_get_property_value(dev, "ID_NET_DRIVER", &link->driver);
2b5b25f1 432 if (r < 0 && r != -ENOENT)
613701a4
YW
433 log_link_debug_errno(link, r, "Failed to get driver, ignoring: %m");
434
435 *ret = TAKE_PTR(link);
436 return 0;
437}
438
439int link_get_config(LinkConfigContext *ctx, Link *link) {
613701a4
YW
440 int r;
441
442 assert(ctx);
443 assert(link);
444
445 /* Do not configure loopback interfaces by .link files. */
446 if (link->flags & IFF_LOOPBACK)
447 return -ENOENT;
f5767302 448
418c02c3 449 LIST_FOREACH(configs, config, ctx->configs) {
613701a4
YW
450 r = net_match_config(
451 &config->match,
ab70e429 452 link->event->dev,
613701a4
YW
453 &link->hw_addr,
454 &link->permanent_hw_addr,
455 link->driver,
456 link->iftype,
65022cd7 457 link->kind,
613701a4
YW
458 link->ifname,
459 /* alternative_names = */ NULL,
460 /* wlan_iftype = */ 0,
461 /* ssid = */ NULL,
462 /* bssid = */ NULL);
1a3caa49
YW
463 if (r < 0)
464 return r;
465 if (r == 0)
466 continue;
467
613701a4
YW
468 if (config->match.ifname && !strv_contains(config->match.ifname, "*") && link->name_assign_type == NET_NAME_ENUM)
469 log_link_warning(link, "Config file %s is applied to device based on potentially unpredictable interface name.",
470 config->filename);
1a3caa49 471 else
613701a4 472 log_link_debug(link, "Config file %s is applied", config->filename);
1a3caa49 473
613701a4 474 link->config = config;
1a3caa49 475 return 0;
af6f0d42
TG
476 }
477
478 return -ENOENT;
479}
480
ab70e429
YW
481static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) {
482 LinkConfig *config = ASSERT_PTR(ASSERT_PTR(link)->config);
483 const char *name = ASSERT_PTR(link->ifname);
2e17fed5
YW
484 int r;
485
ab70e429 486 assert(link->event);
2e17fed5 487 assert(ethtool_fd);
2e17fed5 488
ab70e429 489 if (link->event->event_mode != EVENT_UDEV_WORKER) {
089bef66
YW
490 log_link_debug(link, "Running in test mode, skipping application of ethtool settings.");
491 return 0;
492 }
493
2e17fed5
YW
494 r = ethtool_set_glinksettings(ethtool_fd, name,
495 config->autonegotiation, config->advertise,
18f84f8a 496 config->speed, config->duplex, config->port, config->mdi);
2e17fed5 497 if (r < 0) {
a7994dd3 498 if (config->autonegotiation >= 0)
613701a4
YW
499 log_link_warning_errno(link, r, "Could not %s auto negotiation, ignoring: %m",
500 enable_disable(config->autonegotiation));
2e17fed5
YW
501
502 if (!eqzero(config->advertise))
613701a4 503 log_link_warning_errno(link, r, "Could not set advertise mode, ignoring: %m");
a7994dd3
YW
504
505 if (config->speed > 0)
613701a4
YW
506 log_link_warning_errno(link, r, "Could not set speed to %"PRIu64"Mbps, ignoring: %m",
507 DIV_ROUND_UP(config->speed, 1000000));
a7994dd3
YW
508
509 if (config->duplex >= 0)
613701a4
YW
510 log_link_warning_errno(link, r, "Could not set duplex to %s, ignoring: %m",
511 duplex_to_string(config->duplex));
a7994dd3
YW
512
513 if (config->port >= 0)
613701a4
YW
514 log_link_warning_errno(link, r, "Could not set port to '%s', ignoring: %m",
515 port_to_string(config->port));
18f84f8a
YW
516
517 if (config->mdi != ETH_TP_MDI_INVALID)
518 log_link_warning_errno(link, r, "Could not set MDI-X to '%s', ignoring: %m",
519 mdi_to_string(config->mdi));
2e17fed5
YW
520 }
521
d3867133 522 r = ethtool_set_wol(ethtool_fd, name, config->wol, config->wol_password);
c50404ae
YW
523 if (r < 0) {
524 _cleanup_free_ char *str = NULL;
525
526 (void) wol_options_to_string_alloc(config->wol, &str);
613701a4
YW
527 log_link_warning_errno(link, r, "Could not set WakeOnLan%s%s, ignoring: %m",
528 isempty(str) ? "" : " to ", strempty(str));
c50404ae 529 }
2e17fed5
YW
530
531 r = ethtool_set_features(ethtool_fd, name, config->features);
532 if (r < 0)
613701a4 533 log_link_warning_errno(link, r, "Could not set offload features, ignoring: %m");
2e17fed5 534
80662eec
YW
535 r = ethtool_set_channels(ethtool_fd, name, &config->channels);
536 if (r < 0)
613701a4 537 log_link_warning_errno(link, r, "Could not set channels, ignoring: %m");
2e17fed5 538
80662eec
YW
539 r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring);
540 if (r < 0)
613701a4 541 log_link_warning_errno(link, r, "Could not set ring buffer, ignoring: %m");
2e17fed5 542
80662eec
YW
543 r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
544 if (r < 0)
613701a4 545 log_link_warning_errno(link, r, "Could not set flow control, ignoring: %m");
2e17fed5 546
6c35ea5e
DDM
547 r = ethtool_set_nic_coalesce_settings(ethtool_fd, name, &config->coalesce);
548 if (r < 0)
613701a4 549 log_link_warning_errno(link, r, "Could not set coalesce settings, ignoring: %m");
6c35ea5e 550
cdc9be29
YW
551 r = ethtool_set_eee_settings(ethtool_fd, name, config->eee_enabled, config->eee_tx_lpi_enabled, config->eee_tx_lpi_timer_usec, config->eee_advertise[0]);
552 if (r < 0)
553 log_link_warning_errno(link, r, "Could not set energy efficient ethernet settings, ignoring: %m");
554
2e17fed5
YW
555 return 0;
556}
557
9e2b7763
YW
558static bool hw_addr_is_valid(Link *link, const struct hw_addr_data *hw_addr) {
559 assert(link);
560 assert(hw_addr);
561
562 switch (link->iftype) {
563 case ARPHRD_ETHER:
564 /* Refuse all zero and all 0xFF. */
565 assert(hw_addr->length == ETH_ALEN);
566 return !ether_addr_is_null(&hw_addr->ether) && !ether_addr_is_broadcast(&hw_addr->ether);
567
568 case ARPHRD_INFINIBAND:
0b75493d 569 /* The last 8 bytes cannot be zero. */
9e2b7763
YW
570 assert(hw_addr->length == INFINIBAND_ALEN);
571 return !memeqzero(hw_addr->bytes + INFINIBAND_ALEN - 8, 8);
572
573 default:
574 assert_not_reached();
575 }
576}
577
578static int link_generate_new_hw_addr(Link *link, struct hw_addr_data *ret) {
579 struct hw_addr_data hw_addr = HW_ADDR_NULL;
45aa0e84 580 bool is_static = false;
9e2b7763
YW
581 uint8_t *p;
582 size_t len;
f1ac7002 583 int r;
16b9b87a 584
613701a4
YW
585 assert(link);
586 assert(link->config);
ab70e429
YW
587 assert(link->event);
588 assert(link->event->dev);
9e2b7763
YW
589 assert(ret);
590
591 if (link->hw_addr.length == 0)
592 goto finalize;
593
594 if (link->config->mac_address_policy == MAC_ADDRESS_POLICY_NONE) {
595 log_link_debug(link, "Using static MAC address.");
596 hw_addr = link->config->hw_addr;
45aa0e84 597 is_static = true;
9e2b7763
YW
598 goto finalize;
599 }
600
601 if (!IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
602 goto finalize;
3c9b8860 603
613701a4 604 switch (link->addr_assign_type) {
015b097c 605 case NET_ADDR_SET:
9e2b7763
YW
606 log_link_debug(link, "MAC address on the device already set by userspace.");
607 goto finalize;
015b097c 608 case NET_ADDR_STOLEN:
9e2b7763
YW
609 log_link_debug(link, "MAC address on the device already set based on another device.");
610 goto finalize;
015b097c
ZJS
611 case NET_ADDR_RANDOM:
612 case NET_ADDR_PERM:
613 break;
614 default:
613701a4 615 log_link_warning(link, "Unknown addr_assign_type %u, ignoring", link->addr_assign_type);
9e2b7763 616 goto finalize;
015b097c 617 }
04b67d49 618
613701a4 619 if ((link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM) == (link->addr_assign_type == NET_ADDR_RANDOM)) {
9e2b7763 620 log_link_debug(link, "MAC address on the device already matches policy \"%s\".",
613701a4 621 mac_address_policy_to_string(link->config->mac_address_policy));
9e2b7763 622 goto finalize;
9d9fed9e 623 }
16b9b87a 624
9e2b7763
YW
625 hw_addr = (struct hw_addr_data) {
626 .length = arphrd_to_hw_addr_len(link->iftype),
627 };
550c8784 628
9e2b7763
YW
629 switch (link->iftype) {
630 case ARPHRD_ETHER:
631 p = hw_addr.bytes;
632 len = hw_addr.length;
633 break;
634 case ARPHRD_INFINIBAND:
635 p = hw_addr.bytes + INFINIBAND_ALEN - 8;
636 len = 8;
637 break;
638 default:
639 assert_not_reached();
640 }
641
642 if (link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM)
550c8784 643 /* We require genuine randomness here, since we want to make sure we won't collide with other
ffa047a0 644 * systems booting up at the very same time. */
9e2b7763 645 for (;;) {
87cb1ab6 646 random_bytes(p, len);
9e2b7763
YW
647 if (hw_addr_is_valid(link, &hw_addr))
648 break;
649 }
650
651 else {
dbe81cbd 652 uint64_t result;
9bf3b535 653
ab70e429 654 r = net_get_unique_predictable_data(link->event->dev,
96848152
ZJS
655 naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS),
656 &result);
16b9b87a 657 if (r < 0)
9e2b7763 658 return log_link_warning_errno(link, r, "Could not generate persistent MAC address: %m");
16b9b87a 659
9e2b7763
YW
660 assert(len <= sizeof(result));
661 memcpy(p, &result, len);
662 if (!hw_addr_is_valid(link, &hw_addr))
663 return log_link_warning_errno(link, SYNTHETIC_ERRNO(EINVAL),
664 "Could not generate valid persistent MAC address: %m");
16b9b87a
TG
665 }
666
9e2b7763
YW
667finalize:
668
45aa0e84 669 r = net_verify_hardware_address(link->ifname, is_static, link->iftype, &link->hw_addr, &hw_addr);
9e2b7763
YW
670 if (r < 0)
671 return r;
672
673 if (hw_addr_equal(&link->hw_addr, &hw_addr)) {
674 *ret = HW_ADDR_NULL;
675 return 0;
676 }
677
678 if (hw_addr.length > 0)
679 log_link_debug(link, "Applying %s MAC address: %s",
680 link->config->mac_address_policy == MAC_ADDRESS_POLICY_NONE ? "static" :
681 mac_address_policy_to_string(link->config->mac_address_policy),
682 HW_ADDR_TO_STR(&hw_addr));
683
684 *ret = hw_addr;
685 return 0;
16b9b87a
TG
686}
687
ab70e429 688static int link_apply_rtnl_settings(Link *link) {
9e2b7763 689 struct hw_addr_data hw_addr = {};
ab70e429 690 LinkConfig *config = ASSERT_PTR(ASSERT_PTR(link)->config);
613701a4 691 int r;
af6f0d42 692
ab70e429 693 assert(link->event);
3e137a1b 694
ab70e429 695 if (link->event->event_mode != EVENT_UDEV_WORKER) {
089bef66
YW
696 log_link_debug(link, "Running in test mode, skipping application of rtnl settings.");
697 return 0;
698 }
699
9e2b7763 700 (void) link_generate_new_hw_addr(link, &hw_addr);
af6f0d42 701
ab70e429 702 r = rtnl_set_link_properties(&link->event->rtnl, link->ifindex, config->alias, &hw_addr,
face9fcc
YW
703 config->txqueues, config->rxqueues, config->txqueuelen,
704 config->mtu, config->gso_max_size, config->gso_max_segments);
50725d10 705 if (r < 0)
613701a4
YW
706 log_link_warning_errno(link, r,
707 "Could not set Alias=, MACAddress=/MACAddressPolicy=, "
708 "TransmitQueues=, ReceiveQueues=, TransmitQueueLength=, MTUBytes=, "
709 "GenericSegmentOffloadMaxBytes= or GenericSegmentOffloadMaxSegments=, "
710 "ignoring: %m");
50725d10 711
2e17fed5
YW
712 return 0;
713}
224ded67 714
d806fff1
YW
715static bool enable_name_policy(void) {
716 static int cached = -1;
717 bool b;
718 int r;
719
720 if (cached >= 0)
721 return cached;
722
3787934b 723 r = proc_cmdline_get_bool("net.ifnames", /* flags = */ 0, &b);
d806fff1
YW
724 if (r < 0)
725 log_warning_errno(r, "Failed to parse net.ifnames= kernel command line option, ignoring: %m");
726 if (r <= 0)
727 return (cached = true);
728
729 if (!b)
730 log_info("Network interface NamePolicy= disabled on kernel command line.");
731
732 return (cached = b);
733}
734
735static int link_generate_new_name(Link *link) {
ab70e429
YW
736 LinkConfig *config = ASSERT_PTR(ASSERT_PTR(link)->config);;
737 sd_device *device = ASSERT_PTR(ASSERT_PTR(link->event)->dev);
0b189e8f 738
cd941e65 739 if (link->action != SD_DEVICE_ADD) {
5ea4afcf 740 log_link_debug(link, "Not applying Name= and NamePolicy= on '%s' uevent.",
613701a4 741 device_action_to_string(link->action));
73d2bb08
ZJS
742 goto no_rename;
743 }
744
613701a4
YW
745 if (IN_SET(link->name_assign_type, NET_NAME_USER, NET_NAME_RENAMED) &&
746 !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
747 log_link_debug(link, "Device already has a name given by userspace, not renaming.");
748 goto no_rename;
749 }
750
d806fff1 751 if (enable_name_policy() && config->name_policy)
613701a4 752 for (NamePolicy *policy = config->name_policy; *policy != _NAMEPOLICY_INVALID; policy++) {
5cdb3f70 753 const char *new_name = NULL;
0b189e8f 754
613701a4 755 switch (*policy) {
0b189e8f 756 case NAMEPOLICY_KERNEL:
613701a4 757 if (link->name_assign_type != NET_NAME_PREDICTABLE)
0b189e8f
ZJS
758 continue;
759
760 /* The kernel claims to have given a predictable name, keep it. */
613701a4
YW
761 log_link_debug(link, "Policy *%s*: keeping predictable kernel name",
762 name_policy_to_string(*policy));
0b189e8f 763 goto no_rename;
3907446f 764 case NAMEPOLICY_KEEP:
613701a4 765 if (!IN_SET(link->name_assign_type, NET_NAME_USER, NET_NAME_RENAMED))
3907446f
ZJS
766 continue;
767
613701a4
YW
768 log_link_debug(link, "Policy *%s*: keeping existing userspace name",
769 name_policy_to_string(*policy));
3907446f 770 goto no_rename;
0b189e8f
ZJS
771 case NAMEPOLICY_DATABASE:
772 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
773 break;
774 case NAMEPOLICY_ONBOARD:
775 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
776 break;
777 case NAMEPOLICY_SLOT:
778 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
779 break;
780 case NAMEPOLICY_PATH:
781 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
782 break;
783 case NAMEPOLICY_MAC:
784 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
785 break;
786 default:
04499a70 787 assert_not_reached();
5fde13d7 788 }
5cdb3f70 789 if (ifname_valid(new_name)) {
613701a4
YW
790 log_link_debug(link, "Policy *%s* yields \"%s\".", name_policy_to_string(*policy), new_name);
791 link->new_name = new_name;
5cdb3f70
YW
792 return 0;
793 }
daeb71a3 794 }
daeb71a3 795
613701a4
YW
796 if (link->config->name) {
797 log_link_debug(link, "Policies didn't yield a name, using specified Name=%s.", link->config->name);
798 link->new_name = link->config->name;
2e17fed5
YW
799 return 0;
800 }
16b9b87a 801
613701a4 802 log_link_debug(link, "Policies didn't yield a name and Name= is not given, not renaming.");
2e17fed5 803no_rename:
b15053de
YW
804 if (!naming_scheme_has(NAMING_USE_INTERFACE_PROPERTY))
805 return sd_device_get_sysname(device, &link->new_name);
806
613701a4 807 link->new_name = link->ifname;
2e17fed5
YW
808 return 0;
809}
810
9094ae52
YW
811static int link_generate_alternative_names(Link *link) {
812 _cleanup_strv_free_ char **altnames = NULL;
ab70e429
YW
813 LinkConfig *config = ASSERT_PTR(ASSERT_PTR(link)->config);
814 sd_device *device = ASSERT_PTR(ASSERT_PTR(link->event)->dev);
613701a4 815 int r;
2e17fed5 816
ab70e429 817 assert(!ASSERT_PTR(link->event)->altnames);
2e17fed5 818
9094ae52 819 if (link->action != SD_DEVICE_ADD) {
5ea4afcf 820 log_link_debug(link, "Not applying AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.",
9094ae52
YW
821 device_action_to_string(link->action));
822 return 0;
823 }
43b3a5ef 824
ef1d2c07
YW
825 if (config->alternative_names) {
826 altnames = strv_copy(config->alternative_names);
827 if (!altnames)
828 return log_oom();
829 }
830
831 if (config->alternative_names_policy)
832 for (NamePolicy *p = config->alternative_names_policy; *p != _NAMEPOLICY_INVALID; p++) {
61fd7d67 833 const char *n = NULL;
ef1d2c07
YW
834
835 switch (*p) {
836 case NAMEPOLICY_DATABASE:
837 (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &n);
838 break;
839 case NAMEPOLICY_ONBOARD:
840 (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &n);
841 break;
842 case NAMEPOLICY_SLOT:
843 (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &n);
844 break;
845 case NAMEPOLICY_PATH:
846 (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &n);
847 break;
848 case NAMEPOLICY_MAC:
849 (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &n);
850 break;
851 default:
04499a70 852 assert_not_reached();
ef1d2c07 853 }
e65c6c1b 854 if (ifname_valid_full(n, IFNAME_VALID_ALTERNATIVE)) {
ef1d2c07
YW
855 r = strv_extend(&altnames, n);
856 if (r < 0)
857 return log_oom();
858 }
859 }
860
ab70e429 861 link->event->altnames = TAKE_PTR(altnames);
2e17fed5
YW
862 return 0;
863}
a5053a15 864
f4282e6a 865static int sr_iov_configure(Link *link, sd_netlink **rtnl, SRIOV *sr_iov, SRIOVAttribute attr) {
bd29dfef
YW
866 int r;
867
868 assert(link);
869 assert(rtnl);
870 assert(link->ifindex > 0);
871
f4282e6a
YW
872 if (!sr_iov_has_config(sr_iov, attr))
873 return 0;
371005ac 874
f4282e6a
YW
875 if (!*rtnl) {
876 r = sd_netlink_open(rtnl);
bd29dfef
YW
877 if (r < 0)
878 return r;
f4282e6a 879 }
bd29dfef 880
f4282e6a
YW
881 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
882 r = sd_rtnl_message_new_link(*rtnl, &req, RTM_SETLINK, link->ifindex);
883 if (r < 0)
884 return r;
bd29dfef 885
f4282e6a
YW
886 r = sr_iov_set_netlink_message(sr_iov, attr, req);
887 if (r < 0)
888 return r;
bd29dfef 889
f4282e6a 890 return sd_netlink_call(*rtnl, req, 0, NULL);
bd29dfef
YW
891}
892
ab70e429 893static int link_apply_sr_iov_config(Link *link) {
bd29dfef 894 SRIOV *sr_iov;
252e96ea 895 uint32_t n;
bd29dfef
YW
896 int r;
897
898 assert(link);
899 assert(link->config);
ab70e429 900 assert(ASSERT_PTR(link->event)->dev);
41ce9d76 901
ab70e429 902 if (link->event->event_mode != EVENT_UDEV_WORKER) {
089bef66
YW
903 log_link_debug(link, "Running in test mode, skipping application of SR-IOV settings.");
904 return 0;
905 }
906
ab70e429 907 r = sr_iov_set_num_vfs(link->event->dev, link->config->sr_iov_num_vfs, link->config->sr_iov_by_section);
41ce9d76
YW
908 if (r < 0)
909 log_link_warning_errno(link, r, "Failed to set the number of SR-IOV virtual functions, ignoring: %m");
bd29dfef 910
252e96ea
YW
911 if (ordered_hashmap_isempty(link->config->sr_iov_by_section))
912 return 0;
913
ab70e429 914 r = sr_iov_get_num_vfs(link->event->dev, &n);
252e96ea 915 if (r < 0) {
11c5eff1 916 log_link_warning_errno(link, r, "Failed to get the number of SR-IOV virtual functions, ignoring all [SR-IOV] sections: %m");
252e96ea
YW
917 return 0;
918 }
919 if (n == 0) {
11c5eff1 920 log_link_warning(link, "No SR-IOV virtual function exists, ignoring all [SR-IOV] sections: %m");
252e96ea
YW
921 return 0;
922 }
923
bd29dfef 924 ORDERED_HASHMAP_FOREACH(sr_iov, link->config->sr_iov_by_section) {
252e96ea 925 if (sr_iov->vf >= n) {
11c5eff1 926 log_link_warning(link, "SR-IOV virtual function %"PRIu32" does not exist, ignoring [SR-IOV] section for the virtual function.", sr_iov->vf);
252e96ea
YW
927 continue;
928 }
929
f4282e6a
YW
930 for (SRIOVAttribute attr = 0; attr < _SR_IOV_ATTRIBUTE_MAX; attr++) {
931 r = sr_iov_configure(link, &link->event->rtnl, sr_iov, attr);
932 if (r < 0)
933 log_link_warning_errno(link, r,
934 "Failed to set up %s for SR-IOV virtual function %"PRIu32", ignoring: %m",
935 sr_iov_attribute_to_string(attr), sr_iov->vf);
936 }
bd29dfef
YW
937 }
938
939 return 0;
940}
941
ab70e429 942static int link_apply_rps_cpu_mask(Link *link) {
0f30bf58
RRZ
943 _cleanup_free_ char *mask_str = NULL;
944 LinkConfig *config;
945 int r;
946
ab70e429
YW
947 config = ASSERT_PTR(ASSERT_PTR(link)->config);
948 assert(ASSERT_PTR(link->event)->dev);
0f30bf58 949
ab70e429 950 if (link->event->event_mode != EVENT_UDEV_WORKER) {
089bef66
YW
951 log_link_debug(link, "Running in test mode, skipping application of RPS setting.");
952 return 0;
953 }
954
0f30bf58 955 /* Skip if the config is not specified. */
16069d75 956 if (!config->rps_cpu_mask.set)
0f30bf58
RRZ
957 return 0;
958
16069d75 959 mask_str = cpu_set_to_mask_string(&config->rps_cpu_mask);
0f30bf58
RRZ
960 if (!mask_str)
961 return log_oom();
962
963 log_link_debug(link, "Applying RPS CPU mask: %s", mask_str);
964
965 /* Currently, this will set CPU mask to all rx queue of matched device. */
ab70e429 966 FOREACH_DEVICE_SYSATTR(link->event->dev, attr) {
0f30bf58
RRZ
967 const char *c;
968
969 c = path_startswith(attr, "queues/");
970 if (!c)
971 continue;
972
973 c = startswith(c, "rx-");
974 if (!c)
975 continue;
976
977 c += strcspn(c, "/");
978
979 if (!path_equal(c, "/rps_cpus"))
980 continue;
981
ab70e429 982 r = sd_device_set_sysattr_value(link->event->dev, attr, mask_str);
0f30bf58
RRZ
983 if (r < 0)
984 log_link_warning_errno(link, r, "Failed to write %s sysfs attribute, ignoring: %m", attr);
985 }
986
987 return 0;
988}
989
ab70e429
YW
990static int link_apply_udev_properties(Link *link) {
991 LinkConfig *config = ASSERT_PTR(ASSERT_PTR(link)->config);
992 UdevEvent *event = ASSERT_PTR(link->event);
3e00171d 993
046286e8
YW
994 /* 1. apply ImportProperty=. */
995 STRV_FOREACH(p, config->import_properties)
036c75de 996 (void) udev_builtin_import_property(event, *p);
046286e8
YW
997
998 /* 2. apply Property=. */
999 STRV_FOREACH(p, config->properties) {
1000 _cleanup_free_ char *key = NULL;
1001 const char *eq;
1002
1003 eq = strchr(*p, '=');
1004 if (!eq)
1005 continue;
1006
1007 key = strndup(*p, eq - *p);
1008 if (!key)
1009 return log_oom();
1010
036c75de 1011 (void) udev_builtin_add_property(event, key, eq + 1);
046286e8
YW
1012 }
1013
1014 /* 3. apply UnsetProperty=. */
1015 STRV_FOREACH(p, config->unset_properties)
036c75de 1016 (void) udev_builtin_add_property(event, *p, NULL);
046286e8
YW
1017
1018 /* 4. set the default properties. */
036c75de 1019 (void) udev_builtin_add_property(event, "ID_NET_LINK_FILE", config->filename);
3e00171d
YW
1020
1021 _cleanup_free_ char *joined = NULL;
1022 STRV_FOREACH(d, config->dropins) {
1023 _cleanup_free_ char *escaped = NULL;
1024
1025 escaped = xescape(*d, ":");
1026 if (!escaped)
1027 return log_oom();
1028
1029 if (!strextend_with_separator(&joined, ":", escaped))
1030 return log_oom();
1031 }
1032
036c75de 1033 (void) udev_builtin_add_property(event, "ID_NET_LINK_FILE_DROPINS", joined);
3e00171d
YW
1034
1035 if (link->new_name)
036c75de 1036 (void) udev_builtin_add_property(event, "ID_NET_NAME", link->new_name);
3e00171d
YW
1037
1038 return 0;
1039}
1040
ab70e429 1041int link_apply_config(LinkConfigContext *ctx, Link *link) {
2e17fed5
YW
1042 int r;
1043
1044 assert(ctx);
613701a4 1045 assert(link);
2e17fed5 1046
ab70e429 1047 r = link_apply_ethtool_settings(link, &ctx->ethtool_fd);
2e17fed5
YW
1048 if (r < 0)
1049 return r;
1050
ab70e429 1051 r = link_apply_rtnl_settings(link);
2e17fed5
YW
1052 if (r < 0)
1053 return r;
d95b83b8 1054
d806fff1 1055 r = link_generate_new_name(link);
e5eadf53
YW
1056 if (r < 0)
1057 return r;
847a8a5f 1058
9094ae52 1059 r = link_generate_alternative_names(link);
847a8a5f
TG
1060 if (r < 0)
1061 return r;
1062
ab70e429 1063 r = link_apply_sr_iov_config(link);
bd29dfef
YW
1064 if (r < 0)
1065 return r;
1066
ab70e429 1067 r = link_apply_rps_cpu_mask(link);
3e00171d
YW
1068 if (r < 0)
1069 return r;
1070
ab70e429 1071 return link_apply_udev_properties(link);
847a8a5f
TG
1072}
1073
046286e8
YW
1074int config_parse_udev_property(
1075 const char *unit,
1076 const char *filename,
1077 unsigned line,
1078 const char *section,
1079 unsigned section_line,
1080 const char *lvalue,
1081 int ltype,
1082 const char *rvalue,
1083 void *data,
1084 void *userdata) {
1085
1086 char ***properties = ASSERT_PTR(data);
1087 int r;
1088
1089 assert(filename);
1090 assert(lvalue);
1091 assert(rvalue);
1092
1093 if (isempty(rvalue)) {
1094 /* Empty assignment resets the list */
1095 *properties = strv_free(*properties);
1096 return 0;
1097 }
1098
1099 for (const char *p = rvalue;; ) {
1100 _cleanup_free_ char *word = NULL, *resolved = NULL, *key = NULL;
1101 const char *eq;
1102
1103 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
1104 if (r == -ENOMEM)
1105 return log_oom();
1106 if (r < 0) {
1107 log_syntax(unit, LOG_WARNING, filename, line, r,
1108 "Invalid syntax, ignoring assignment: %s", rvalue);
1109 return 0;
1110 }
1111 if (r == 0)
1112 return 0;
1113
1114 r = specifier_printf(word, SIZE_MAX, link_specifier_table, NULL, NULL, &resolved);
1115 if (r < 0) {
1116 log_syntax(unit, LOG_WARNING, filename, line, r,
1117 "Failed to resolve specifiers in %s, ignoring assignment: %m", word);
1118 continue;
1119 }
1120
4c547d21 1121 if (!udev_property_assignment_is_valid(resolved)) {
046286e8
YW
1122 log_syntax(unit, LOG_WARNING, filename, line, 0,
1123 "Invalid udev property, ignoring assignment: %s", word);
1124 continue;
1125 }
1126
1127 assert_se(eq = strchr(resolved, '='));
1128 key = strndup(resolved, eq - resolved);
1129 if (!key)
1130 return log_oom();
1131
1132 if (!device_property_can_set(key)) {
1133 log_syntax(unit, LOG_WARNING, filename, line, 0,
1134 "Invalid udev property name '%s', ignoring assignment: %s", key, resolved);
1135 continue;
1136 }
1137
1138 r = strv_env_replace_consume(properties, TAKE_PTR(resolved));
1139 if (r < 0)
1140 return log_error_errno(r, "Failed to update properties: %m");
1141 }
1142}
1143
1144int config_parse_udev_property_name(
1145 const char *unit,
1146 const char *filename,
1147 unsigned line,
1148 const char *section,
1149 unsigned section_line,
1150 const char *lvalue,
1151 int ltype,
1152 const char *rvalue,
1153 void *data,
1154 void *userdata) {
1155
1156 char ***properties = ASSERT_PTR(data);
1157 int r;
1158
1159 assert(filename);
1160 assert(lvalue);
1161 assert(rvalue);
1162
1163 if (isempty(rvalue)) {
1164 /* Empty assignment resets the list */
1165 *properties = strv_free(*properties);
1166 return 0;
1167 }
1168
1169 for (const char *p = rvalue;; ) {
1170 _cleanup_free_ char *word = NULL, *resolved = NULL;
1171
1172 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
1173 if (r == -ENOMEM)
1174 return log_oom();
1175 if (r < 0) {
1176 log_syntax(unit, LOG_WARNING, filename, line, r,
1177 "Invalid syntax, ignoring assignment: %s", rvalue);
1178 return 0;
1179 }
1180 if (r == 0)
1181 return 0;
1182
1183 r = specifier_printf(word, SIZE_MAX, link_specifier_table, NULL, NULL, &resolved);
1184 if (r < 0) {
1185 log_syntax(unit, LOG_WARNING, filename, line, r,
1186 "Failed to resolve specifiers in %s, ignoring assignment: %m", word);
1187 continue;
1188 }
1189
4c547d21 1190 if (!udev_property_name_is_valid(resolved)) {
046286e8
YW
1191 log_syntax(unit, LOG_WARNING, filename, line, 0,
1192 "Invalid udev property name, ignoring assignment: %s", resolved);
1193 continue;
1194 }
1195
1196 if (!device_property_can_set(resolved)) {
1197 log_syntax(unit, LOG_WARNING, filename, line, 0,
1198 "Invalid udev property name, ignoring assignment: %s", resolved);
1199 continue;
1200 }
1201
1202 r = strv_consume(properties, TAKE_PTR(resolved));
1203 if (r < 0)
1204 return log_error_errno(r, "Failed to update properties: %m");
1205 }
1206}
1207
fc27088a
YW
1208int config_parse_ifalias(
1209 const char *unit,
1210 const char *filename,
1211 unsigned line,
1212 const char *section,
1213 unsigned section_line,
1214 const char *lvalue,
1215 int ltype,
1216 const char *rvalue,
1217 void *data,
1218 void *userdata) {
1219
99534007 1220 char **s = ASSERT_PTR(data);
fc27088a
YW
1221
1222 assert(filename);
1223 assert(lvalue);
1224 assert(rvalue);
fc27088a 1225
d1df0466 1226 if (isempty(rvalue)) {
fc27088a
YW
1227 *s = mfree(*s);
1228 return 0;
1229 }
1230
1231 if (!ascii_is_valid(rvalue)) {
1232 log_syntax(unit, LOG_WARNING, filename, line, 0,
1233 "Interface alias is not ASCII clean, ignoring assignment: %s", rvalue);
1234 return 0;
1235 }
1236
1237 if (strlen(rvalue) >= IFALIASZ) {
1238 log_syntax(unit, LOG_WARNING, filename, line, 0,
1239 "Interface alias is too long, ignoring assignment: %s", rvalue);
1240 return 0;
1241 }
1242
b3f9c17a 1243 return free_and_strdup_warn(s, rvalue);
fc27088a
YW
1244}
1245
face9fcc
YW
1246int config_parse_rx_tx_queues(
1247 const char *unit,
1248 const char *filename,
1249 unsigned line,
1250 const char *section,
1251 unsigned section_line,
1252 const char *lvalue,
1253 int ltype,
1254 const char *rvalue,
1255 void *data,
1256 void *userdata) {
1257
1258 uint32_t k, *v = data;
1259 int r;
1260
1261 if (isempty(rvalue)) {
1262 *v = 0;
1263 return 0;
1264 }
1265
1266 r = safe_atou32(rvalue, &k);
1267 if (r < 0) {
1268 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue);
1269 return 0;
1270 }
1271 if (k == 0 || k > 4096) {
1272 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s=, ignoring assignment: %s.", lvalue, rvalue);
1273 return 0;
1274 }
1275
1276 *v = k;
1277 return 0;
1278}
1279
ef4a91a7
1280int config_parse_txqueuelen(
1281 const char *unit,
1282 const char *filename,
1283 unsigned line,
1284 const char *section,
1285 unsigned section_line,
1286 const char *lvalue,
1287 int ltype,
1288 const char *rvalue,
1289 void *data,
1290 void *userdata) {
1291
1292 uint32_t k, *v = data;
1293 int r;
1294
1295 if (isempty(rvalue)) {
1296 *v = UINT32_MAX;
1297 return 0;
1298 }
1299
1300 r = safe_atou32(rvalue, &k);
1301 if (r < 0) {
1302 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue);
1303 return 0;
1304 }
1305 if (k == UINT32_MAX) {
1306 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s=, ignoring assignment: %s.", lvalue, rvalue);
1307 return 0;
1308 }
1309
1310 *v = k;
1311 return 0;
1312}
1313
d3867133
YW
1314int config_parse_wol_password(
1315 const char *unit,
1316 const char *filename,
1317 unsigned line,
1318 const char *section,
1319 unsigned section_line,
1320 const char *lvalue,
1321 int ltype,
1322 const char *rvalue,
1323 void *data,
1324 void *userdata) {
1325
99534007 1326 LinkConfig *config = ASSERT_PTR(userdata);
d3867133
YW
1327 int r;
1328
1329 assert(filename);
1330 assert(lvalue);
1331 assert(rvalue);
d3867133
YW
1332
1333 if (isempty(rvalue)) {
418c02c3
YW
1334 config->wol_password = erase_and_free(config->wol_password);
1335 config->wol_password_file = mfree(config->wol_password_file);
d3867133
YW
1336 return 0;
1337 }
1338
1339 if (path_is_absolute(rvalue) && path_is_safe(rvalue)) {
418c02c3
YW
1340 config->wol_password = erase_and_free(config->wol_password);
1341 return free_and_strdup_warn(&config->wol_password_file, rvalue);
d3867133
YW
1342 }
1343
1344 warn_file_is_world_accessible(filename, NULL, unit, line);
1345
418c02c3 1346 r = link_parse_wol_password(config, rvalue);
d3867133
YW
1347 if (r == -ENOMEM)
1348 return log_oom();
1349 if (r < 0) {
1350 log_syntax(unit, LOG_WARNING, filename, line, r,
1351 "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue);
1352 return 0;
1353 }
1354
418c02c3 1355 config->wol_password_file = mfree(config->wol_password_file);
d3867133
YW
1356 return 0;
1357}
1358
0f30bf58
RRZ
1359int config_parse_rps_cpu_mask(
1360 const char *unit,
1361 const char *filename,
1362 unsigned line,
1363 const char *section,
1364 unsigned section_line,
1365 const char *lvalue,
1366 int ltype,
1367 const char *rvalue,
1368 void *data,
1369 void *userdata) {
1370
16069d75 1371 CPUSet *mask = ASSERT_PTR(data);
0f30bf58
RRZ
1372 int r;
1373
0f30bf58
RRZ
1374 assert(rvalue);
1375
16069d75
YW
1376 if (streq(rvalue, "disable")) {
1377 _cleanup_(cpu_set_done) CPUSet c = {};
1378
1379 r = cpu_set_realloc(&c, 1);
1380 if (r < 0)
0f30bf58
RRZ
1381 return log_oom();
1382
16069d75 1383 return cpu_set_done_and_replace(*mask, c);
0f30bf58
RRZ
1384 }
1385
16069d75
YW
1386 if (streq(rvalue, "all")) {
1387 _cleanup_(cpu_set_done) CPUSet c = {};
0f30bf58 1388
16069d75 1389 r = cpu_set_add_all(&c);
0f30bf58
RRZ
1390 if (r < 0) {
1391 log_syntax(unit, LOG_WARNING, filename, line, r,
1392 "Failed to create CPU affinity mask representing \"all\" cpus, ignoring: %m");
1393 return 0;
1394 }
16069d75
YW
1395
1396 return cpu_set_done_and_replace(*mask, c);
0f30bf58
RRZ
1397 }
1398
fe3ada07 1399 return config_parse_cpu_set(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
0f30bf58
RRZ
1400}
1401
54ed9f88
ZJS
1402static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
1403 [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
1404 [MAC_ADDRESS_POLICY_RANDOM] = "random",
1405 [MAC_ADDRESS_POLICY_NONE] = "none",
be32eb9b
TG
1406};
1407
54ed9f88 1408DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
d03cb6b8
YW
1409DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(
1410 config_parse_mac_address_policy,
1411 mac_address_policy,
1412 MACAddressPolicy,
42efe5be 1413 MAC_ADDRESS_POLICY_NONE);
be32eb9b 1414
464cf22f 1415DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
42efe5be 1416 _NAMEPOLICY_INVALID);
ef1d2c07 1417
ef1d2c07 1418DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy, alternative_names_policy, NamePolicy,
42efe5be 1419 _NAMEPOLICY_INVALID);