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