]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #22791 from keszybz/bootctl-invert-order
[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 128
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;
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;
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 == -ENOENT)
350 return 0;
351 if (r < 0)
352 return r;
353 if (r > 0) {
354 log_debug("Skipping empty file: %s", filename);
355 return 0;
356 }
357
358 fname = strdup(filename);
359 if (!fname)
360 return log_oom();
361
362 name = strdup(basename(filename));
363 if (!name)
364 return log_oom();
365
366 d = strrchr(name, '.');
367 if (!d)
368 return -EINVAL;
369
370 *d = '\0';
371
372 dropin_dirname = strjoina(name, ".network.d");
373
374 network = new(Network, 1);
375 if (!network)
376 return log_oom();
377
378 *network = (Network) {
379 .filename = TAKE_PTR(fname),
380 .name = TAKE_PTR(name),
381
382 .manager = manager,
383 .n_ref = 1,
384
385 .required_for_online = -1,
386 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
387 .activation_policy = _ACTIVATION_POLICY_INVALID,
388 .arp = -1,
389 .multicast = -1,
390 .allmulticast = -1,
391 .promiscuous = -1,
392
393 .keep_configuration = manager->keep_configuration,
394
395 .dhcp_duid.type = _DUID_TYPE_INVALID,
396 .dhcp_critical = -1,
397 .dhcp_use_ntp = true,
398 .dhcp_routes_to_ntp = true,
399 .dhcp_use_sip = true,
400 .dhcp_use_dns = true,
401 .dhcp_routes_to_dns = true,
402 .dhcp_use_hostname = true,
403 .dhcp_use_routes = true,
404 .dhcp_use_gateway = -1,
405 .dhcp_send_hostname = true,
406 .dhcp_send_release = true,
407 .dhcp_route_metric = DHCP_ROUTE_METRIC,
408 .dhcp_client_identifier = _DHCP_CLIENT_ID_INVALID,
409 .dhcp_route_table = RT_TABLE_MAIN,
410 .dhcp_ip_service_type = -1,
411 .dhcp_broadcast = -1,
412
413 .dhcp6_use_address = true,
414 .dhcp6_use_pd_prefix = true,
415 .dhcp6_use_dns = true,
416 .dhcp6_use_hostname = true,
417 .dhcp6_use_ntp = 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 if (r < 0)
555 return r;
556
557 r = network_add_ipv4ll_route(network);
558 if (r < 0)
559 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
560
561 r = network_add_default_route_on_device(network);
562 if (r < 0)
563 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
564 network->filename);
565
566 r = network_verify(network);
567 if (r == -ENOMEM)
568 return r;
569 if (r < 0)
570 /* Ignore .network files that do not match the conditions. */
571 return 0;
572
573 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
574 if (r < 0)
575 return r;
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 r = network_load_one(manager, networks, *f);
595 if (r < 0)
596 return log_error_errno(r, "Failed to load %s: %m", *f);
597 }
598
599 return 0;
600 }
601
602 static bool stats_by_path_equal(Hashmap *a, Hashmap *b) {
603 struct stat *st_a, *st_b;
604 const char *path;
605
606 assert(a);
607 assert(b);
608
609 if (hashmap_size(a) != hashmap_size(b))
610 return false;
611
612 HASHMAP_FOREACH_KEY(st_a, path, a) {
613 st_b = hashmap_get(b, path);
614 if (!st_b)
615 return false;
616
617 if (!stat_inode_unmodified(st_a, st_b))
618 return false;
619 }
620
621 return true;
622 }
623
624 int network_reload(Manager *manager) {
625 OrderedHashmap *new_networks = NULL;
626 Network *n, *old;
627 int r;
628
629 assert(manager);
630
631 r = network_load(manager, &new_networks);
632 if (r < 0)
633 goto failure;
634
635 ORDERED_HASHMAP_FOREACH(n, new_networks) {
636 r = network_get_by_name(manager, n->name, &old);
637 if (r < 0) {
638 log_debug("Found new .network file: %s", n->filename);
639 continue;
640 }
641
642 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
643 log_debug("Found updated .network file: %s", n->filename);
644 continue;
645 }
646
647 r = ordered_hashmap_replace(new_networks, old->name, old);
648 if (r < 0)
649 goto failure;
650
651 network_ref(old);
652 network_unref(n);
653 }
654
655 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
656 manager->networks = new_networks;
657
658 return manager_build_dhcp_pd_subnet_ids(manager);
659
660 failure:
661 ordered_hashmap_free_with_destructor(new_networks, network_unref);
662
663 return r;
664 }
665
666 int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
667 Network *n;
668 int r;
669
670 assert(manager);
671
672 set_clear(manager->dhcp_pd_subnet_ids);
673
674 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
675 if (n->unmanaged)
676 continue;
677
678 if (!n->dhcp_pd)
679 continue;
680
681 if (n->dhcp_pd_subnet_id < 0)
682 continue;
683
684 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
685 if (r < 0)
686 return r;
687 }
688
689 return 0;
690 }
691
692 static Network *network_free(Network *network) {
693 if (!network)
694 return NULL;
695
696 free(network->filename);
697 hashmap_free(network->stats_by_path);
698
699 net_match_clear(&network->match);
700 condition_free_list(network->conditions);
701
702 free(network->dhcp_server_relay_agent_circuit_id);
703 free(network->dhcp_server_relay_agent_remote_id);
704 free(network->dhcp_server_boot_server_name);
705 free(network->dhcp_server_boot_filename);
706
707 free(network->description);
708 free(network->dhcp_vendor_class_identifier);
709 free(network->dhcp_mudurl);
710 strv_free(network->dhcp_user_class);
711 free(network->dhcp_hostname);
712 free(network->dhcp_label);
713 set_free(network->dhcp_deny_listed_ip);
714 set_free(network->dhcp_allow_listed_ip);
715 set_free(network->dhcp_request_options);
716 set_free(network->dhcp6_request_options);
717 free(network->dhcp6_mudurl);
718 strv_free(network->dhcp6_user_class);
719 strv_free(network->dhcp6_vendor_class);
720
721 strv_free(network->ntp);
722 for (unsigned i = 0; i < network->n_dns; i++)
723 in_addr_full_free(network->dns[i]);
724 free(network->dns);
725 ordered_set_free(network->search_domains);
726 ordered_set_free(network->route_domains);
727 strv_free(network->bind_carrier);
728
729 ordered_set_free(network->router_search_domains);
730 free(network->router_dns);
731 set_free(network->ndisc_deny_listed_router);
732 set_free(network->ndisc_allow_listed_router);
733 set_free(network->ndisc_deny_listed_prefix);
734 set_free(network->ndisc_allow_listed_prefix);
735 set_free(network->ndisc_deny_listed_route_prefix);
736 set_free(network->ndisc_allow_listed_route_prefix);
737
738 free(network->batadv_name);
739 free(network->bridge_name);
740 free(network->bond_name);
741 free(network->vrf_name);
742 hashmap_free_free_key(network->stacked_netdev_names);
743 netdev_unref(network->bridge);
744 netdev_unref(network->bond);
745 netdev_unref(network->vrf);
746 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
747
748 set_free_free(network->ipv6_proxy_ndp_addresses);
749 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
750 hashmap_free_with_destructor(network->routes_by_section, route_free);
751 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
752 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
753 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
754 hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
755 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
756 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
757 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
758 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
759 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
760 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
761 hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free);
762 hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
763
764 free(network->name);
765
766 free(network->dhcp_server_timezone);
767 free(network->dhcp_server_uplink_name);
768 free(network->router_uplink_name);
769 free(network->dhcp_pd_uplink_name);
770
771 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
772 free(network->dhcp_server_emit[t].addresses);
773
774 set_free_free(network->dnssec_negative_trust_anchors);
775
776 free(network->lldp_mudurl);
777
778 ordered_hashmap_free(network->dhcp_client_send_options);
779 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
780 ordered_hashmap_free(network->dhcp_server_send_options);
781 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
782 ordered_hashmap_free(network->dhcp6_client_send_options);
783 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
784 set_free(network->dhcp_pd_tokens);
785 set_free(network->ndisc_tokens);
786
787 return mfree(network);
788 }
789
790 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
791
792 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
793 Network *network;
794
795 assert(manager);
796 assert(name);
797 assert(ret);
798
799 network = ordered_hashmap_get(manager->networks, name);
800 if (!network)
801 return -ENOENT;
802
803 *ret = network;
804
805 return 0;
806 }
807
808 bool network_has_static_ipv6_configurations(Network *network) {
809 Address *address;
810 Route *route;
811 BridgeFDB *fdb;
812 BridgeMDB *mdb;
813 Neighbor *neighbor;
814
815 assert(network);
816
817 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
818 if (address->family == AF_INET6)
819 return true;
820
821 HASHMAP_FOREACH(route, network->routes_by_section)
822 if (route->family == AF_INET6)
823 return true;
824
825 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
826 if (fdb->family == AF_INET6)
827 return true;
828
829 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
830 if (mdb->family == AF_INET6)
831 return true;
832
833 HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
834 if (neighbor->family == AF_INET6)
835 return true;
836
837 if (!hashmap_isempty(network->address_labels_by_section))
838 return true;
839
840 if (!hashmap_isempty(network->prefixes_by_section))
841 return true;
842
843 if (!hashmap_isempty(network->route_prefixes_by_section))
844 return true;
845
846 return false;
847 }
848
849 int config_parse_stacked_netdev(
850 const char *unit,
851 const char *filename,
852 unsigned line,
853 const char *section,
854 unsigned section_line,
855 const char *lvalue,
856 int ltype,
857 const char *rvalue,
858 void *data,
859 void *userdata) {
860
861 _cleanup_free_ char *name = NULL;
862 NetDevKind kind = ltype;
863 Hashmap **h = data;
864 int r;
865
866 assert(filename);
867 assert(lvalue);
868 assert(rvalue);
869 assert(data);
870 assert(IN_SET(kind,
871 NETDEV_KIND_IPOIB,
872 NETDEV_KIND_IPVLAN,
873 NETDEV_KIND_IPVTAP,
874 NETDEV_KIND_MACSEC,
875 NETDEV_KIND_MACVLAN,
876 NETDEV_KIND_MACVTAP,
877 NETDEV_KIND_VLAN,
878 NETDEV_KIND_VXLAN,
879 NETDEV_KIND_XFRM,
880 _NETDEV_KIND_TUNNEL));
881
882 if (!ifname_valid(rvalue)) {
883 log_syntax(unit, LOG_WARNING, filename, line, 0,
884 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
885 return 0;
886 }
887
888 name = strdup(rvalue);
889 if (!name)
890 return log_oom();
891
892 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
893 if (r == -ENOMEM)
894 return log_oom();
895 if (r < 0)
896 log_syntax(unit, LOG_WARNING, filename, line, r,
897 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
898 else if (r == 0)
899 log_syntax(unit, LOG_DEBUG, filename, line, r,
900 "NetDev '%s' specified twice, ignoring.", name);
901 else
902 TAKE_PTR(name);
903
904 return 0;
905 }
906
907 int config_parse_domains(
908 const char *unit,
909 const char *filename,
910 unsigned line,
911 const char *section,
912 unsigned section_line,
913 const char *lvalue,
914 int ltype,
915 const char *rvalue,
916 void *data,
917 void *userdata) {
918
919 Network *n = userdata;
920 int r;
921
922 assert(filename);
923 assert(lvalue);
924 assert(rvalue);
925 assert(n);
926
927 if (isempty(rvalue)) {
928 n->search_domains = ordered_set_free(n->search_domains);
929 n->route_domains = ordered_set_free(n->route_domains);
930 return 0;
931 }
932
933 for (const char *p = rvalue;;) {
934 _cleanup_free_ char *w = NULL, *normalized = NULL;
935 const char *domain;
936 bool is_route;
937
938 r = extract_first_word(&p, &w, NULL, 0);
939 if (r == -ENOMEM)
940 return log_oom();
941 if (r < 0) {
942 log_syntax(unit, LOG_WARNING, filename, line, r,
943 "Failed to extract search or route domain, ignoring: %s", rvalue);
944 return 0;
945 }
946 if (r == 0)
947 return 0;
948
949 is_route = w[0] == '~';
950 domain = is_route ? w + 1 : w;
951
952 if (dns_name_is_root(domain) || streq(domain, "*")) {
953 /* If the root domain appears as is, or the special token "*" is found, we'll
954 * consider this as routing domain, unconditionally. */
955 is_route = true;
956 domain = "."; /* make sure we don't allow empty strings, thus write the root
957 * domain as "." */
958 } else {
959 r = dns_name_normalize(domain, 0, &normalized);
960 if (r < 0) {
961 log_syntax(unit, LOG_WARNING, filename, line, r,
962 "'%s' is not a valid domain name, ignoring.", domain);
963 continue;
964 }
965
966 domain = normalized;
967
968 if (is_localhost(domain)) {
969 log_syntax(unit, LOG_WARNING, filename, line, 0,
970 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
971 domain);
972 continue;
973 }
974 }
975
976 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
977 r = ordered_set_put_strdup(set, domain);
978 if (r == -EEXIST)
979 continue;
980 if (r < 0)
981 return log_oom();
982 }
983 }
984
985 int config_parse_timezone(
986 const char *unit,
987 const char *filename,
988 unsigned line,
989 const char *section,
990 unsigned section_line,
991 const char *lvalue,
992 int ltype,
993 const char *rvalue,
994 void *data,
995 void *userdata) {
996
997 char **tz = data;
998 int r;
999
1000 assert(filename);
1001 assert(lvalue);
1002 assert(rvalue);
1003 assert(data);
1004
1005 if (isempty(rvalue)) {
1006 *tz = mfree(*tz);
1007 return 0;
1008 }
1009
1010 r = verify_timezone(rvalue, LOG_WARNING);
1011 if (r < 0) {
1012 log_syntax(unit, LOG_WARNING, filename, line, r,
1013 "Timezone is not valid, ignoring assignment: %s", rvalue);
1014 return 0;
1015 }
1016
1017 return free_and_strdup_warn(tz, rvalue);
1018 }
1019
1020 int config_parse_dns(
1021 const char *unit,
1022 const char *filename,
1023 unsigned line,
1024 const char *section,
1025 unsigned section_line,
1026 const char *lvalue,
1027 int ltype,
1028 const char *rvalue,
1029 void *data,
1030 void *userdata) {
1031
1032 Network *n = userdata;
1033 int r;
1034
1035 assert(filename);
1036 assert(lvalue);
1037 assert(rvalue);
1038 assert(n);
1039
1040 if (isempty(rvalue)) {
1041 for (unsigned i = 0; i < n->n_dns; i++)
1042 in_addr_full_free(n->dns[i]);
1043 n->dns = mfree(n->dns);
1044 n->n_dns = 0;
1045 return 0;
1046 }
1047
1048 for (const char *p = rvalue;;) {
1049 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
1050 _cleanup_free_ char *w = NULL;
1051 struct in_addr_full **m;
1052
1053 r = extract_first_word(&p, &w, NULL, 0);
1054 if (r == -ENOMEM)
1055 return log_oom();
1056 if (r < 0) {
1057 log_syntax(unit, LOG_WARNING, filename, line, r,
1058 "Invalid syntax, ignoring: %s", rvalue);
1059 return 0;
1060 }
1061 if (r == 0)
1062 return 0;
1063
1064 r = in_addr_full_new_from_string(w, &dns);
1065 if (r < 0) {
1066 log_syntax(unit, LOG_WARNING, filename, line, r,
1067 "Failed to parse dns server address, ignoring: %s", w);
1068 continue;
1069 }
1070
1071 if (IN_SET(dns->port, 53, 853))
1072 dns->port = 0;
1073
1074 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
1075 if (!m)
1076 return log_oom();
1077
1078 m[n->n_dns++] = TAKE_PTR(dns);
1079 n->dns = m;
1080 }
1081 }
1082
1083 int config_parse_dnssec_negative_trust_anchors(
1084 const char *unit,
1085 const char *filename,
1086 unsigned line,
1087 const char *section,
1088 unsigned section_line,
1089 const char *lvalue,
1090 int ltype,
1091 const char *rvalue,
1092 void *data,
1093 void *userdata) {
1094
1095 Set **nta = data;
1096 int r;
1097
1098 assert(filename);
1099 assert(lvalue);
1100 assert(rvalue);
1101 assert(nta);
1102
1103 if (isempty(rvalue)) {
1104 *nta = set_free_free(*nta);
1105 return 0;
1106 }
1107
1108 for (const char *p = rvalue;;) {
1109 _cleanup_free_ char *w = NULL;
1110
1111 r = extract_first_word(&p, &w, NULL, 0);
1112 if (r == -ENOMEM)
1113 return log_oom();
1114 if (r < 0) {
1115 log_syntax(unit, LOG_WARNING, filename, line, r,
1116 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1117 return 0;
1118 }
1119 if (r == 0)
1120 return 0;
1121
1122 r = dns_name_is_valid(w);
1123 if (r <= 0) {
1124 log_syntax(unit, LOG_WARNING, filename, line, r,
1125 "%s is not a valid domain name, ignoring.", w);
1126 continue;
1127 }
1128
1129 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
1130 if (r < 0)
1131 return log_oom();
1132 }
1133 }
1134
1135 int config_parse_ntp(
1136 const char *unit,
1137 const char *filename,
1138 unsigned line,
1139 const char *section,
1140 unsigned section_line,
1141 const char *lvalue,
1142 int ltype,
1143 const char *rvalue,
1144 void *data,
1145 void *userdata) {
1146
1147 char ***l = data;
1148 int r;
1149
1150 assert(filename);
1151 assert(lvalue);
1152 assert(rvalue);
1153 assert(l);
1154
1155 if (isempty(rvalue)) {
1156 *l = strv_free(*l);
1157 return 0;
1158 }
1159
1160 for (const char *p = rvalue;;) {
1161 _cleanup_free_ char *w = NULL;
1162
1163 r = extract_first_word(&p, &w, NULL, 0);
1164 if (r == -ENOMEM)
1165 return log_oom();
1166 if (r < 0) {
1167 log_syntax(unit, LOG_WARNING, filename, line, r,
1168 "Failed to extract NTP server name, ignoring: %s", rvalue);
1169 return 0;
1170 }
1171 if (r == 0)
1172 return 0;
1173
1174 r = dns_name_is_valid_or_address(w);
1175 if (r <= 0) {
1176 log_syntax(unit, LOG_WARNING, filename, line, r,
1177 "%s is not a valid domain name or IP address, ignoring.", w);
1178 continue;
1179 }
1180
1181 if (strv_length(*l) > MAX_NTP_SERVERS) {
1182 log_syntax(unit, LOG_WARNING, filename, line, 0,
1183 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1184 MAX_NTP_SERVERS, w);
1185 return 0;
1186 }
1187
1188 r = strv_consume(l, TAKE_PTR(w));
1189 if (r < 0)
1190 return log_oom();
1191 }
1192 }
1193
1194 int config_parse_required_for_online(
1195 const char *unit,
1196 const char *filename,
1197 unsigned line,
1198 const char *section,
1199 unsigned section_line,
1200 const char *lvalue,
1201 int ltype,
1202 const char *rvalue,
1203 void *data,
1204 void *userdata) {
1205
1206 Network *network = userdata;
1207 LinkOperationalStateRange range;
1208 bool required = true;
1209 int r;
1210
1211 assert(filename);
1212 assert(lvalue);
1213 assert(rvalue);
1214 assert(network);
1215
1216 if (isempty(rvalue)) {
1217 network->required_for_online = -1;
1218 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1219 return 0;
1220 }
1221
1222 r = parse_operational_state_range(rvalue, &range);
1223 if (r < 0) {
1224 r = parse_boolean(rvalue);
1225 if (r < 0) {
1226 log_syntax(unit, LOG_WARNING, filename, line, r,
1227 "Failed to parse %s= setting, ignoring assignment: %s",
1228 lvalue, rvalue);
1229 return 0;
1230 }
1231
1232 required = r;
1233 range = LINK_OPERSTATE_RANGE_DEFAULT;
1234 }
1235
1236 network->required_for_online = required;
1237 network->required_operstate_for_online = range;
1238
1239 return 0;
1240 }
1241
1242 int config_parse_link_group(
1243 const char *unit,
1244 const char *filename,
1245 unsigned line,
1246 const char *section,
1247 unsigned section_line,
1248 const char *lvalue,
1249 int ltype,
1250 const char *rvalue,
1251 void *data,
1252 void *userdata) {
1253
1254 Network *network = userdata;
1255 int r;
1256 int32_t group;
1257
1258 assert(filename);
1259 assert(lvalue);
1260 assert(rvalue);
1261 assert(network);
1262
1263 if (isempty(rvalue)) {
1264 network->group = -1;
1265 return 0;
1266 }
1267
1268 r = safe_atoi32(rvalue, &group);
1269 if (r < 0) {
1270 log_syntax(unit, LOG_WARNING, filename, line, r,
1271 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1272 return 0;
1273 }
1274
1275 if (group < 0) {
1276 log_syntax(unit, LOG_WARNING, filename, line, r,
1277 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1278 return 0;
1279 }
1280
1281 network->group = group;
1282 return 0;
1283 }
1284
1285 int config_parse_ignore_carrier_loss(
1286 const char *unit,
1287 const char *filename,
1288 unsigned line,
1289 const char *section,
1290 unsigned section_line,
1291 const char *lvalue,
1292 int ltype,
1293 const char *rvalue,
1294 void *data,
1295 void *userdata) {
1296
1297 Network *network = userdata;
1298 usec_t usec;
1299 int r;
1300
1301 assert(filename);
1302 assert(lvalue);
1303 assert(rvalue);
1304 assert(network);
1305
1306 if (isempty(rvalue)) {
1307 network->ignore_carrier_loss_set = false;
1308 return 0;
1309 }
1310
1311 r = parse_boolean(rvalue);
1312 if (r >= 0) {
1313 network->ignore_carrier_loss_set = true;
1314 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1315 return 0;
1316 }
1317
1318 r = parse_sec(rvalue, &usec);
1319 if (r < 0) {
1320 log_syntax(unit, LOG_WARNING, filename, line, r,
1321 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1322 return 0;
1323 }
1324
1325 network->ignore_carrier_loss_set = true;
1326 network->ignore_carrier_loss_usec = usec;
1327 return 0;
1328 }
1329
1330 DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1331 "Failed to parse RequiredFamilyForOnline= setting");
1332
1333 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1334 "Failed to parse KeepConfiguration= setting");
1335
1336 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1337 [KEEP_CONFIGURATION_NO] = "no",
1338 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1339 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1340 [KEEP_CONFIGURATION_STATIC] = "static",
1341 [KEEP_CONFIGURATION_YES] = "yes",
1342 };
1343
1344 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
1345
1346 static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1347 [ACTIVATION_POLICY_UP] = "up",
1348 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1349 [ACTIVATION_POLICY_MANUAL] = "manual",
1350 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1351 [ACTIVATION_POLICY_DOWN] = "down",
1352 [ACTIVATION_POLICY_BOUND] = "bound",
1353 };
1354
1355 DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1356 DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");