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