]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #29987 from yuwata/network-bridge-vlan
[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_with_destructor(network->addresses_by_section, address_free);
191 network->routes_by_section = hashmap_free_with_destructor(network->routes_by_section, route_free);
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) {
278 network->ignore_carrier_loss_set = true;
279 network->ignore_carrier_loss_usec = network->configure_without_carrier ? USEC_INFINITY : 0;
280 }
281
282 if (IN_SET(network->activation_policy, ACTIVATION_POLICY_DOWN, ACTIVATION_POLICY_ALWAYS_DOWN, ACTIVATION_POLICY_MANUAL)) {
283 if (network->required_for_online < 0 ||
284 (network->required_for_online == true && network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN)) {
285 log_debug("%s: Setting RequiredForOnline=no because ActivationPolicy=%s.", network->filename,
286 activation_policy_to_string(network->activation_policy));
287 network->required_for_online = false;
288 } else if (network->required_for_online == true)
289 log_warning("%s: RequiredForOnline=yes and ActivationPolicy=%s, "
290 "this may cause a delay at boot.", network->filename,
291 activation_policy_to_string(network->activation_policy));
292 }
293
294 if (network->required_for_online < 0)
295 network->required_for_online = true;
296
297 if (network->keep_configuration < 0)
298 network->keep_configuration = KEEP_CONFIGURATION_NO;
299
300 if (network->ipv6_proxy_ndp == 0 && !set_isempty(network->ipv6_proxy_ndp_addresses)) {
301 log_warning("%s: IPv6ProxyNDP= is disabled. Ignoring IPv6ProxyNDPAddress=.", network->filename);
302 network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
303 }
304
305 r = network_drop_invalid_addresses(network);
306 if (r < 0)
307 return r; /* network_drop_invalid_addresses() logs internally. */
308 network_drop_invalid_routes(network);
309 network_drop_invalid_nexthops(network);
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_DEFAULT,
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 .ipv4_rp_filter = _IP_REVERSE_PATH_FILTER_INVALID,
475
476 .ipv6_accept_ra = -1,
477 .ipv6_accept_ra_use_dns = true,
478 .ipv6_accept_ra_use_gateway = true,
479 .ipv6_accept_ra_use_captive_portal = true,
480 .ipv6_accept_ra_use_route_prefix = true,
481 .ipv6_accept_ra_use_autonomous_prefix = true,
482 .ipv6_accept_ra_use_onlink_prefix = true,
483 .ipv6_accept_ra_use_mtu = true,
484 .ipv6_accept_ra_use_hop_limit = true,
485 .ipv6_accept_ra_use_icmp6_ratelimit = true,
486 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
487 .ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
488 .ipv6_accept_ra_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
489 .ipv6_accept_ra_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
490 .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
491
492 .can_termination = -1,
493
494 .ipoib_mode = _IP_OVER_INFINIBAND_MODE_INVALID,
495 .ipoib_umcast = -1,
496 };
497
498 r = config_parse_many(
499 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root = */ NULL,
500 "Match\0"
501 "Link\0"
502 "SR-IOV\0"
503 "Network\0"
504 "Address\0"
505 "Neighbor\0"
506 "IPv6AddressLabel\0"
507 "RoutingPolicyRule\0"
508 "Route\0"
509 "NextHop\0"
510 "DHCP\0" /* compat */
511 "DHCPv4\0"
512 "DHCPv6\0"
513 "DHCPv6PrefixDelegation\0" /* compat */
514 "DHCPPrefixDelegation\0"
515 "DHCPServer\0"
516 "DHCPServerStaticLease\0"
517 "IPv6AcceptRA\0"
518 "IPv6NDPProxyAddress\0"
519 "Bridge\0"
520 "BridgeFDB\0"
521 "BridgeMDB\0"
522 "BridgeVLAN\0"
523 "IPv6SendRA\0"
524 "IPv6PrefixDelegation\0"
525 "IPv6Prefix\0"
526 "IPv6RoutePrefix\0"
527 "IPv6PREF64Prefix\0"
528 "LLDP\0"
529 "TrafficControlQueueingDiscipline\0"
530 "CAN\0"
531 "QDisc\0"
532 "BFIFO\0"
533 "CAKE\0"
534 "ControlledDelay\0"
535 "DeficitRoundRobinScheduler\0"
536 "DeficitRoundRobinSchedulerClass\0"
537 "EnhancedTransmissionSelection\0"
538 "FairQueueing\0"
539 "FairQueueingControlledDelay\0"
540 "FlowQueuePIE\0"
541 "GenericRandomEarlyDetection\0"
542 "HeavyHitterFilter\0"
543 "HierarchyTokenBucket\0"
544 "HierarchyTokenBucketClass\0"
545 "NetworkEmulator\0"
546 "PFIFO\0"
547 "PFIFOFast\0"
548 "PFIFOHeadDrop\0"
549 "PIE\0"
550 "QuickFairQueueing\0"
551 "QuickFairQueueingClass\0"
552 "StochasticFairBlue\0"
553 "StochasticFairnessQueueing\0"
554 "TokenBucketFilter\0"
555 "TrivialLinkEqualizer\0",
556 config_item_perf_lookup, network_network_gperf_lookup,
557 CONFIG_PARSE_WARN,
558 network,
559 &network->stats_by_path,
560 &network->dropins);
561 if (r < 0)
562 return r; /* config_parse_many() logs internally. */
563
564 r = network_add_ipv4ll_route(network);
565 if (r < 0)
566 return log_warning_errno(r, "%s: Failed to add IPv4LL route: %m", network->filename);
567
568 r = network_add_default_route_on_device(network);
569 if (r < 0)
570 return log_warning_errno(r, "%s: Failed to add default route on device: %m",
571 network->filename);
572
573 r = network_verify(network);
574 if (r < 0)
575 return r; /* network_verify() logs internally. */
576
577 r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network);
578 if (r < 0)
579 return log_warning_errno(r, "%s: Failed to store configuration into hashmap: %m", filename);
580
581 TAKE_PTR(network);
582 return 0;
583 }
584
585 int network_load(Manager *manager, OrderedHashmap **networks) {
586 _cleanup_strv_free_ char **files = NULL;
587 int r;
588
589 assert(manager);
590
591 ordered_hashmap_clear_with_destructor(*networks, network_unref);
592
593 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
594 if (r < 0)
595 return log_error_errno(r, "Failed to enumerate network files: %m");
596
597 STRV_FOREACH(f, files)
598 (void) network_load_one(manager, networks, *f);
599
600 return 0;
601 }
602
603 int network_reload(Manager *manager) {
604 OrderedHashmap *new_networks = NULL;
605 Network *n, *old;
606 int r;
607
608 assert(manager);
609
610 r = network_load(manager, &new_networks);
611 if (r < 0)
612 goto failure;
613
614 ORDERED_HASHMAP_FOREACH(n, new_networks) {
615 r = network_get_by_name(manager, n->name, &old);
616 if (r < 0) {
617 log_debug("Found new .network file: %s", n->filename);
618 continue;
619 }
620
621 if (!stats_by_path_equal(n->stats_by_path, old->stats_by_path)) {
622 log_debug("Found updated .network file: %s", n->filename);
623 continue;
624 }
625
626 r = ordered_hashmap_replace(new_networks, old->name, old);
627 if (r < 0)
628 goto failure;
629
630 network_ref(old);
631 network_unref(n);
632 }
633
634 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
635 manager->networks = new_networks;
636
637 return manager_build_dhcp_pd_subnet_ids(manager);
638
639 failure:
640 ordered_hashmap_free_with_destructor(new_networks, network_unref);
641
642 return r;
643 }
644
645 int manager_build_dhcp_pd_subnet_ids(Manager *manager) {
646 Network *n;
647 int r;
648
649 assert(manager);
650
651 set_clear(manager->dhcp_pd_subnet_ids);
652
653 ORDERED_HASHMAP_FOREACH(n, manager->networks) {
654 if (n->unmanaged)
655 continue;
656
657 if (!n->dhcp_pd)
658 continue;
659
660 if (n->dhcp_pd_subnet_id < 0)
661 continue;
662
663 r = set_ensure_put(&manager->dhcp_pd_subnet_ids, &uint64_hash_ops, &n->dhcp_pd_subnet_id);
664 if (r < 0)
665 return r;
666 }
667
668 return 0;
669 }
670
671 static Network *network_free(Network *network) {
672 if (!network)
673 return NULL;
674
675 free(network->name);
676 free(network->filename);
677 free(network->description);
678 strv_free(network->dropins);
679 hashmap_free(network->stats_by_path);
680
681 /* conditions */
682 net_match_clear(&network->match);
683 condition_free_list(network->conditions);
684
685 /* link settings */
686 strv_free(network->bind_carrier);
687
688 /* NTP */
689 strv_free(network->ntp);
690
691 /* DNS */
692 for (unsigned i = 0; i < network->n_dns; i++)
693 in_addr_full_free(network->dns[i]);
694 free(network->dns);
695 ordered_set_free(network->search_domains);
696 ordered_set_free(network->route_domains);
697 set_free_free(network->dnssec_negative_trust_anchors);
698
699 /* DHCP server */
700 free(network->dhcp_server_relay_agent_circuit_id);
701 free(network->dhcp_server_relay_agent_remote_id);
702 free(network->dhcp_server_boot_server_name);
703 free(network->dhcp_server_boot_filename);
704 free(network->dhcp_server_timezone);
705 free(network->dhcp_server_uplink_name);
706 for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
707 free(network->dhcp_server_emit[t].addresses);
708 ordered_hashmap_free(network->dhcp_server_send_options);
709 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
710
711 /* DHCP client */
712 free(network->dhcp_vendor_class_identifier);
713 free(network->dhcp_mudurl);
714 free(network->dhcp_hostname);
715 free(network->dhcp_label);
716 set_free(network->dhcp_deny_listed_ip);
717 set_free(network->dhcp_allow_listed_ip);
718 strv_free(network->dhcp_user_class);
719 set_free(network->dhcp_request_options);
720 ordered_hashmap_free(network->dhcp_client_send_options);
721 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
722 free(network->dhcp_netlabel);
723 nft_set_context_clear(&network->dhcp_nft_set_context);
724
725 /* DHCPv6 client */
726 free(network->dhcp6_mudurl);
727 free(network->dhcp6_hostname);
728 strv_free(network->dhcp6_user_class);
729 strv_free(network->dhcp6_vendor_class);
730 set_free(network->dhcp6_request_options);
731 ordered_hashmap_free(network->dhcp6_client_send_options);
732 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
733 free(network->dhcp6_netlabel);
734 nft_set_context_clear(&network->dhcp6_nft_set_context);
735
736 /* DHCP PD */
737 free(network->dhcp_pd_uplink_name);
738 set_free(network->dhcp_pd_tokens);
739 free(network->dhcp_pd_netlabel);
740 nft_set_context_clear(&network->dhcp_pd_nft_set_context);
741
742 /* Router advertisement */
743 ordered_set_free(network->router_search_domains);
744 free(network->router_dns);
745 free(network->router_uplink_name);
746
747 /* NDisc */
748 set_free(network->ndisc_deny_listed_router);
749 set_free(network->ndisc_allow_listed_router);
750 set_free(network->ndisc_deny_listed_prefix);
751 set_free(network->ndisc_allow_listed_prefix);
752 set_free(network->ndisc_deny_listed_route_prefix);
753 set_free(network->ndisc_allow_listed_route_prefix);
754 set_free(network->ndisc_tokens);
755 free(network->ndisc_netlabel);
756 nft_set_context_clear(&network->ndisc_nft_set_context);
757
758 /* LLDP */
759 free(network->lldp_mudurl);
760
761 /* netdev */
762 free(network->batadv_name);
763 free(network->bridge_name);
764 free(network->bond_name);
765 free(network->vrf_name);
766 hashmap_free_free_key(network->stacked_netdev_names);
767 netdev_unref(network->bridge);
768 netdev_unref(network->bond);
769 netdev_unref(network->vrf);
770 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
771
772 /* static configs */
773 set_free_free(network->ipv6_proxy_ndp_addresses);
774 ordered_hashmap_free_with_destructor(network->addresses_by_section, address_free);
775 hashmap_free_with_destructor(network->routes_by_section, route_free);
776 hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
777 hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
778 hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
779 ordered_hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
780 hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
781 hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
782 hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
783 hashmap_free_with_destructor(network->pref64_prefixes_by_section, pref64_prefix_free);
784 hashmap_free_with_destructor(network->rules_by_section, routing_policy_rule_free);
785 hashmap_free_with_destructor(network->dhcp_static_leases_by_section, dhcp_static_lease_free);
786 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
787 hashmap_free_with_destructor(network->qdiscs_by_section, qdisc_free);
788 hashmap_free_with_destructor(network->tclasses_by_section, tclass_free);
789
790 return mfree(network);
791 }
792
793 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
794
795 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
796 Network *network;
797
798 assert(manager);
799 assert(name);
800 assert(ret);
801
802 network = ordered_hashmap_get(manager->networks, name);
803 if (!network)
804 return -ENOENT;
805
806 *ret = network;
807
808 return 0;
809 }
810
811 bool network_has_static_ipv6_configurations(Network *network) {
812 Address *address;
813 Route *route;
814 BridgeFDB *fdb;
815 BridgeMDB *mdb;
816 Neighbor *neighbor;
817
818 assert(network);
819
820 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
821 if (address->family == AF_INET6)
822 return true;
823
824 HASHMAP_FOREACH(route, network->routes_by_section)
825 if (route->family == AF_INET6)
826 return true;
827
828 HASHMAP_FOREACH(fdb, network->bridge_fdb_entries_by_section)
829 if (fdb->family == AF_INET6)
830 return true;
831
832 HASHMAP_FOREACH(mdb, network->bridge_mdb_entries_by_section)
833 if (mdb->family == AF_INET6)
834 return true;
835
836 ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
837 if (neighbor->family == AF_INET6)
838 return true;
839
840 if (!hashmap_isempty(network->address_labels_by_section))
841 return true;
842
843 if (!hashmap_isempty(network->prefixes_by_section))
844 return true;
845
846 if (!hashmap_isempty(network->route_prefixes_by_section))
847 return true;
848
849 if (!hashmap_isempty(network->pref64_prefixes_by_section))
850 return true;
851
852 return false;
853 }
854
855 int config_parse_stacked_netdev(
856 const char *unit,
857 const char *filename,
858 unsigned line,
859 const char *section,
860 unsigned section_line,
861 const char *lvalue,
862 int ltype,
863 const char *rvalue,
864 void *data,
865 void *userdata) {
866
867 _cleanup_free_ char *name = NULL;
868 NetDevKind kind = ltype;
869 Hashmap **h = ASSERT_PTR(data);
870 int r;
871
872 assert(filename);
873 assert(lvalue);
874 assert(rvalue);
875 assert(IN_SET(kind,
876 NETDEV_KIND_IPOIB,
877 NETDEV_KIND_IPVLAN,
878 NETDEV_KIND_IPVTAP,
879 NETDEV_KIND_MACSEC,
880 NETDEV_KIND_MACVLAN,
881 NETDEV_KIND_MACVTAP,
882 NETDEV_KIND_VLAN,
883 NETDEV_KIND_VXLAN,
884 NETDEV_KIND_XFRM,
885 _NETDEV_KIND_TUNNEL));
886
887 if (!ifname_valid(rvalue)) {
888 log_syntax(unit, LOG_WARNING, filename, line, 0,
889 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
890 return 0;
891 }
892
893 name = strdup(rvalue);
894 if (!name)
895 return log_oom();
896
897 r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind));
898 if (r == -ENOMEM)
899 return log_oom();
900 if (r < 0)
901 log_syntax(unit, LOG_WARNING, filename, line, r,
902 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
903 else if (r == 0)
904 log_syntax(unit, LOG_DEBUG, filename, line, r,
905 "NetDev '%s' specified twice, ignoring.", name);
906 else
907 TAKE_PTR(name);
908
909 return 0;
910 }
911
912 int config_parse_domains(
913 const char *unit,
914 const char *filename,
915 unsigned line,
916 const char *section,
917 unsigned section_line,
918 const char *lvalue,
919 int ltype,
920 const char *rvalue,
921 void *data,
922 void *userdata) {
923
924 Network *n = ASSERT_PTR(userdata);
925 int r;
926
927 assert(filename);
928 assert(lvalue);
929 assert(rvalue);
930
931 if (isempty(rvalue)) {
932 n->search_domains = ordered_set_free(n->search_domains);
933 n->route_domains = ordered_set_free(n->route_domains);
934 return 0;
935 }
936
937 for (const char *p = rvalue;;) {
938 _cleanup_free_ char *w = NULL, *normalized = NULL;
939 const char *domain;
940 bool is_route;
941
942 r = extract_first_word(&p, &w, NULL, 0);
943 if (r == -ENOMEM)
944 return log_oom();
945 if (r < 0) {
946 log_syntax(unit, LOG_WARNING, filename, line, r,
947 "Failed to extract search or route domain, ignoring: %s", rvalue);
948 return 0;
949 }
950 if (r == 0)
951 return 0;
952
953 is_route = w[0] == '~';
954 domain = is_route ? w + 1 : w;
955
956 if (dns_name_is_root(domain) || streq(domain, "*")) {
957 /* If the root domain appears as is, or the special token "*" is found, we'll
958 * consider this as routing domain, unconditionally. */
959 is_route = true;
960 domain = "."; /* make sure we don't allow empty strings, thus write the root
961 * domain as "." */
962 } else {
963 r = dns_name_normalize(domain, 0, &normalized);
964 if (r < 0) {
965 log_syntax(unit, LOG_WARNING, filename, line, r,
966 "'%s' is not a valid domain name, ignoring.", domain);
967 continue;
968 }
969
970 domain = normalized;
971
972 if (is_localhost(domain)) {
973 log_syntax(unit, LOG_WARNING, filename, line, 0,
974 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
975 domain);
976 continue;
977 }
978 }
979
980 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
981 r = ordered_set_put_strdup(set, domain);
982 if (r == -EEXIST)
983 continue;
984 if (r < 0)
985 return log_oom();
986 }
987 }
988
989 int config_parse_timezone(
990 const char *unit,
991 const char *filename,
992 unsigned line,
993 const char *section,
994 unsigned section_line,
995 const char *lvalue,
996 int ltype,
997 const char *rvalue,
998 void *data,
999 void *userdata) {
1000
1001 char **tz = ASSERT_PTR(data);
1002 int r;
1003
1004 assert(filename);
1005 assert(lvalue);
1006 assert(rvalue);
1007
1008 if (isempty(rvalue)) {
1009 *tz = mfree(*tz);
1010 return 0;
1011 }
1012
1013 r = verify_timezone(rvalue, LOG_WARNING);
1014 if (r < 0) {
1015 log_syntax(unit, LOG_WARNING, filename, line, r,
1016 "Timezone is not valid, ignoring assignment: %s", rvalue);
1017 return 0;
1018 }
1019
1020 return free_and_strdup_warn(tz, rvalue);
1021 }
1022
1023 int config_parse_dns(
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 Network *n = ASSERT_PTR(userdata);
1036 int r;
1037
1038 assert(filename);
1039 assert(lvalue);
1040 assert(rvalue);
1041
1042 if (isempty(rvalue)) {
1043 for (unsigned i = 0; i < n->n_dns; i++)
1044 in_addr_full_free(n->dns[i]);
1045 n->dns = mfree(n->dns);
1046 n->n_dns = 0;
1047 return 0;
1048 }
1049
1050 for (const char *p = rvalue;;) {
1051 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
1052 _cleanup_free_ char *w = NULL;
1053 struct in_addr_full **m;
1054
1055 r = extract_first_word(&p, &w, NULL, 0);
1056 if (r == -ENOMEM)
1057 return log_oom();
1058 if (r < 0) {
1059 log_syntax(unit, LOG_WARNING, filename, line, r,
1060 "Invalid syntax, ignoring: %s", rvalue);
1061 return 0;
1062 }
1063 if (r == 0)
1064 return 0;
1065
1066 r = in_addr_full_new_from_string(w, &dns);
1067 if (r < 0) {
1068 log_syntax(unit, LOG_WARNING, filename, line, r,
1069 "Failed to parse dns server address, ignoring: %s", w);
1070 continue;
1071 }
1072
1073 if (IN_SET(dns->port, 53, 853))
1074 dns->port = 0;
1075
1076 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
1077 if (!m)
1078 return log_oom();
1079
1080 m[n->n_dns++] = TAKE_PTR(dns);
1081 n->dns = m;
1082 }
1083 }
1084
1085 int config_parse_dnssec_negative_trust_anchors(
1086 const char *unit,
1087 const char *filename,
1088 unsigned line,
1089 const char *section,
1090 unsigned section_line,
1091 const char *lvalue,
1092 int ltype,
1093 const char *rvalue,
1094 void *data,
1095 void *userdata) {
1096
1097 Set **nta = ASSERT_PTR(data);
1098 int r;
1099
1100 assert(filename);
1101 assert(lvalue);
1102 assert(rvalue);
1103
1104 if (isempty(rvalue)) {
1105 *nta = set_free_free(*nta);
1106 return 0;
1107 }
1108
1109 for (const char *p = rvalue;;) {
1110 _cleanup_free_ char *w = NULL;
1111
1112 r = extract_first_word(&p, &w, NULL, 0);
1113 if (r == -ENOMEM)
1114 return log_oom();
1115 if (r < 0) {
1116 log_syntax(unit, LOG_WARNING, filename, line, r,
1117 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1118 return 0;
1119 }
1120 if (r == 0)
1121 return 0;
1122
1123 r = dns_name_is_valid(w);
1124 if (r <= 0) {
1125 log_syntax(unit, LOG_WARNING, filename, line, r,
1126 "%s is not a valid domain name, ignoring.", w);
1127 continue;
1128 }
1129
1130 r = set_ensure_consume(nta, &dns_name_hash_ops, TAKE_PTR(w));
1131 if (r < 0)
1132 return log_oom();
1133 }
1134 }
1135
1136 int config_parse_ntp(
1137 const char *unit,
1138 const char *filename,
1139 unsigned line,
1140 const char *section,
1141 unsigned section_line,
1142 const char *lvalue,
1143 int ltype,
1144 const char *rvalue,
1145 void *data,
1146 void *userdata) {
1147
1148 char ***l = ASSERT_PTR(data);
1149 int r;
1150
1151 assert(filename);
1152 assert(lvalue);
1153 assert(rvalue);
1154
1155 if (isempty(rvalue)) {
1156 *l = strv_free(*l);
1157 return 0;
1158 }
1159
1160 for (const char *p = rvalue;;) {
1161 _cleanup_free_ char *w = NULL;
1162
1163 r = extract_first_word(&p, &w, NULL, 0);
1164 if (r == -ENOMEM)
1165 return log_oom();
1166 if (r < 0) {
1167 log_syntax(unit, LOG_WARNING, filename, line, r,
1168 "Failed to extract NTP server name, ignoring: %s", rvalue);
1169 return 0;
1170 }
1171 if (r == 0)
1172 return 0;
1173
1174 r = dns_name_is_valid_or_address(w);
1175 if (r <= 0) {
1176 log_syntax(unit, LOG_WARNING, filename, line, r,
1177 "%s is not a valid domain name or IP address, ignoring.", w);
1178 continue;
1179 }
1180
1181 if (strv_length(*l) > MAX_NTP_SERVERS) {
1182 log_syntax(unit, LOG_WARNING, filename, line, 0,
1183 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1184 MAX_NTP_SERVERS, w);
1185 return 0;
1186 }
1187
1188 r = strv_consume(l, TAKE_PTR(w));
1189 if (r < 0)
1190 return log_oom();
1191 }
1192 }
1193
1194 int config_parse_required_for_online(
1195 const char *unit,
1196 const char *filename,
1197 unsigned line,
1198 const char *section,
1199 unsigned section_line,
1200 const char *lvalue,
1201 int ltype,
1202 const char *rvalue,
1203 void *data,
1204 void *userdata) {
1205
1206 Network *network = ASSERT_PTR(userdata);
1207 LinkOperationalStateRange range;
1208 bool required = true;
1209 int r;
1210
1211 assert(filename);
1212 assert(lvalue);
1213 assert(rvalue);
1214
1215 if (isempty(rvalue)) {
1216 network->required_for_online = -1;
1217 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1218 return 0;
1219 }
1220
1221 r = parse_operational_state_range(rvalue, &range);
1222 if (r < 0) {
1223 r = parse_boolean(rvalue);
1224 if (r < 0) {
1225 log_syntax(unit, LOG_WARNING, filename, line, r,
1226 "Failed to parse %s= setting, ignoring assignment: %s",
1227 lvalue, rvalue);
1228 return 0;
1229 }
1230
1231 required = r;
1232 range = LINK_OPERSTATE_RANGE_DEFAULT;
1233 }
1234
1235 network->required_for_online = required;
1236 network->required_operstate_for_online = range;
1237
1238 return 0;
1239 }
1240
1241 int config_parse_link_group(
1242 const char *unit,
1243 const char *filename,
1244 unsigned line,
1245 const char *section,
1246 unsigned section_line,
1247 const char *lvalue,
1248 int ltype,
1249 const char *rvalue,
1250 void *data,
1251 void *userdata) {
1252
1253 Network *network = ASSERT_PTR(userdata);
1254 int r;
1255 int32_t group;
1256
1257 assert(filename);
1258 assert(lvalue);
1259 assert(rvalue);
1260
1261 if (isempty(rvalue)) {
1262 network->group = -1;
1263 return 0;
1264 }
1265
1266 r = safe_atoi32(rvalue, &group);
1267 if (r < 0) {
1268 log_syntax(unit, LOG_WARNING, filename, line, r,
1269 "Failed to parse Group=, ignoring assignment: %s", rvalue);
1270 return 0;
1271 }
1272
1273 if (group < 0) {
1274 log_syntax(unit, LOG_WARNING, filename, line, r,
1275 "Value of Group= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1276 return 0;
1277 }
1278
1279 network->group = group;
1280 return 0;
1281 }
1282
1283 int config_parse_ignore_carrier_loss(
1284 const char *unit,
1285 const char *filename,
1286 unsigned line,
1287 const char *section,
1288 unsigned section_line,
1289 const char *lvalue,
1290 int ltype,
1291 const char *rvalue,
1292 void *data,
1293 void *userdata) {
1294
1295 Network *network = ASSERT_PTR(userdata);
1296 usec_t usec;
1297 int r;
1298
1299 assert(filename);
1300 assert(lvalue);
1301 assert(rvalue);
1302
1303 if (isempty(rvalue)) {
1304 network->ignore_carrier_loss_set = false;
1305 return 0;
1306 }
1307
1308 r = parse_boolean(rvalue);
1309 if (r >= 0) {
1310 network->ignore_carrier_loss_set = true;
1311 network->ignore_carrier_loss_usec = r > 0 ? USEC_INFINITY : 0;
1312 return 0;
1313 }
1314
1315 r = parse_sec(rvalue, &usec);
1316 if (r < 0) {
1317 log_syntax(unit, LOG_WARNING, filename, line, r,
1318 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
1319 return 0;
1320 }
1321
1322 network->ignore_carrier_loss_set = true;
1323 network->ignore_carrier_loss_usec = usec;
1324 return 0;
1325 }
1326
1327 DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
1328 "Failed to parse RequiredFamilyForOnline= setting");
1329
1330 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1331 "Failed to parse KeepConfiguration= setting");
1332
1333 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1334 [KEEP_CONFIGURATION_NO] = "no",
1335 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1336 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1337 [KEEP_CONFIGURATION_STATIC] = "static",
1338 [KEEP_CONFIGURATION_YES] = "yes",
1339 };
1340
1341 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
1342
1343 static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = {
1344 [ACTIVATION_POLICY_UP] = "up",
1345 [ACTIVATION_POLICY_ALWAYS_UP] = "always-up",
1346 [ACTIVATION_POLICY_MANUAL] = "manual",
1347 [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down",
1348 [ACTIVATION_POLICY_DOWN] = "down",
1349 [ACTIVATION_POLICY_BOUND] = "bound",
1350 };
1351
1352 DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy);
1353 DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy");