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