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