]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #25092 from fbuihuu/random-seed-tweaks
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <linux/netdevice.h>
6 #include <unistd.h>
7
8 #include "alloc-util.h"
9 #include "conf-files.h"
10 #include "conf-parser.h"
11 #include "dns-domain.h"
12 #include "fd-util.h"
13 #include "hostname-util.h"
14 #include "in-addr-util.h"
15 #include "net-condition.h"
16 #include "netdev/macvlan.h"
17 #include "networkd-address-label.h"
18 #include "networkd-address.h"
19 #include "networkd-bridge-fdb.h"
20 #include "networkd-bridge-mdb.h"
21 #include "networkd-dhcp-common.h"
22 #include "networkd-dhcp-server-static-lease.h"
23 #include "networkd-dhcp-server.h"
24 #include "networkd-ipv6-proxy-ndp.h"
25 #include "networkd-manager.h"
26 #include "networkd-ndisc.h"
27 #include "networkd-neighbor.h"
28 #include "networkd-network.h"
29 #include "networkd-nexthop.h"
30 #include "networkd-radv.h"
31 #include "networkd-route.h"
32 #include "networkd-routing-policy-rule.h"
33 #include "networkd-sriov.h"
34 #include "parse-util.h"
35 #include "path-lookup.h"
36 #include "qdisc.h"
37 #include "radv-internal.h"
38 #include "set.h"
39 #include "socket-util.h"
40 #include "stat-util.h"
41 #include "string-table.h"
42 #include "string-util.h"
43 #include "strv.h"
44 #include "tclass.h"
45 #include "util.h"
46
47 /* Let's assume that anything above this number is a user misconfiguration. */
48 #define MAX_NTP_SERVERS 128U
49
50 static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret) {
51 const char *kind_string;
52 NetDev *netdev;
53 int r;
54
55 /* For test-networkd-conf, the check must be earlier than the assertions. */
56 if (!name)
57 return 0;
58
59 assert(network);
60 assert(network->manager);
61 assert(network->filename);
62 assert(ret);
63
64 if (kind == _NETDEV_KIND_TUNNEL)
65 kind_string = "tunnel";
66 else {
67 kind_string = netdev_kind_to_string(kind);
68 if (!kind_string)
69 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
70 "%s: Invalid NetDev kind of %s, ignoring assignment.",
71 network->filename, name);
72 }
73
74 r = netdev_get(network->manager, name, &netdev);
75 if (r < 0)
76 return log_warning_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
77 network->filename, name);
78
79 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
80 IN_SET(netdev->kind,
81 NETDEV_KIND_ERSPAN,
82 NETDEV_KIND_GRE,
83 NETDEV_KIND_GRETAP,
84 NETDEV_KIND_IP6GRE,
85 NETDEV_KIND_IP6GRETAP,
86 NETDEV_KIND_IP6TNL,
87 NETDEV_KIND_IPIP,
88 NETDEV_KIND_SIT,
89 NETDEV_KIND_VTI,
90 NETDEV_KIND_VTI6)))
91 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
92 "%s: NetDev %s is not a %s, ignoring assignment",
93 network->filename, name, kind_string);
94
95 *ret = netdev_ref(netdev);
96 return 1;
97 }
98
99 static int network_resolve_stacked_netdevs(Network *network) {
100 void *name, *kind;
101 int r;
102
103 assert(network);
104
105 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names) {
106 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
107
108 if (network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev) <= 0)
109 continue;
110
111 r = hashmap_ensure_put(&network->stacked_netdevs, &string_hash_ops, netdev->ifname, netdev);
112 if (r == -ENOMEM)
113 return log_oom();
114 if (r < 0)
115 log_warning_errno(r, "%s: Failed to add NetDev '%s' to network, ignoring: %m",
116 network->filename, (const char *) name);
117
118 netdev = NULL;
119 }
120
121 return 0;
122 }
123
124 int network_verify(Network *network) {
125 int r;
126
127 assert(network);
128 assert(network->manager);
129 assert(network->filename);
130
131 if (net_match_is_empty(&network->match) && !network->conditions)
132 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
133 "%s: No valid settings found in the [Match] section, ignoring file. "
134 "To match all interfaces, add Name=* in the [Match] section.",
135 network->filename);
136
137 /* skip out early if configuration does not match the environment */
138 if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
139 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
140 "%s: Conditions in the file do not match the system environment, skipping.",
141 network->filename);
142
143 if (network->keep_master) {
144 if (network->batadv_name)
145 log_warning("%s: BatmanAdvanced= set with KeepMaster= enabled, ignoring BatmanAdvanced=.",
146 network->filename);
147 if (network->bond_name)
148 log_warning("%s: Bond= set with KeepMaster= enabled, ignoring Bond=.",
149 network->filename);
150 if (network->bridge_name)
151 log_warning("%s: Bridge= set with KeepMaster= enabled, ignoring Bridge=.",
152 network->filename);
153 if (network->vrf_name)
154 log_warning("%s: VRF= set with KeepMaster= enabled, ignoring VRF=.",
155 network->filename);
156
157 network->batadv_name = mfree(network->batadv_name);
158 network->bond_name = mfree(network->bond_name);
159 network->bridge_name = mfree(network->bridge_name);
160 network->vrf_name = mfree(network->vrf_name);
161 }
162
163 (void) network_resolve_netdev_one(network, network->batadv_name, NETDEV_KIND_BATADV, &network->batadv);
164 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
165 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
166 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
167 r = network_resolve_stacked_netdevs(network);
168 if (r < 0)
169 return r;
170
171 /* Free unnecessary entries. */
172 network->batadv_name = mfree(network->batadv_name);
173 network->bond_name = mfree(network->bond_name);
174 network->bridge_name = mfree(network->bridge_name);
175 network->vrf_name = mfree(network->vrf_name);
176 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
177
178 if (network->bond) {
179 /* Bonding slave does not support addressing. */
180 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
181 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
182 network->filename);
183 network->link_local = ADDRESS_FAMILY_NO;
184 }
185 if (network->dhcp_server) {
186 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
187 network->filename);
188 network->dhcp_server = false;
189 }
190 if (!ordered_hashmap_isempty(network->addresses_by_section))
191 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
192 network->filename);
193 if (!hashmap_isempty(network->routes_by_section))
194 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
195 network->filename);
196
197 network->addresses_by_section = ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
198 network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
199 }
200
201 if (network->link_local < 0) {
202 network->link_local = ADDRESS_FAMILY_IPV6;
203
204 if (network->keep_master || network->bridge)
205 network->link_local = ADDRESS_FAMILY_NO;
206 else {
207 NetDev *netdev;
208
209 HASHMAP_FOREACH(netdev, network->stacked_netdevs) {
210 MacVlan *m;
211
212 if (netdev->kind == NETDEV_KIND_MACVLAN)
213 m = MACVLAN(netdev);
214 else if (netdev->kind == NETDEV_KIND_MACVTAP)
215 m = MACVTAP(netdev);
216 else
217 continue;
218
219 assert(m);
220
221 if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU)
222 network->link_local = ADDRESS_FAMILY_NO;
223
224 /* There won't be a passthru MACVLAN/MACVTAP if there's already one in another mode */
225 break;
226 }
227 }
228 }
229
230 if (network->ipv6ll_address_gen_mode == IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE)
231 SET_FLAG(network->link_local, ADDRESS_FAMILY_IPV6, false);
232
233 if (in6_addr_is_set(&network->ipv6ll_stable_secret) &&
234 network->ipv6ll_address_gen_mode < 0)
235 network->ipv6ll_address_gen_mode = IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
236
237 /* IPMasquerade implies IPForward */
238 network->ip_forward |= network->ip_masquerade;
239
240 network_adjust_ipv6_proxy_ndp(network);
241 network_adjust_ipv6_accept_ra(network);
242 network_adjust_dhcp(network);
243 network_adjust_radv(network);
244 network_adjust_bridge_vlan(network);
245
246 if (network->mtu > 0 && network->dhcp_use_mtu) {
247 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
248 "Disabling UseMTU=.", network->filename);
249 network->dhcp_use_mtu = false;
250 }
251
252 if (network->dhcp_critical >= 0) {
253 if (network->keep_configuration >= 0) {
254 if (network->manager->keep_configuration < 0)
255 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
256 "Ignoring CriticalConnection=.", network->filename);
257 } else if (network->dhcp_critical)
258 /* CriticalConnection=yes also preserve foreign static configurations. */
259 network->keep_configuration = KEEP_CONFIGURATION_YES;
260 else
261 network->keep_configuration = KEEP_CONFIGURATION_NO;
262 }
263
264 if (!strv_isempty(network->bind_carrier)) {
265 if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND))
266 log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. "
267 "Setting ActivationPolicy=bound.", network->filename);
268 network->activation_policy = ACTIVATION_POLICY_BOUND;
269 } else if (network->activation_policy == ACTIVATION_POLICY_BOUND) {
270 log_warning("%s: ActivationPolicy=bound requires BindCarrier=. "
271 "Ignoring ActivationPolicy=bound.", network->filename);
272 network->activation_policy = ACTIVATION_POLICY_UP;
273 }
274
275 if (network->activation_policy == _ACTIVATION_POLICY_INVALID)
276 network->activation_policy = ACTIVATION_POLICY_UP;
277
278 if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) {
279 if (network->ignore_carrier_loss_set && network->ignore_carrier_loss_usec < USEC_INFINITY)
280 log_warning("%s: IgnoreCarrierLoss=no or finite timespan conflicts with ActivationPolicy=always-up. "
281 "Setting IgnoreCarrierLoss=yes.", network->filename);
282 network->ignore_carrier_loss_set = true;
283 network->ignore_carrier_loss_usec = USEC_INFINITY;
284 }
285
286 if (!network->ignore_carrier_loss_set) {
287 network->ignore_carrier_loss_set = true;
288 network->ignore_carrier_loss_usec = network->configure_without_carrier ? USEC_INFINITY : 0;
289 }
290
291 if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) {
292 if (network->required_for_online < 0 ||
293 (network->required_for_online == true && network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN)) {
294 log_debug("%s: Setting RequiredForOnline=no because ActivationPolicy=%s.", network->filename,
295 activation_policy_to_string(network->activation_policy));
296 network->required_for_online = false;
297 } else if (network->required_for_online == true)
298 log_warning("%s: RequiredForOnline=yes and ActivationPolicy=%s, "
299 "this may cause a delay at boot.", network->filename,
300 activation_policy_to_string(network->activation_policy));
301 }
302
303 if (network->required_for_online < 0)
304 network->required_for_online = true;
305
306 if (network->keep_configuration < 0)
307 network->keep_configuration = KEEP_CONFIGURATION_NO;
308
309 if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
310 log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
311 network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
312 }
313
314 r = network_drop_invalid_addresses(network);
315 if (r < 0)
316 return r; /* network_drop_invalid_addresses() logs internally. */
317 network_drop_invalid_routes(network);
318 network_drop_invalid_nexthops(network);
319 network_drop_invalid_bridge_fdb_entries(network);
320 network_drop_invalid_bridge_mdb_entries(network);
321 network_drop_invalid_neighbors(network);
322 network_drop_invalid_address_labels(network);
323 network_drop_invalid_prefixes(network);
324 network_drop_invalid_route_prefixes(network);
325 network_drop_invalid_routing_policy_rules(network);
326 network_drop_invalid_qdisc(network);
327 network_drop_invalid_tclass(network);
328 r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section);
329 if (r < 0)
330 return r; /* sr_iov_drop_invalid_sections() logs internally. */
331 network_drop_invalid_static_leases(network);
332
333 network_adjust_dhcp_server(network);
334
335 return 0;
336 }
337
338 int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
339 _cleanup_free_ char *fname = NULL, *name = NULL;
340 _cleanup_(network_unrefp) Network *network = NULL;
341 const char *dropin_dirname;
342 char *d;
343 int r;
344
345 assert(manager);
346 assert(filename);
347
348 r = null_or_empty_path(filename);
349 if (r < 0)
350 return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
351 if (r > 0) {
352 log_debug("Skipping empty file: %s", filename);
353 return 0;
354 }
355
356 fname = strdup(filename);
357 if (!fname)
358 return log_oom();
359
360 name = strdup(basename(filename));
361 if (!name)
362 return log_oom();
363
364 d = strrchr(name, '.');
365 if (!d)
366 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file name: %s", filename);
367
368 *d = '\0';
369
370 dropin_dirname = strjoina(name, ".network.d");
371
372 network = new(Network, 1);
373 if (!network)
374 return log_oom();
375
376 *network = (Network) {
377 .filename = TAKE_PTR(fname),
378 .name = TAKE_PTR(name),
379
380 .manager = manager,
381 .n_ref = 1,
382
383 .required_for_online = -1,
384 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
385 .activation_policy = _ACTIVATION_POLICY_INVALID,
386 .group = -1,
387 .arp = -1,
388 .multicast = -1,
389 .allmulticast = -1,
390 .promiscuous = -1,
391
392 .keep_configuration = manager->keep_configuration,
393
394 .dhcp_duid.type = _DUID_TYPE_INVALID,
395 .dhcp_critical = -1,
396 .dhcp_use_ntp = true,
397 .dhcp_routes_to_ntp = true,
398 .dhcp_use_sip = true,
399 .dhcp_use_dns = true,
400 .dhcp_routes_to_dns = true,
401 .dhcp_use_hostname = true,
402 .dhcp_use_routes = true,
403 .dhcp_use_gateway = -1,
404 .dhcp_send_hostname = true,
405 .dhcp_send_release = true,
406 .dhcp_route_metric = DHCP_ROUTE_METRIC,
407 .dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
408 .dhcp_route_table = RT_TABLE_MAIN,
409 .dhcp_ip_service_type = -1,
410 .dhcp_broadcast = -1,
411
412 .dhcp6_use_address = true,
413 .dhcp6_use_pd_prefix = true,
414 .dhcp6_use_dns = true,
415 .dhcp6_use_hostname = true,
416 .dhcp6_use_ntp = true,
417 .dhcp6_use_rapid_commit = true,
418 .dhcp6_duid.type = _DUID_TYPE_INVALID,
419 .dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
420
421 .dhcp_pd = -1,
422 .dhcp_pd_announce = true,
423 .dhcp_pd_assign = true,
424 .dhcp_pd_manage_temporary_address = true,
425 .dhcp_pd_subnet_id = -1,
426 .dhcp_pd_route_metric = DHCP6PD_ROUTE_METRIC,
427
428 .dhcp_server_bind_to_interface = true,
429 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
430 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
431 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
432 .dhcp_server_emit_router = true,
433 .dhcp_server_emit_timezone = true,
434
435 .router_lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
436 .router_dns_lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
437 .router_emit_dns = true,
438 .router_emit_domains = true,
439
440 .use_bpdu = -1,
441 .hairpin = -1,
442 .isolated = -1,
443 .fast_leave = -1,
444 .allow_port_to_be_root = -1,
445 .unicast_flood = -1,
446 .multicast_flood = -1,
447 .multicast_to_unicast = -1,
448 .neighbor_suppression = -1,
449 .learning = -1,
450 .bridge_proxy_arp = -1,
451 .bridge_proxy_arp_wifi = -1,
452 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
453 .multicast_router = _MULTICAST_ROUTER_INVALID,
454
455 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
456 .lldp_multicast_mode = _SD_LLDP_MULTICAST_MODE_INVALID,
457
458 .dns_default_route = -1,
459 .llmnr = RESOLVE_SUPPORT_YES,
460 .mdns = RESOLVE_SUPPORT_NO,
461 .dnssec_mode = _DNSSEC_MODE_INVALID,
462 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
463
464 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
465 .link_local = _ADDRESS_FAMILY_INVALID,
466 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
467
468 .ipv4_accept_local = -1,
469 .ipv4_route_localnet = -1,
470 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
471 .ipv6_dad_transmits = -1,
472 .ipv6_hop_limit = -1,
473 .ipv6_proxy_ndp = -1,
474 .proxy_arp = -1,
475
476 .ipv6_accept_ra = -1,
477 .ipv6_accept_ra_use_dns = true,
478 .ipv6_accept_ra_use_gateway = true,
479 .ipv6_accept_ra_use_route_prefix = true,
480 .ipv6_accept_ra_use_autonomous_prefix = true,
481 .ipv6_accept_ra_use_onlink_prefix = true,
482 .ipv6_accept_ra_use_mtu = true,
483 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
484 .ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
485 .ipv6_accept_ra_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
486 .ipv6_accept_ra_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
487 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
488
489 .can_termination = -1,
490
491 .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
492 .ipoib_umcast = -1,
493 };
494
495 r = config_parse_many(
496 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
497 "Match\0"
498 "Link\0"
499 "SR-IOV\0"
500 "Network\0"
501 "Address\0"
502 "Neighbor\0"
503 "IPv6AddressLabel\0"
504 "RoutingPolicyRule\0"
505 "Route\0"
506 "NextHop\0"
507 "DHCP\0" /* compat */
508 "DHCPv4\0"
509 "DHCPv6\0"
510 "DHCPv6PrefixDelegation\0" /* compat */
511 "DHCPPrefixDelegation\0"
512 "DHCPServer\0"
513 "DHCPServerStaticLease\0"
514 "IPv6AcceptRA\0"
515 "IPv6NDPProxyAddress\0"
516 "Bridge\0"
517 "BridgeFDB\0"
518 "BridgeMDB\0"
519 "BridgeVLAN\0"
520 "IPv6SendRA\0"
521 "IPv6PrefixDelegation\0"
522 "IPv6Prefix\0"
523 "IPv6RoutePrefix\0"
524 "LLDP\0"
525 "TrafficControlQueueingDiscipline\0"
526 "CAN\0"
527 "QDisc\0"
528 "BFIFO\0"
529 "CAKE\0"
530 "ControlledDelay\0"
531 "DeficitRoundRobinScheduler\0"
532 "DeficitRoundRobinSchedulerClass\0"
533 "EnhancedTransmissionSelection\0"
534 "FairQueueing\0"
535 "FairQueueingControlledDelay\0"
536 "FlowQueuePIE\0"
537 "GenericRandomEarlyDetection\0"
538 "HeavyHitterFilter\0"
539 "HierarchyTokenBucket\0"
540 "HierarchyTokenBucketClass\0"
541 "NetworkEmulator\0"
542 "PFIFO\0"
543 "PFIFOFast\0"
544 "PFIFOHeadDrop\0"
545 "PIE\0"
546 "QuickFairQueueing\0"
547 "QuickFairQueueingClass\0"
548 "StochasticFairBlue\0"
549 "StochasticFairnessQueueing\0"
550 "TokenBucketFilter\0"
551 "TrivialLinkEqualizer\0",
552 config_item_perf_lookup, network_network_gperf_lookup,
553 CONFIG_PARSE_WARN,
554 network,
555 &network->stats_by_path,
556 NULL);
557 if (r < 0)
558 return r; /* config_parse_many() logs internally. */
559
560 r = network_add_ipv4ll_route(network);
561 if (r < 0)
562 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
563
564 r = network_add_default_route_on_device(network);
565 if (r < 0)
566 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
567 network->filename);
568
569 r = network_verify(network);
570 if (r < 0)
571 return r; /* network_verify() logs internally. */
572
573 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
574 if (r < 0)
575 return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
576
577 TAKE_PTR(network);
578 return 0;
579 }
580
581 int network_load(Manager *manager, OrderedHashmap **networks) {
582 _cleanup_strv_free_ char **files = NULL;
583 int r;
584
585 assert(manager);
586
587 ordered_hashmap_clear_with_destructor(*networks, network_unref);
588
589 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
590 if (r < 0)
591 return log_error_errno(r, "Failed to enumerate network files: %m");
592
593 STRV_FOREACH(f, files)
594 (void) network_load_one(manager, networks, *f);
595
596 return 0;
597 }
598
599 int network_reload(Manager *manager) {
600 OrderedHashmap *new_networks = NULL;
601 Network *n, *old;
602 int r;
603
604 assert(manager);
605
606 r = network_load(manager, &new_networks);
607 if (r < 0)
608 goto failure;
609
610 ORDERED_HASHMAP_FOREACH(n, new_networks) {
611 r = network_get_by_name(manager, n->name, &old);
612 if (r < 0) {
613 log_debug("Found new .network file: %s", n->filename);
614 continue;
615 }
616
617 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
618 log_debug("Found updated .network file: %s", n->filename);
619 continue;
620 }
621
622 r = ordered_hashmap_replace(new_networks, old->name, old);
623 if (r < 0)
624 goto failure;
625
626 network_ref(old);
627 network_unref(n);
628 }
629
630 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
631 manager->networks = new_networks;
632
633 return manager_build_dhcp_pd_subnet_ids(manager);
634
635 failure:
636 ordered_hashmap_free_with_destructor(new_networks, network_unref);
637
638 return r;
639 }
640
641 int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
642 Network *n;
643 int r;
644
645 assert(manager);
646
647 set_clear(manager->dhcp_pd_subnet_ids);
648
649 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
650 if (n->unmanaged)
651 continue;
652
653 if (!n->dhcp_pd)
654 continue;
655
656 if (n->dhcp_pd_subnet_id < 0)
657 continue;
658
659 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
660 if (r < 0)
661 return r;
662 }
663
664 return 0;
665 }
666
667 static Network *network_free(Network *network) {
668 if (!network)
669 return NULL;
670
671 free(network->name);
672 free(network->filename);
673 free(network->description);
674 hashmap_free(network->stats_by_path);
675
676 /* conditions */
677 net_match_clear(&network->match);
678 condition_free_list(network->conditions);
679
680 /* link settings */
681 strv_free(network->bind_carrier);
682
683 /* NTP */
684 strv_free(network->ntp);
685
686 /* DNS */
687 for (unsigned i = 0; i < network->n_dns; i++)
688 in_addr_full_free(network->dns[i]);
689 free(network->dns);
690 ordered_set_free(network->search_domains);
691 ordered_set_free(network->route_domains);
692 set_free_free(network->dnssec_negative_trust_anchors);
693
694 /* DHCP server */
695 free(network->dhcp_server_relay_agent_circuit_id);
696 free(network->dhcp_server_relay_agent_remote_id);
697 free(network->dhcp_server_boot_server_name);
698 free(network->dhcp_server_boot_filename);
699 free(network->dhcp_server_timezone);
700 free(network->dhcp_server_uplink_name);
701 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
702 free(network->dhcp_server_emit[t].addresses);
703 ordered_hashmap_free(network->dhcp_server_send_options);
704 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
705
706 /* DHCP client */
707 free(network->dhcp_vendor_class_identifier);
708 free(network->dhcp_mudurl);
709 free(network->dhcp_hostname);
710 free(network->dhcp_label);
711 set_free(network->dhcp_deny_listed_ip);
712 set_free(network->dhcp_allow_listed_ip);
713 strv_free(network->dhcp_user_class);
714 set_free(network->dhcp_request_options);
715 ordered_hashmap_free(network->dhcp_client_send_options);
716 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
717 free(network->dhcp_netlabel);
718
719 /* DHCPv6 client */
720 free(network->dhcp6_mudurl);
721 strv_free(network->dhcp6_user_class);
722 strv_free(network->dhcp6_vendor_class);
723 set_free(network->dhcp6_request_options);
724 ordered_hashmap_free(network->dhcp6_client_send_options);
725 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
726 free(network->dhcp6_netlabel);
727
728 /* DHCP PD */
729 free(network->dhcp_pd_uplink_name);
730 set_free(network->dhcp_pd_tokens);
731 free(network->dhcp_pd_netlabel);
732
733 /* Router advertisement */
734 ordered_set_free(network->router_search_domains);
735 free(network->router_dns);
736 free(network->router_uplink_name);
737
738 /* NDisc */
739 set_free(network->ndisc_deny_listed_router);
740 set_free(network->ndisc_allow_listed_router);
741 set_free(network->ndisc_deny_listed_prefix);
742 set_free(network->ndisc_allow_listed_prefix);
743 set_free(network->ndisc_deny_listed_route_prefix);
744 set_free(network->ndisc_allow_listed_route_prefix);
745 set_free(network->ndisc_tokens);
746 free(network->ndisc_netlabel);
747
748 /* LLDP */
749 free(network->lldp_mudurl);
750
751 /* netdev */
752 free(network->batadv_name);
753 free(network->bridge_name);
754 free(network->bond_name);
755 free(network->vrf_name);
756 hashmap_free_free_key(network->stacked_netdev_names);
757 netdev_unref(network->bridge);
758 netdev_unref(network->bond);
759 netdev_unref(network->vrf);
760 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
761
762 /* static configs */
763 set_free_free(network->ipv6_proxy_ndp_addresses);
764 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
765 hashmap_free_with_destructor(network->routes_by_section, route_free);
766 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
767 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
768 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
769 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
770 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
771 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
772 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
773 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
774 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
775 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
776 hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free);
777 hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
778
779 return mfree(network);
780 }
781
782 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
783
784 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
785 Network *network;
786
787 assert(manager);
788 assert(name);
789 assert(ret);
790
791 network = ordered_hashmap_get(manager->networks, name);
792 if (!network)
793 return -ENOENT;
794
795 *ret = network;
796
797 return 0;
798 }
799
800 bool network_has_static_ipv6_configurations(Network *network) {
801 Address *address;
802 Route *route;
803 BridgeFDB *fdb;
804 BridgeMDB *mdb;
805 Neighbor *neighbor;
806
807 assert(network);
808
809 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
810 if (address->family == AF_INET6)
811 return true;
812
813 HASHMAP_FOREACH(route, network->routes_by_section)
814 if (route->family == AF_INET6)
815 return true;
816
817 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
818 if (fdb->family == AF_INET6)
819 return true;
820
821 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
822 if (mdb->family == AF_INET6)
823 return true;
824
825 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
826 if (neighbor->family == AF_INET6)
827 return true;
828
829 if (!hashmap_isempty(network->address_labels_by_section))
830 return true;
831
832 if (!hashmap_isempty(network->prefixes_by_section))
833 return true;
834
835 if (!hashmap_isempty(network->route_prefixes_by_section))
836 return true;
837
838 return false;
839 }
840
841 int config_parse_stacked_netdev(
842 const char *unit,
843 const char *filename,
844 unsigned line,
845 const char *section,
846 unsigned section_line,
847 const char *lvalue,
848 int ltype,
849 const char *rvalue,
850 void *data,
851 void *userdata) {
852
853 _cleanup_free_ char *name = NULL;
854 NetDevKind kind = ltype;
855 Hashmap **h = ASSERT_PTR(data);
856 int r;
857
858 assert(filename);
859 assert(lvalue);
860 assert(rvalue);
861 assert(IN_SET(kind,
862 NETDEV_KIND_IPOIB,
863 NETDEV_KIND_IPVLAN,
864 NETDEV_KIND_IPVTAP,
865 NETDEV_KIND_MACSEC,
866 NETDEV_KIND_MACVLAN,
867 NETDEV_KIND_MACVTAP,
868 NETDEV_KIND_VLAN,
869 NETDEV_KIND_VXLAN,
870 NETDEV_KIND_XFRM,
871 _NETDEV_KIND_TUNNEL));
872
873 if (!ifname_valid(rvalue)) {
874 log_syntax(unit, LOG_WARNING, filename, line, 0,
875 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
876 return 0;
877 }
878
879 name = strdup(rvalue);
880 if (!name)
881 return log_oom();
882
883 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
884 if (r == -ENOMEM)
885 return log_oom();
886 if (r < 0)
887 log_syntax(unit, LOG_WARNING, filename, line, r,
888 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
889 else if (r == 0)
890 log_syntax(unit, LOG_DEBUG, filename, line, r,
891 "NetDev '%s' specified twice, ignoring.", name);
892 else
893 TAKE_PTR(name);
894
895 return 0;
896 }
897
898 int config_parse_domains(
899 const char *unit,
900 const char *filename,
901 unsigned line,
902 const char *section,
903 unsigned section_line,
904 const char *lvalue,
905 int ltype,
906 const char *rvalue,
907 void *data,
908 void *userdata) {
909
910 Network *n = ASSERT_PTR(userdata);
911 int r;
912
913 assert(filename);
914 assert(lvalue);
915 assert(rvalue);
916
917 if (isempty(rvalue)) {
918 n->search_domains = ordered_set_free(n->search_domains);
919 n->route_domains = ordered_set_free(n->route_domains);
920 return 0;
921 }
922
923 for (const char *p = rvalue;;) {
924 _cleanup_free_ char *w = NULL, *normalized = NULL;
925 const char *domain;
926 bool is_route;
927
928 r = extract_first_word(&p, &w, NULL, 0);
929 if (r == -ENOMEM)
930 return log_oom();
931 if (r < 0) {
932 log_syntax(unit, LOG_WARNING, filename, line, r,
933 "Failed to extract search or route domain, ignoring: %s", rvalue);
934 return 0;
935 }
936 if (r == 0)
937 return 0;
938
939 is_route = w[0] == '~';
940 domain = is_route ? w + 1 : w;
941
942 if (dns_name_is_root(domain) || streq(domain, "*")) {
943 /* If the root domain appears as is, or the special token "*" is found, we'll
944 * consider this as routing domain, unconditionally. */
945 is_route = true;
946 domain = "."; /* make sure we don't allow empty strings, thus write the root
947 * domain as "." */
948 } else {
949 r = dns_name_normalize(domain, 0, &normalized);
950 if (r < 0) {
951 log_syntax(unit, LOG_WARNING, filename, line, r,
952 "'%s' is not a valid domain name, ignoring.", domain);
953 continue;
954 }
955
956 domain = normalized;
957
958 if (is_localhost(domain)) {
959 log_syntax(unit, LOG_WARNING, filename, line, 0,
960 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
961 domain);
962 continue;
963 }
964 }
965
966 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
967 r = ordered_set_put_strdup(set, domain);
968 if (r == -EEXIST)
969 continue;
970 if (r < 0)
971 return log_oom();
972 }
973 }
974
975 int config_parse_timezone(
976 const char *unit,
977 const char *filename,
978 unsigned line,
979 const char *section,
980 unsigned section_line,
981 const char *lvalue,
982 int ltype,
983 const char *rvalue,
984 void *data,
985 void *userdata) {
986
987 char **tz = ASSERT_PTR(data);
988 int r;
989
990 assert(filename);
991 assert(lvalue);
992 assert(rvalue);
993
994 if (isempty(rvalue)) {
995 *tz = mfree(*tz);
996 return 0;
997 }
998
999 r = verify_timezone(rvalue, LOG_WARNING);
1000 if (r < 0) {
1001 log_syntax(unit, LOG_WARNING, filename, line, r,
1002 "Timezone is not valid, ignoring assignment: %s", rvalue);
1003 return 0;
1004 }
1005
1006 return free_and_strdup_warn(tz, rvalue);
1007 }
1008
1009 int config_parse_dns(
1010 const char *unit,
1011 const char *filename,
1012 unsigned line,
1013 const char *section,
1014 unsigned section_line,
1015 const char *lvalue,
1016 int ltype,
1017 const char *rvalue,
1018 void *data,
1019 void *userdata) {
1020
1021 Network *n = ASSERT_PTR(userdata);
1022 int r;
1023
1024 assert(filename);
1025 assert(lvalue);
1026 assert(rvalue);
1027
1028 if (isempty(rvalue)) {
1029 for (unsigned i = 0; i < n->n_dns; i++)
1030 in_addr_full_free(n->dns[i]);
1031 n->dns = mfree(n->dns);
1032 n->n_dns = 0;
1033 return 0;
1034 }
1035
1036 for (const char *p = rvalue;;) {
1037 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
1038 _cleanup_free_ char *w = NULL;
1039 struct in_addr_full **m;
1040
1041 r = extract_first_word(&p, &w, NULL, 0);
1042 if (r == -ENOMEM)
1043 return log_oom();
1044 if (r < 0) {
1045 log_syntax(unit, LOG_WARNING, filename, line, r,
1046 "Invalid syntax, ignoring: %s", rvalue);
1047 return 0;
1048 }
1049 if (r == 0)
1050 return 0;
1051
1052 r = in_addr_full_new_from_string(w, &dns);
1053 if (r < 0) {
1054 log_syntax(unit, LOG_WARNING, filename, line, r,
1055 "Failed to parse dns server address, ignoring: %s", w);
1056 continue;
1057 }
1058
1059 if (IN_SET(dns->port, 53, 853))
1060 dns->port = 0;
1061
1062 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
1063 if (!m)
1064 return log_oom();
1065
1066 m[n->n_dns++] = TAKE_PTR(dns);
1067 n->dns = m;
1068 }
1069 }
1070
1071 int config_parse_dnssec_negative_trust_anchors(
1072 const char *unit,
1073 const char *filename,
1074 unsigned line,
1075 const char *section,
1076 unsigned section_line,
1077 const char *lvalue,
1078 int ltype,
1079 const char *rvalue,
1080 void *data,
1081 void *userdata) {
1082
1083 Set **nta = ASSERT_PTR(data);
1084 int r;
1085
1086 assert(filename);
1087 assert(lvalue);
1088 assert(rvalue);
1089
1090 if (isempty(rvalue)) {
1091 *nta = set_free_free(*nta);
1092 return 0;
1093 }
1094
1095 for (const char *p = rvalue;;) {
1096 _cleanup_free_ char *w = NULL;
1097
1098 r = extract_first_word(&p, &w, NULL, 0);
1099 if (r == -ENOMEM)
1100 return log_oom();
1101 if (r < 0) {
1102 log_syntax(unit, LOG_WARNING, filename, line, r,
1103 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1104 return 0;
1105 }
1106 if (r == 0)
1107 return 0;
1108
1109 r = dns_name_is_valid(w);
1110 if (r <= 0) {
1111 log_syntax(unit, LOG_WARNING, filename, line, r,
1112 "%s is not a valid domain name, ignoring.", w);
1113 continue;
1114 }
1115
1116 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
1117 if (r < 0)
1118 return log_oom();
1119 }
1120 }
1121
1122 int config_parse_ntp(
1123 const char *unit,
1124 const char *filename,
1125 unsigned line,
1126 const char *section,
1127 unsigned section_line,
1128 const char *lvalue,
1129 int ltype,
1130 const char *rvalue,
1131 void *data,
1132 void *userdata) {
1133
1134 char ***l = ASSERT_PTR(data);
1135 int r;
1136
1137 assert(filename);
1138 assert(lvalue);
1139 assert(rvalue);
1140
1141 if (isempty(rvalue)) {
1142 *l = strv_free(*l);
1143 return 0;
1144 }
1145
1146 for (const char *p = rvalue;;) {
1147 _cleanup_free_ char *w = NULL;
1148
1149 r = extract_first_word(&p, &w, NULL, 0);
1150 if (r == -ENOMEM)
1151 return log_oom();
1152 if (r < 0) {
1153 log_syntax(unit, LOG_WARNING, filename, line, r,
1154 "Failed to extract NTP server name, ignoring: %s", rvalue);
1155 return 0;
1156 }
1157 if (r == 0)
1158 return 0;
1159
1160 r = dns_name_is_valid_or_address(w);
1161 if (r <= 0) {
1162 log_syntax(unit, LOG_WARNING, filename, line, r,
1163 "%s is not a valid domain name or IP address, ignoring.", w);
1164 continue;
1165 }
1166
1167 if (strv_length(*l) > MAX_NTP_SERVERS) {
1168 log_syntax(unit, LOG_WARNING, filename, line, 0,
1169 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1170 MAX_NTP_SERVERS, w);
1171 return 0;
1172 }
1173
1174 r = strv_consume(l, TAKE_PTR(w));
1175 if (r < 0)
1176 return log_oom();
1177 }
1178 }
1179
1180 int config_parse_required_for_online(
1181 const char *unit,
1182 const char *filename,
1183 unsigned line,
1184 const char *section,
1185 unsigned section_line,
1186 const char *lvalue,
1187 int ltype,
1188 const char *rvalue,
1189 void *data,
1190 void *userdata) {
1191
1192 Network *network = ASSERT_PTR(userdata);
1193 LinkOperationalStateRange range;
1194 bool required = true;
1195 int r;
1196
1197 assert(filename);
1198 assert(lvalue);
1199 assert(rvalue);
1200
1201 if (isempty(rvalue)) {
1202 network->required_for_online = -1;
1203 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1204 return 0;
1205 }
1206
1207 r = parse_operational_state_range(rvalue, &range);
1208 if (r < 0) {
1209 r = parse_boolean(rvalue);
1210 if (r < 0) {
1211 log_syntax(unit, LOG_WARNING, filename, line, r,
1212 "Failed to parse %s= setting, ignoring assignment: %s",
1213 lvalue, rvalue);
1214 return 0;
1215 }
1216
1217 required = r;
1218 range = LINK_OPERSTATE_RANGE_DEFAULT;
1219 }
1220
1221 network->required_for_online = required;
1222 network->required_operstate_for_online = range;
1223
1224 return 0;
1225 }
1226
1227 int config_parse_link_group(
1228 const char *unit,
1229 const char *filename,
1230 unsigned line,
1231 const char *section,
1232 unsigned section_line,
1233 const char *lvalue,
1234 int ltype,
1235 const char *rvalue,
1236 void *data,
1237 void *userdata) {
1238
1239 Network *network = ASSERT_PTR(userdata);
1240 int r;
1241 int32_t group;
1242
1243 assert(filename);
1244 assert(lvalue);
1245 assert(rvalue);
1246
1247 if (isempty(rvalue)) {
1248 network->group = -1;
1249 return 0;
1250 }
1251
1252 r = safe_atoi32(rvalue, &group);
1253 if (r < 0) {
1254 log_syntax(unit, LOG_WARNING, filename, line, r,
1255 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1256 return 0;
1257 }
1258
1259 if (group < 0) {
1260 log_syntax(unit, LOG_WARNING, filename, line, r,
1261 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1262 return 0;
1263 }
1264
1265 network->group = group;
1266 return 0;
1267 }
1268
1269 int config_parse_ignore_carrier_loss(
1270 const char *unit,
1271 const char *filename,
1272 unsigned line,
1273 const char *section,
1274 unsigned section_line,
1275 const char *lvalue,
1276 int ltype,
1277 const char *rvalue,
1278 void *data,
1279 void *userdata) {
1280
1281 Network *network = ASSERT_PTR(userdata);
1282 usec_t usec;
1283 int r;
1284
1285 assert(filename);
1286 assert(lvalue);
1287 assert(rvalue);
1288
1289 if (isempty(rvalue)) {
1290 network->ignore_carrier_loss_set = false;
1291 return 0;
1292 }
1293
1294 r = parse_boolean(rvalue);
1295 if (r >= 0) {
1296 network->ignore_carrier_loss_set = true;
1297 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1298 return 0;
1299 }
1300
1301 r = parse_sec(rvalue, &usec);
1302 if (r < 0) {
1303 log_syntax(unit, LOG_WARNING, filename, line, r,
1304 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1305 return 0;
1306 }
1307
1308 network->ignore_carrier_loss_set = true;
1309 network->ignore_carrier_loss_usec = usec;
1310 return 0;
1311 }
1312
1313 DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1314 "Failed to parse RequiredFamilyForOnline= setting");
1315
1316 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1317 "Failed to parse KeepConfiguration= setting");
1318
1319 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1320 [KEEP_CONFIGURATION_NO] = "no",
1321 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1322 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1323 [KEEP_CONFIGURATION_STATIC] = "static",
1324 [KEEP_CONFIGURATION_YES] = "yes",
1325 };
1326
1327 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
1328
1329 static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1330 [ACTIVATION_POLICY_UP] = "up",
1331 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1332 [ACTIVATION_POLICY_MANUAL] = "manual",
1333 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1334 [ACTIVATION_POLICY_DOWN] = "down",
1335 [ACTIVATION_POLICY_BOUND] = "bound",
1336 };
1337
1338 DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1339 DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");