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