]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
tree-wide: use ASSERT_PTR more
[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 = DHCP_ROUTE_METRIC,
485 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
486
487 .can_termination = -1,
488
489 .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
490 .ipoib_umcast = -1,
491 };
492
493 r = config_parse_many(
494 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
495 "Match\0"
496 "Link\0"
497 "SR-IOV\0"
498 "Network\0"
499 "Address\0"
500 "Neighbor\0"
501 "IPv6AddressLabel\0"
502 "RoutingPolicyRule\0"
503 "Route\0"
504 "NextHop\0"
505 "DHCP\0" /* compat */
506 "DHCPv4\0"
507 "DHCPv6\0"
508 "DHCPv6PrefixDelegation\0" /* compat */
509 "DHCPPrefixDelegation\0"
510 "DHCPServer\0"
511 "DHCPServerStaticLease\0"
512 "IPv6AcceptRA\0"
513 "IPv6NDPProxyAddress\0"
514 "Bridge\0"
515 "BridgeFDB\0"
516 "BridgeMDB\0"
517 "BridgeVLAN\0"
518 "IPv6SendRA\0"
519 "IPv6PrefixDelegation\0"
520 "IPv6Prefix\0"
521 "IPv6RoutePrefix\0"
522 "LLDP\0"
523 "TrafficControlQueueingDiscipline\0"
524 "CAN\0"
525 "QDisc\0"
526 "BFIFO\0"
527 "CAKE\0"
528 "ControlledDelay\0"
529 "DeficitRoundRobinScheduler\0"
530 "DeficitRoundRobinSchedulerClass\0"
531 "EnhancedTransmissionSelection\0"
532 "FairQueueing\0"
533 "FairQueueingControlledDelay\0"
534 "FlowQueuePIE\0"
535 "GenericRandomEarlyDetection\0"
536 "HeavyHitterFilter\0"
537 "HierarchyTokenBucket\0"
538 "HierarchyTokenBucketClass\0"
539 "NetworkEmulator\0"
540 "PFIFO\0"
541 "PFIFOFast\0"
542 "PFIFOHeadDrop\0"
543 "PIE\0"
544 "QuickFairQueueing\0"
545 "QuickFairQueueingClass\0"
546 "StochasticFairBlue\0"
547 "StochasticFairnessQueueing\0"
548 "TokenBucketFilter\0"
549 "TrivialLinkEqualizer\0",
550 config_item_perf_lookup, network_network_gperf_lookup,
551 CONFIG_PARSE_WARN,
552 network,
553 &network->stats_by_path,
554 NULL);
555 if (r < 0)
556 return r; /* config_parse_many() logs internally. */
557
558 r = network_add_ipv4ll_route(network);
559 if (r < 0)
560 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
561
562 r = network_add_default_route_on_device(network);
563 if (r < 0)
564 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
565 network->filename);
566
567 r = network_verify(network);
568 if (r < 0)
569 return r; /* network_verify() logs internally. */
570
571 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
572 if (r < 0)
573 return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
574
575 TAKE_PTR(network);
576 return 0;
577 }
578
579 int network_load(Manager *manager, OrderedHashmap **networks) {
580 _cleanup_strv_free_ char **files = NULL;
581 int r;
582
583 assert(manager);
584
585 ordered_hashmap_clear_with_destructor(*networks, network_unref);
586
587 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
588 if (r < 0)
589 return log_error_errno(r, "Failed to enumerate network files: %m");
590
591 STRV_FOREACH(f, files)
592 (void) network_load_one(manager, networks, *f);
593
594 return 0;
595 }
596
597 int network_reload(Manager *manager) {
598 OrderedHashmap *new_networks = NULL;
599 Network *n, *old;
600 int r;
601
602 assert(manager);
603
604 r = network_load(manager, &new_networks);
605 if (r < 0)
606 goto failure;
607
608 ORDERED_HASHMAP_FOREACH(n, new_networks) {
609 r = network_get_by_name(manager, n->name, &old);
610 if (r < 0) {
611 log_debug("Found new .network file: %s", n->filename);
612 continue;
613 }
614
615 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
616 log_debug("Found updated .network file: %s", n->filename);
617 continue;
618 }
619
620 r = ordered_hashmap_replace(new_networks, old->name, old);
621 if (r < 0)
622 goto failure;
623
624 network_ref(old);
625 network_unref(n);
626 }
627
628 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
629 manager->networks = new_networks;
630
631 return manager_build_dhcp_pd_subnet_ids(manager);
632
633 failure:
634 ordered_hashmap_free_with_destructor(new_networks, network_unref);
635
636 return r;
637 }
638
639 int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
640 Network *n;
641 int r;
642
643 assert(manager);
644
645 set_clear(manager->dhcp_pd_subnet_ids);
646
647 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
648 if (n->unmanaged)
649 continue;
650
651 if (!n->dhcp_pd)
652 continue;
653
654 if (n->dhcp_pd_subnet_id < 0)
655 continue;
656
657 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
658 if (r < 0)
659 return r;
660 }
661
662 return 0;
663 }
664
665 static Network *network_free(Network *network) {
666 if (!network)
667 return NULL;
668
669 free(network->name);
670 free(network->filename);
671 free(network->description);
672 hashmap_free(network->stats_by_path);
673
674 /* conditions */
675 net_match_clear(&network->match);
676 condition_free_list(network->conditions);
677
678 /* link settings */
679 strv_free(network->bind_carrier);
680
681 /* NTP */
682 strv_free(network->ntp);
683
684 /* DNS */
685 for (unsigned i = 0; i < network->n_dns; i++)
686 in_addr_full_free(network->dns[i]);
687 free(network->dns);
688 ordered_set_free(network->search_domains);
689 ordered_set_free(network->route_domains);
690 set_free_free(network->dnssec_negative_trust_anchors);
691
692 /* DHCP server */
693 free(network->dhcp_server_relay_agent_circuit_id);
694 free(network->dhcp_server_relay_agent_remote_id);
695 free(network->dhcp_server_boot_server_name);
696 free(network->dhcp_server_boot_filename);
697 free(network->dhcp_server_timezone);
698 free(network->dhcp_server_uplink_name);
699 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
700 free(network->dhcp_server_emit[t].addresses);
701 ordered_hashmap_free(network->dhcp_server_send_options);
702 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
703
704 /* DHCP client */
705 free(network->dhcp_vendor_class_identifier);
706 free(network->dhcp_mudurl);
707 free(network->dhcp_hostname);
708 free(network->dhcp_label);
709 set_free(network->dhcp_deny_listed_ip);
710 set_free(network->dhcp_allow_listed_ip);
711 strv_free(network->dhcp_user_class);
712 set_free(network->dhcp_request_options);
713 ordered_hashmap_free(network->dhcp_client_send_options);
714 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
715 free(network->dhcp_netlabel);
716
717 /* DHCPv6 client */
718 free(network->dhcp6_mudurl);
719 strv_free(network->dhcp6_user_class);
720 strv_free(network->dhcp6_vendor_class);
721 set_free(network->dhcp6_request_options);
722 ordered_hashmap_free(network->dhcp6_client_send_options);
723 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
724 free(network->dhcp6_netlabel);
725
726 /* DHCP PD */
727 free(network->dhcp_pd_uplink_name);
728 set_free(network->dhcp_pd_tokens);
729 free(network->dhcp_pd_netlabel);
730
731 /* Router advertisement */
732 ordered_set_free(network->router_search_domains);
733 free(network->router_dns);
734 free(network->router_uplink_name);
735
736 /* NDisc */
737 set_free(network->ndisc_deny_listed_router);
738 set_free(network->ndisc_allow_listed_router);
739 set_free(network->ndisc_deny_listed_prefix);
740 set_free(network->ndisc_allow_listed_prefix);
741 set_free(network->ndisc_deny_listed_route_prefix);
742 set_free(network->ndisc_allow_listed_route_prefix);
743 set_free(network->ndisc_tokens);
744 free(network->ndisc_netlabel);
745
746 /* LLDP */
747 free(network->lldp_mudurl);
748
749 /* netdev */
750 free(network->batadv_name);
751 free(network->bridge_name);
752 free(network->bond_name);
753 free(network->vrf_name);
754 hashmap_free_free_key(network->stacked_netdev_names);
755 netdev_unref(network->bridge);
756 netdev_unref(network->bond);
757 netdev_unref(network->vrf);
758 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
759
760 /* static configs */
761 set_free_free(network->ipv6_proxy_ndp_addresses);
762 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
763 hashmap_free_with_destructor(network->routes_by_section, route_free);
764 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
765 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
766 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
767 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
768 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
769 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
770 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
771 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
772 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
773 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
774 hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free);
775 hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
776
777 return mfree(network);
778 }
779
780 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
781
782 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
783 Network *network;
784
785 assert(manager);
786 assert(name);
787 assert(ret);
788
789 network = ordered_hashmap_get(manager->networks, name);
790 if (!network)
791 return -ENOENT;
792
793 *ret = network;
794
795 return 0;
796 }
797
798 bool network_has_static_ipv6_configurations(Network *network) {
799 Address *address;
800 Route *route;
801 BridgeFDB *fdb;
802 BridgeMDB *mdb;
803 Neighbor *neighbor;
804
805 assert(network);
806
807 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
808 if (address->family == AF_INET6)
809 return true;
810
811 HASHMAP_FOREACH(route, network->routes_by_section)
812 if (route->family == AF_INET6)
813 return true;
814
815 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
816 if (fdb->family == AF_INET6)
817 return true;
818
819 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
820 if (mdb->family == AF_INET6)
821 return true;
822
823 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
824 if (neighbor->family == AF_INET6)
825 return true;
826
827 if (!hashmap_isempty(network->address_labels_by_section))
828 return true;
829
830 if (!hashmap_isempty(network->prefixes_by_section))
831 return true;
832
833 if (!hashmap_isempty(network->route_prefixes_by_section))
834 return true;
835
836 return false;
837 }
838
839 int config_parse_stacked_netdev(
840 const char *unit,
841 const char *filename,
842 unsigned line,
843 const char *section,
844 unsigned section_line,
845 const char *lvalue,
846 int ltype,
847 const char *rvalue,
848 void *data,
849 void *userdata) {
850
851 _cleanup_free_ char *name = NULL;
852 NetDevKind kind = ltype;
853 Hashmap **h = ASSERT_PTR(data);
854 int r;
855
856 assert(filename);
857 assert(lvalue);
858 assert(rvalue);
859 assert(IN_SET(kind,
860 NETDEV_KIND_IPOIB,
861 NETDEV_KIND_IPVLAN,
862 NETDEV_KIND_IPVTAP,
863 NETDEV_KIND_MACSEC,
864 NETDEV_KIND_MACVLAN,
865 NETDEV_KIND_MACVTAP,
866 NETDEV_KIND_VLAN,
867 NETDEV_KIND_VXLAN,
868 NETDEV_KIND_XFRM,
869 _NETDEV_KIND_TUNNEL));
870
871 if (!ifname_valid(rvalue)) {
872 log_syntax(unit, LOG_WARNING, filename, line, 0,
873 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
874 return 0;
875 }
876
877 name = strdup(rvalue);
878 if (!name)
879 return log_oom();
880
881 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
882 if (r == -ENOMEM)
883 return log_oom();
884 if (r < 0)
885 log_syntax(unit, LOG_WARNING, filename, line, r,
886 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
887 else if (r == 0)
888 log_syntax(unit, LOG_DEBUG, filename, line, r,
889 "NetDev '%s' specified twice, ignoring.", name);
890 else
891 TAKE_PTR(name);
892
893 return 0;
894 }
895
896 int config_parse_domains(
897 const char *unit,
898 const char *filename,
899 unsigned line,
900 const char *section,
901 unsigned section_line,
902 const char *lvalue,
903 int ltype,
904 const char *rvalue,
905 void *data,
906 void *userdata) {
907
908 Network *n = ASSERT_PTR(userdata);
909 int r;
910
911 assert(filename);
912 assert(lvalue);
913 assert(rvalue);
914
915 if (isempty(rvalue)) {
916 n->search_domains = ordered_set_free(n->search_domains);
917 n->route_domains = ordered_set_free(n->route_domains);
918 return 0;
919 }
920
921 for (const char *p = rvalue;;) {
922 _cleanup_free_ char *w = NULL, *normalized = NULL;
923 const char *domain;
924 bool is_route;
925
926 r = extract_first_word(&p, &w, NULL, 0);
927 if (r == -ENOMEM)
928 return log_oom();
929 if (r < 0) {
930 log_syntax(unit, LOG_WARNING, filename, line, r,
931 "Failed to extract search or route domain, ignoring: %s", rvalue);
932 return 0;
933 }
934 if (r == 0)
935 return 0;
936
937 is_route = w[0] == '~';
938 domain = is_route ? w + 1 : w;
939
940 if (dns_name_is_root(domain) || streq(domain, "*")) {
941 /* If the root domain appears as is, or the special token "*" is found, we'll
942 * consider this as routing domain, unconditionally. */
943 is_route = true;
944 domain = "."; /* make sure we don't allow empty strings, thus write the root
945 * domain as "." */
946 } else {
947 r = dns_name_normalize(domain, 0, &normalized);
948 if (r < 0) {
949 log_syntax(unit, LOG_WARNING, filename, line, r,
950 "'%s' is not a valid domain name, ignoring.", domain);
951 continue;
952 }
953
954 domain = normalized;
955
956 if (is_localhost(domain)) {
957 log_syntax(unit, LOG_WARNING, filename, line, 0,
958 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
959 domain);
960 continue;
961 }
962 }
963
964 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
965 r = ordered_set_put_strdup(set, domain);
966 if (r == -EEXIST)
967 continue;
968 if (r < 0)
969 return log_oom();
970 }
971 }
972
973 int config_parse_timezone(
974 const char *unit,
975 const char *filename,
976 unsigned line,
977 const char *section,
978 unsigned section_line,
979 const char *lvalue,
980 int ltype,
981 const char *rvalue,
982 void *data,
983 void *userdata) {
984
985 char **tz = ASSERT_PTR(data);
986 int r;
987
988 assert(filename);
989 assert(lvalue);
990 assert(rvalue);
991
992 if (isempty(rvalue)) {
993 *tz = mfree(*tz);
994 return 0;
995 }
996
997 r = verify_timezone(rvalue, LOG_WARNING);
998 if (r < 0) {
999 log_syntax(unit, LOG_WARNING, filename, line, r,
1000 "Timezone is not valid, ignoring assignment: %s", rvalue);
1001 return 0;
1002 }
1003
1004 return free_and_strdup_warn(tz, rvalue);
1005 }
1006
1007 int config_parse_dns(
1008 const char *unit,
1009 const char *filename,
1010 unsigned line,
1011 const char *section,
1012 unsigned section_line,
1013 const char *lvalue,
1014 int ltype,
1015 const char *rvalue,
1016 void *data,
1017 void *userdata) {
1018
1019 Network *n = ASSERT_PTR(userdata);
1020 int r;
1021
1022 assert(filename);
1023 assert(lvalue);
1024 assert(rvalue);
1025
1026 if (isempty(rvalue)) {
1027 for (unsigned i = 0; i < n->n_dns; i++)
1028 in_addr_full_free(n->dns[i]);
1029 n->dns = mfree(n->dns);
1030 n->n_dns = 0;
1031 return 0;
1032 }
1033
1034 for (const char *p = rvalue;;) {
1035 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
1036 _cleanup_free_ char *w = NULL;
1037 struct in_addr_full **m;
1038
1039 r = extract_first_word(&p, &w, NULL, 0);
1040 if (r == -ENOMEM)
1041 return log_oom();
1042 if (r < 0) {
1043 log_syntax(unit, LOG_WARNING, filename, line, r,
1044 "Invalid syntax, ignoring: %s", rvalue);
1045 return 0;
1046 }
1047 if (r == 0)
1048 return 0;
1049
1050 r = in_addr_full_new_from_string(w, &dns);
1051 if (r < 0) {
1052 log_syntax(unit, LOG_WARNING, filename, line, r,
1053 "Failed to parse dns server address, ignoring: %s", w);
1054 continue;
1055 }
1056
1057 if (IN_SET(dns->port, 53, 853))
1058 dns->port = 0;
1059
1060 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
1061 if (!m)
1062 return log_oom();
1063
1064 m[n->n_dns++] = TAKE_PTR(dns);
1065 n->dns = m;
1066 }
1067 }
1068
1069 int config_parse_dnssec_negative_trust_anchors(
1070 const char *unit,
1071 const char *filename,
1072 unsigned line,
1073 const char *section,
1074 unsigned section_line,
1075 const char *lvalue,
1076 int ltype,
1077 const char *rvalue,
1078 void *data,
1079 void *userdata) {
1080
1081 Set **nta = ASSERT_PTR(data);
1082 int r;
1083
1084 assert(filename);
1085 assert(lvalue);
1086 assert(rvalue);
1087
1088 if (isempty(rvalue)) {
1089 *nta = set_free_free(*nta);
1090 return 0;
1091 }
1092
1093 for (const char *p = rvalue;;) {
1094 _cleanup_free_ char *w = NULL;
1095
1096 r = extract_first_word(&p, &w, NULL, 0);
1097 if (r == -ENOMEM)
1098 return log_oom();
1099 if (r < 0) {
1100 log_syntax(unit, LOG_WARNING, filename, line, r,
1101 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1102 return 0;
1103 }
1104 if (r == 0)
1105 return 0;
1106
1107 r = dns_name_is_valid(w);
1108 if (r <= 0) {
1109 log_syntax(unit, LOG_WARNING, filename, line, r,
1110 "%s is not a valid domain name, ignoring.", w);
1111 continue;
1112 }
1113
1114 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
1115 if (r < 0)
1116 return log_oom();
1117 }
1118 }
1119
1120 int config_parse_ntp(
1121 const char *unit,
1122 const char *filename,
1123 unsigned line,
1124 const char *section,
1125 unsigned section_line,
1126 const char *lvalue,
1127 int ltype,
1128 const char *rvalue,
1129 void *data,
1130 void *userdata) {
1131
1132 char ***l = ASSERT_PTR(data);
1133 int r;
1134
1135 assert(filename);
1136 assert(lvalue);
1137 assert(rvalue);
1138
1139 if (isempty(rvalue)) {
1140 *l = strv_free(*l);
1141 return 0;
1142 }
1143
1144 for (const char *p = rvalue;;) {
1145 _cleanup_free_ char *w = NULL;
1146
1147 r = extract_first_word(&p, &w, NULL, 0);
1148 if (r == -ENOMEM)
1149 return log_oom();
1150 if (r < 0) {
1151 log_syntax(unit, LOG_WARNING, filename, line, r,
1152 "Failed to extract NTP server name, ignoring: %s", rvalue);
1153 return 0;
1154 }
1155 if (r == 0)
1156 return 0;
1157
1158 r = dns_name_is_valid_or_address(w);
1159 if (r <= 0) {
1160 log_syntax(unit, LOG_WARNING, filename, line, r,
1161 "%s is not a valid domain name or IP address, ignoring.", w);
1162 continue;
1163 }
1164
1165 if (strv_length(*l) > MAX_NTP_SERVERS) {
1166 log_syntax(unit, LOG_WARNING, filename, line, 0,
1167 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1168 MAX_NTP_SERVERS, w);
1169 return 0;
1170 }
1171
1172 r = strv_consume(l, TAKE_PTR(w));
1173 if (r < 0)
1174 return log_oom();
1175 }
1176 }
1177
1178 int config_parse_required_for_online(
1179 const char *unit,
1180 const char *filename,
1181 unsigned line,
1182 const char *section,
1183 unsigned section_line,
1184 const char *lvalue,
1185 int ltype,
1186 const char *rvalue,
1187 void *data,
1188 void *userdata) {
1189
1190 Network *network = ASSERT_PTR(userdata);
1191 LinkOperationalStateRange range;
1192 bool required = true;
1193 int r;
1194
1195 assert(filename);
1196 assert(lvalue);
1197 assert(rvalue);
1198
1199 if (isempty(rvalue)) {
1200 network->required_for_online = -1;
1201 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1202 return 0;
1203 }
1204
1205 r = parse_operational_state_range(rvalue, &range);
1206 if (r < 0) {
1207 r = parse_boolean(rvalue);
1208 if (r < 0) {
1209 log_syntax(unit, LOG_WARNING, filename, line, r,
1210 "Failed to parse %s= setting, ignoring assignment: %s",
1211 lvalue, rvalue);
1212 return 0;
1213 }
1214
1215 required = r;
1216 range = LINK_OPERSTATE_RANGE_DEFAULT;
1217 }
1218
1219 network->required_for_online = required;
1220 network->required_operstate_for_online = range;
1221
1222 return 0;
1223 }
1224
1225 int config_parse_link_group(
1226 const char *unit,
1227 const char *filename,
1228 unsigned line,
1229 const char *section,
1230 unsigned section_line,
1231 const char *lvalue,
1232 int ltype,
1233 const char *rvalue,
1234 void *data,
1235 void *userdata) {
1236
1237 Network *network = ASSERT_PTR(userdata);
1238 int r;
1239 int32_t group;
1240
1241 assert(filename);
1242 assert(lvalue);
1243 assert(rvalue);
1244
1245 if (isempty(rvalue)) {
1246 network->group = -1;
1247 return 0;
1248 }
1249
1250 r = safe_atoi32(rvalue, &group);
1251 if (r < 0) {
1252 log_syntax(unit, LOG_WARNING, filename, line, r,
1253 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1254 return 0;
1255 }
1256
1257 if (group < 0) {
1258 log_syntax(unit, LOG_WARNING, filename, line, r,
1259 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1260 return 0;
1261 }
1262
1263 network->group = group;
1264 return 0;
1265 }
1266
1267 int config_parse_ignore_carrier_loss(
1268 const char *unit,
1269 const char *filename,
1270 unsigned line,
1271 const char *section,
1272 unsigned section_line,
1273 const char *lvalue,
1274 int ltype,
1275 const char *rvalue,
1276 void *data,
1277 void *userdata) {
1278
1279 Network *network = ASSERT_PTR(userdata);
1280 usec_t usec;
1281 int r;
1282
1283 assert(filename);
1284 assert(lvalue);
1285 assert(rvalue);
1286
1287 if (isempty(rvalue)) {
1288 network->ignore_carrier_loss_set = false;
1289 return 0;
1290 }
1291
1292 r = parse_boolean(rvalue);
1293 if (r >= 0) {
1294 network->ignore_carrier_loss_set = true;
1295 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1296 return 0;
1297 }
1298
1299 r = parse_sec(rvalue, &usec);
1300 if (r < 0) {
1301 log_syntax(unit, LOG_WARNING, filename, line, r,
1302 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1303 return 0;
1304 }
1305
1306 network->ignore_carrier_loss_set = true;
1307 network->ignore_carrier_loss_usec = usec;
1308 return 0;
1309 }
1310
1311 DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1312 "Failed to parse RequiredFamilyForOnline= setting");
1313
1314 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1315 "Failed to parse KeepConfiguration= setting");
1316
1317 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1318 [KEEP_CONFIGURATION_NO] = "no",
1319 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1320 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1321 [KEEP_CONFIGURATION_STATIC] = "static",
1322 [KEEP_CONFIGURATION_YES] = "yes",
1323 };
1324
1325 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
1326
1327 static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1328 [ACTIVATION_POLICY_UP] = "up",
1329 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1330 [ACTIVATION_POLICY_MANUAL] = "manual",
1331 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1332 [ACTIVATION_POLICY_DOWN] = "down",
1333 [ACTIVATION_POLICY_BOUND] = "bound",
1334 };
1335
1336 DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1337 DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");