]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
network: Fix "Unknown section 'DHCPv6PrefixDelegation'." message
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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 "networkd-dhcp-server.h"
16 #include "network-internal.h"
17 #include "networkd-manager.h"
18 #include "networkd-network.h"
19 #include "networkd-sriov.h"
20 #include "parse-util.h"
21 #include "path-lookup.h"
22 #include "set.h"
23 #include "socket-util.h"
24 #include "stat-util.h"
25 #include "string-table.h"
26 #include "string-util.h"
27 #include "strv.h"
28 #include "tc.h"
29 #include "util.h"
30
31 /* Let's assume that anything above this number is a user misconfiguration. */
32 #define MAX_NTP_SERVERS 128
33
34 /* Set defaults following RFC7844 */
35 void network_apply_anonymize_if_set(Network *network) {
36 if (!network->dhcp_anonymize)
37 return;
38 /* RFC7844 3.7
39 SHOULD NOT send the Host Name option */
40 network->dhcp_send_hostname = false;
41 /* RFC7844 section 3.:
42 MAY contain the Client Identifier option
43 Section 3.5:
44 clients MUST use client identifiers based solely
45 on the link-layer address */
46 /* NOTE: Using MAC, as it does not reveal extra information,
47 * and some servers might not answer if this option is not sent */
48 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
49 /* RFC 7844 3.10:
50 SHOULD NOT use the Vendor Class Identifier option */
51 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
52 /* RFC7844 section 3.6.:
53 The client intending to protect its privacy SHOULD only request a
54 minimal number of options in the PRL and SHOULD also randomly shuffle
55 the ordering of option codes in the PRL. If this random ordering
56 cannot be implemented, the client MAY order the option codes in the
57 PRL by option code number (lowest to highest).
58 */
59 /* NOTE: dhcp_use_mtu is false by default,
60 * though it was not initiallized to any value in network_load_one.
61 * Maybe there should be another var called *send*?
62 * (to use the MTU sent by the server but to do not send
63 * the option in the PRL). */
64 network->dhcp_use_mtu = false;
65 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
66 * but this is needed to use them. */
67 network->dhcp_use_routes = true;
68 /* RFC7844 section 3.6.
69 * same comments as previous option */
70 network->dhcp_use_timezone = false;
71 }
72
73 static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
74 const char *kind_string;
75 NetDev *netdev;
76 int r;
77
78 /* For test-networkd-conf, the check must be earlier than the assertions. */
79 if (!name)
80 return 0;
81
82 assert(network);
83 assert(network->manager);
84 assert(network->filename);
85 assert(ret_netdev);
86
87 if (kind == _NETDEV_KIND_TUNNEL)
88 kind_string = "tunnel";
89 else {
90 kind_string = netdev_kind_to_string(kind);
91 if (!kind_string)
92 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
93 "%s: Invalid NetDev kind of %s, ignoring assignment.",
94 network->filename, name);
95 }
96
97 r = netdev_get(network->manager, name, &netdev);
98 if (r < 0)
99 return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
100 network->filename, name);
101
102 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
103 IN_SET(netdev->kind,
104 NETDEV_KIND_IPIP,
105 NETDEV_KIND_SIT,
106 NETDEV_KIND_GRE,
107 NETDEV_KIND_GRETAP,
108 NETDEV_KIND_IP6GRE,
109 NETDEV_KIND_IP6GRETAP,
110 NETDEV_KIND_VTI,
111 NETDEV_KIND_VTI6,
112 NETDEV_KIND_IP6TNL,
113 NETDEV_KIND_ERSPAN)))
114 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
115 "%s: NetDev %s is not a %s, ignoring assignment",
116 network->filename, name, kind_string);
117
118 *ret_netdev = netdev_ref(netdev);
119 return 1;
120 }
121
122 static int network_resolve_stacked_netdevs(Network *network) {
123 void *name, *kind;
124 Iterator i;
125 int r;
126
127 assert(network);
128
129 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
130 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
131
132 r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
133 if (r <= 0)
134 continue;
135
136 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
137 if (r < 0)
138 return log_oom();
139
140 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
141 if (r < 0)
142 return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
143 network->filename, (const char *) name);
144
145 netdev = NULL;
146 }
147
148 return 0;
149 }
150
151 int network_verify(Network *network) {
152 RoutePrefix *route_prefix, *route_prefix_next;
153 RoutingPolicyRule *rule, *rule_next;
154 Neighbor *neighbor, *neighbor_next;
155 AddressLabel *label, *label_next;
156 NextHop *nexthop, *nextnop_next;
157 Address *address, *address_next;
158 Prefix *prefix, *prefix_next;
159 Route *route, *route_next;
160 FdbEntry *fdb, *fdb_next;
161 TrafficControl *tc;
162 SRIOV *sr_iov;
163 Iterator i;
164
165 assert(network);
166 assert(network->filename);
167
168 if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) &&
169 strv_isempty(network->match_path) && strv_isempty(network->match_driver) &&
170 strv_isempty(network->match_type) && strv_isempty(network->match_name) &&
171 strv_isempty(network->match_property) && strv_isempty(network->match_wlan_iftype) &&
172 strv_isempty(network->match_ssid) && !network->conditions)
173 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
174 "%s: No valid settings found in the [Match] section, ignoring file. "
175 "To match all interfaces, add Name=* in the [Match] section.",
176 network->filename);
177
178 /* skip out early if configuration does not match the environment */
179 if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
180 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
181 "%s: Conditions in the file do not match the system environment, skipping.",
182 network->filename);
183
184 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
185 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
186 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
187 (void) network_resolve_stacked_netdevs(network);
188
189 /* Free unnecessary entries. */
190 network->bond_name = mfree(network->bond_name);
191 network->bridge_name = mfree(network->bridge_name);
192 network->vrf_name = mfree(network->vrf_name);
193 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
194
195 if (network->bond) {
196 /* Bonding slave does not support addressing. */
197 if (network->ipv6_accept_ra > 0) {
198 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
199 network->filename);
200 network->ipv6_accept_ra = 0;
201 }
202 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
203 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
204 network->filename);
205 network->link_local = ADDRESS_FAMILY_NO;
206 }
207 if (network->dhcp != ADDRESS_FAMILY_NO) {
208 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
209 network->filename);
210 network->dhcp = ADDRESS_FAMILY_NO;
211 }
212 if (network->dhcp_server) {
213 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
214 network->filename);
215 network->dhcp_server = false;
216 }
217 if (network->n_static_addresses > 0) {
218 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
219 network->filename);
220 while ((address = network->static_addresses))
221 address_free(address);
222 }
223 if (network->n_static_routes > 0) {
224 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
225 network->filename);
226 while ((route = network->static_routes))
227 route_free(route);
228 }
229 }
230
231 if (network->link_local < 0)
232 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
233
234 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
235 if (network->ipv6_accept_ra > 0) {
236 log_warning("%s: IPv6AcceptRA= is enabled by the .network file but IPv6 link local addressing is disabled. "
237 "Disabling IPv6AcceptRA=.", network->filename);
238 network->ipv6_accept_ra = false;
239 }
240
241 if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) {
242 log_warning("%s: DHCPv6 client is enabled by the .network file but IPv6 link local addressing is disabled. "
243 "Disabling DHCPv6 client.", network->filename);
244 SET_FLAG(network->dhcp, ADDRESS_FAMILY_IPV6, false);
245 }
246
247 if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) {
248 log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link local addressing is disabled. "
249 "Disabling IPv6PrefixDelegation=.", network->filename);
250 network->router_prefix_delegation = RADV_PREFIX_DELEGATION_NONE;
251 }
252 }
253
254 if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
255 !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
256 log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
257 "Disabling the fallback assignment.", network->filename);
258 SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
259 }
260
261 if (network->ipv6_accept_ra < 0 && network->bridge)
262 network->ipv6_accept_ra = false;
263
264 /* IPMasquerade=yes implies IPForward=yes */
265 if (network->ip_masquerade)
266 network->ip_forward |= ADDRESS_FAMILY_IPV4;
267
268 if (network->mtu > 0 && network->dhcp_use_mtu) {
269 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
270 "Disabling UseMTU=.", network->filename);
271 network->dhcp_use_mtu = false;
272 }
273
274 if (network->dhcp_use_gateway < 0)
275 network->dhcp_use_gateway = network->dhcp_use_routes;
276
277 if (network->ignore_carrier_loss < 0)
278 network->ignore_carrier_loss = network->configure_without_carrier;
279
280 if (network->dhcp_critical >= 0) {
281 if (network->keep_configuration >= 0)
282 log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
283 "Ignoring CriticalConnection=.", network->filename);
284 else if (network->dhcp_critical)
285 /* CriticalConnection=yes also preserve foreign static configurations. */
286 network->keep_configuration = KEEP_CONFIGURATION_YES;
287 else
288 network->keep_configuration = KEEP_CONFIGURATION_NO;
289 }
290
291 if (network->keep_configuration < 0)
292 network->keep_configuration = KEEP_CONFIGURATION_NO;
293
294 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
295 if (address_section_verify(address) < 0)
296 address_free(address);
297
298 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
299 if (route_section_verify(route, network) < 0)
300 route_free(route);
301
302 LIST_FOREACH_SAFE(nexthops, nexthop, nextnop_next, network->static_nexthops)
303 if (nexthop_section_verify(nexthop) < 0)
304 nexthop_free(nexthop);
305
306 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
307 if (section_is_invalid(fdb->section))
308 fdb_entry_free(fdb);
309
310 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
311 if (neighbor_section_verify(neighbor) < 0)
312 neighbor_free(neighbor);
313
314 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
315 if (section_is_invalid(label->section))
316 address_label_free(label);
317
318 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
319 if (section_is_invalid(prefix->section))
320 prefix_free(prefix);
321
322 LIST_FOREACH_SAFE(route_prefixes, route_prefix, route_prefix_next, network->static_route_prefixes)
323 if (section_is_invalid(route_prefix->section))
324 route_prefix_free(route_prefix);
325
326 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
327 if (routing_policy_rule_section_verify(rule) < 0)
328 routing_policy_rule_free(rule);
329
330 bool has_root = false, has_clsact = false;
331 ORDERED_HASHMAP_FOREACH(tc, network->tc_by_section, i)
332 if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
333 traffic_control_free(tc);
334
335 ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section, i)
336 if (sr_iov_section_verify(sr_iov) < 0)
337 sr_iov_free(sr_iov);
338
339 return 0;
340 }
341
342 int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
343 _cleanup_free_ char *fname = NULL, *name = NULL;
344 _cleanup_(network_unrefp) Network *network = NULL;
345 _cleanup_fclose_ FILE *file = NULL;
346 const char *dropin_dirname;
347 char *d;
348 int r;
349
350 assert(manager);
351 assert(filename);
352
353 file = fopen(filename, "re");
354 if (!file) {
355 if (errno == ENOENT)
356 return 0;
357
358 return -errno;
359 }
360
361 if (null_or_empty_fd(fileno(file))) {
362 log_debug("Skipping empty file: %s", filename);
363 return 0;
364 }
365
366 fname = strdup(filename);
367 if (!fname)
368 return log_oom();
369
370 name = strdup(basename(filename));
371 if (!name)
372 return log_oom();
373
374 d = strrchr(name, '.');
375 if (!d)
376 return -EINVAL;
377
378 *d = '\0';
379
380 dropin_dirname = strjoina(name, ".network.d");
381
382 network = new(Network, 1);
383 if (!network)
384 return log_oom();
385
386 *network = (Network) {
387 .filename = TAKE_PTR(fname),
388 .name = TAKE_PTR(name),
389
390 .manager = manager,
391 .n_ref = 1,
392
393 .required_for_online = true,
394 .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT,
395 .dhcp = ADDRESS_FAMILY_NO,
396 .dhcp_critical = -1,
397 .dhcp_use_ntp = true,
398 .dhcp_use_sip = true,
399 .dhcp_use_dns = true,
400 .dhcp_use_hostname = true,
401 .dhcp_use_routes = true,
402 .dhcp_use_gateway = -1,
403 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
404 .dhcp_send_hostname = true,
405 .dhcp_send_release = true,
406 /* To enable/disable RFC7844 Anonymity Profiles */
407 .dhcp_anonymize = false,
408 .dhcp_route_metric = DHCP_ROUTE_METRIC,
409 /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
410 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
411 .dhcp_route_table = RT_TABLE_MAIN,
412 .dhcp_route_table_set = false,
413 /* NOTE: from man: UseMTU=... Defaults to false*/
414 .dhcp_use_mtu = false,
415 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
416 .dhcp_use_timezone = false,
417 .rapid_commit = true,
418
419 .dhcp6_route_metric = DHCP_ROUTE_METRIC,
420 .dhcp6_use_ntp = true,
421 .dhcp6_use_dns = true,
422
423 .dhcp6_pd_subnet_id = -1,
424 .dhcp6_pd_assign = true,
425
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
430 .dhcp_server_emit_router = true,
431 .dhcp_server_emit_timezone = true,
432
433 .router_emit_dns = true,
434 .router_emit_domains = true,
435
436 .use_bpdu = -1,
437 .hairpin = -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 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
451
452 .dns_default_route = -1,
453 .llmnr = RESOLVE_SUPPORT_YES,
454 .mdns = RESOLVE_SUPPORT_NO,
455 .dnssec_mode = _DNSSEC_MODE_INVALID,
456 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
457
458 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
459 .link_local = _ADDRESS_FAMILY_INVALID,
460 .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
461
462 .ipv4_accept_local = -1,
463
464 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
465 .ipv6_accept_ra = -1,
466 .ipv6_dad_transmits = -1,
467 .ipv6_hop_limit = -1,
468 .ipv6_proxy_ndp = -1,
469 .duid.type = _DUID_TYPE_INVALID,
470 .proxy_arp = -1,
471 .arp = -1,
472 .multicast = -1,
473 .allmulticast = -1,
474 .ipv6_accept_ra_use_dns = true,
475 .ipv6_accept_ra_use_autonomous_prefix = true,
476 .ipv6_accept_ra_use_onlink_prefix = true,
477 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
478 .ipv6_accept_ra_route_table_set = false,
479 .ipv6_accept_ra_start_dhcp6_client = true,
480
481 .configure_without_carrier = false,
482 .ignore_carrier_loss = -1,
483 .keep_configuration = _KEEP_CONFIGURATION_INVALID,
484 .can_triple_sampling = -1,
485 .can_termination = -1,
486 .ip_service_type = -1,
487 };
488
489 r = config_parse_many(
490 filename, NETWORK_DIRS, dropin_dirname,
491 "Match\0"
492 "Link\0"
493 "SR-IOV\0"
494 "Network\0"
495 "Address\0"
496 "Neighbor\0"
497 "IPv6AddressLabel\0"
498 "RoutingPolicyRule\0"
499 "Route\0"
500 "NextHop\0"
501 "DHCP\0" /* compat */
502 "DHCPv4\0"
503 "DHCPv6\0"
504 "DHCPv6PrefixDelegation\0"
505 "DHCPServer\0"
506 "IPv6AcceptRA\0"
507 "IPv6NDPProxyAddress\0"
508 "Bridge\0"
509 "BridgeFDB\0"
510 "BridgeVLAN\0"
511 "IPv6PrefixDelegation\0"
512 "IPv6Prefix\0"
513 "IPv6RoutePrefix\0"
514 "LLDP\0"
515 "TrafficControlQueueingDiscipline\0"
516 "CAN\0"
517 "QDisc\0"
518 "BFIFO\0"
519 "CAKE\0"
520 "ControlledDelay\0"
521 "DeficitRoundRobinScheduler\0"
522 "DeficitRoundRobinSchedulerClass\0"
523 "EnhancedTransmissionSelection\0"
524 "FairQueueing\0"
525 "FairQueueingControlledDelay\0"
526 "GenericRandomEarlyDetection\0"
527 "HeavyHitterFilter\0"
528 "HierarchyTokenBucket\0"
529 "HierarchyTokenBucketClass\0"
530 "NetworkEmulator\0"
531 "PFIFO\0"
532 "PFIFOFast\0"
533 "PFIFOHeadDrop\0"
534 "PIE\0"
535 "QuickFairQueueing\0"
536 "QuickFairQueueingClass\0"
537 "StochasticFairBlue\0"
538 "StochasticFairnessQueueing\0"
539 "TokenBucketFilter\0"
540 "TrivialLinkEqualizer\0",
541 config_item_perf_lookup, network_network_gperf_lookup,
542 CONFIG_PARSE_WARN,
543 network,
544 &network->timestamp);
545 if (r < 0)
546 return r;
547
548 network_apply_anonymize_if_set(network);
549
550 r = network_add_ipv4ll_route(network);
551 if (r < 0)
552 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
553
554 r = network_add_default_route_on_device(network);
555 if (r < 0)
556 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
557 network->filename);
558
559 if (network_verify(network) < 0)
560 /* Ignore .network files that do not match the conditions. */
561 return 0;
562
563 r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops);
564 if (r < 0)
565 return r;
566
567 r = ordered_hashmap_put(*networks, network->name, network);
568 if (r < 0)
569 return r;
570
571 network = NULL;
572 return 0;
573 }
574
575 int network_load(Manager *manager, OrderedHashmap **networks) {
576 _cleanup_strv_free_ char **files = NULL;
577 char **f;
578 int r;
579
580 assert(manager);
581
582 ordered_hashmap_clear_with_destructor(*networks, network_unref);
583
584 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
585 if (r < 0)
586 return log_error_errno(r, "Failed to enumerate network files: %m");
587
588 STRV_FOREACH(f, files) {
589 r = network_load_one(manager, networks, *f);
590 if (r < 0)
591 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
592 }
593
594 return 0;
595 }
596
597 int network_reload(Manager *manager) {
598 OrderedHashmap *new_networks = NULL;
599 Network *n, *old;
600 Iterator i;
601 int r;
602
603 assert(manager);
604
605 r = network_load(manager, &new_networks);
606 if (r < 0)
607 goto failure;
608
609 ORDERED_HASHMAP_FOREACH(n, new_networks, i) {
610 r = network_get_by_name(manager, n->name, &old);
611 if (r < 0)
612 continue; /* The .network file is new. */
613
614 if (n->timestamp != old->timestamp)
615 continue; /* The .network file is modified. */
616
617 if (!streq(n->filename, old->filename))
618 continue;
619
620 r = ordered_hashmap_replace(new_networks, old->name, old);
621 if (r < 0)
622 goto failure;
623
624 network_ref(old);
625 network_unref(n);
626 }
627
628 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
629 manager->networks = new_networks;
630
631 return 0;
632
633 failure:
634 ordered_hashmap_free_with_destructor(new_networks, network_unref);
635
636 return r;
637 }
638
639 static Network *network_free(Network *network) {
640 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
641 RoutePrefix *route_prefix;
642 RoutingPolicyRule *rule;
643 AddressLabel *label;
644 FdbEntry *fdb_entry;
645 Neighbor *neighbor;
646 Address *address;
647 NextHop *nexthop;
648 Prefix *prefix;
649 Route *route;
650
651 if (!network)
652 return NULL;
653
654 free(network->filename);
655
656 set_free_free(network->match_mac);
657 set_free_free(network->match_permanent_mac);
658 strv_free(network->match_path);
659 strv_free(network->match_driver);
660 strv_free(network->match_type);
661 strv_free(network->match_name);
662 strv_free(network->match_property);
663 strv_free(network->match_wlan_iftype);
664 strv_free(network->match_ssid);
665 set_free_free(network->match_bssid);
666 condition_free_list(network->conditions);
667
668 free(network->description);
669 free(network->dhcp_vendor_class_identifier);
670 free(network->dhcp_mudurl);
671 strv_free(network->dhcp_user_class);
672 free(network->dhcp_hostname);
673 set_free(network->dhcp_deny_listed_ip);
674 set_free(network->dhcp_allow_listed_ip);
675 set_free(network->dhcp_request_options);
676 set_free(network->dhcp6_request_options);
677 free(network->mac);
678 free(network->dhcp6_mudurl);
679 strv_free(network->dhcp6_user_class);
680 strv_free(network->dhcp6_vendor_class);
681
682 if (network->dhcp_acd)
683 sd_ipv4acd_unref(network->dhcp_acd);
684
685 strv_free(network->ntp);
686 for (unsigned i = 0; i < network->n_dns; i++)
687 in_addr_full_free(network->dns[i]);
688 free(network->dns);
689 ordered_set_free_free(network->search_domains);
690 ordered_set_free_free(network->route_domains);
691 strv_free(network->bind_carrier);
692
693 ordered_set_free_free(network->router_search_domains);
694 free(network->router_dns);
695 set_free_free(network->ndisc_deny_listed_prefix);
696
697 free(network->bridge_name);
698 free(network->bond_name);
699 free(network->vrf_name);
700 hashmap_free_free_key(network->stacked_netdev_names);
701 netdev_unref(network->bridge);
702 netdev_unref(network->bond);
703 netdev_unref(network->vrf);
704 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
705
706 while ((route = network->static_routes))
707 route_free(route);
708
709 while ((nexthop = network->static_nexthops))
710 nexthop_free(nexthop);
711
712 while ((address = network->static_addresses))
713 address_free(address);
714
715 while ((fdb_entry = network->static_fdb_entries))
716 fdb_entry_free(fdb_entry);
717
718 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
719 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
720
721 while ((neighbor = network->neighbors))
722 neighbor_free(neighbor);
723
724 while ((label = network->address_labels))
725 address_label_free(label);
726
727 while ((prefix = network->static_prefixes))
728 prefix_free(prefix);
729
730 while ((route_prefix = network->static_route_prefixes))
731 route_prefix_free(route_prefix);
732
733 while ((rule = network->rules))
734 routing_policy_rule_free(rule);
735
736 hashmap_free(network->addresses_by_section);
737 hashmap_free(network->routes_by_section);
738 hashmap_free(network->nexthops_by_section);
739 hashmap_free(network->fdb_entries_by_section);
740 hashmap_free(network->neighbors_by_section);
741 hashmap_free(network->address_labels_by_section);
742 hashmap_free(network->prefixes_by_section);
743 hashmap_free(network->route_prefixes_by_section);
744 hashmap_free(network->rules_by_section);
745 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
746 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
747
748 if (network->manager &&
749 network->manager->duids_requesting_uuid)
750 set_remove(network->manager->duids_requesting_uuid, &network->duid);
751
752 free(network->name);
753
754 free(network->dhcp_server_timezone);
755
756 for (sd_dhcp_lease_server_type t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
757 free(network->dhcp_server_emit[t].addresses);
758
759 set_free_free(network->dnssec_negative_trust_anchors);
760
761 free(network->lldp_mud);
762
763 ordered_hashmap_free(network->dhcp_client_send_options);
764 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
765 ordered_hashmap_free(network->dhcp_server_send_options);
766 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
767 ordered_set_free(network->ipv6_tokens);
768 ordered_hashmap_free(network->dhcp6_client_send_options);
769 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
770
771 return mfree(network);
772 }
773
774 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
775
776 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
777 Network *network;
778
779 assert(manager);
780 assert(name);
781 assert(ret);
782
783 network = ordered_hashmap_get(manager->networks, name);
784 if (!network)
785 return -ENOENT;
786
787 *ret = network;
788
789 return 0;
790 }
791
792 int network_get(Manager *manager, unsigned short iftype, sd_device *device,
793 const char *ifname, char * const *alternative_names, const char *driver,
794 const struct ether_addr *mac, const struct ether_addr *permanent_mac,
795 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
796 Network **ret) {
797 Network *network;
798 Iterator i;
799
800 assert(manager);
801 assert(ret);
802
803 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
804 if (net_match_config(network->match_mac, network->match_permanent_mac,
805 network->match_path, network->match_driver,
806 network->match_type, network->match_name, network->match_property,
807 network->match_wlan_iftype, network->match_ssid, network->match_bssid,
808 device, mac, permanent_mac, driver, iftype,
809 ifname, alternative_names, wlan_iftype, ssid, bssid)) {
810 if (network->match_name && device) {
811 const char *attr;
812 uint8_t name_assign_type = NET_NAME_UNKNOWN;
813
814 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
815 (void) safe_atou8(attr, &name_assign_type);
816
817 if (name_assign_type == NET_NAME_ENUM)
818 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
819 ifname, network->filename);
820 else
821 log_debug("%s: found matching network '%s'", ifname, network->filename);
822 } else
823 log_debug("%s: found matching network '%s'", ifname, network->filename);
824
825 *ret = network;
826 return 0;
827 }
828
829 *ret = NULL;
830
831 return -ENOENT;
832 }
833
834 int network_apply(Network *network, Link *link) {
835 assert(network);
836 assert(link);
837
838 link->network = network_ref(network);
839
840 if (network->n_dns > 0 ||
841 !strv_isempty(network->ntp) ||
842 !ordered_set_isempty(network->search_domains) ||
843 !ordered_set_isempty(network->route_domains))
844 link_dirty(link);
845
846 return 0;
847 }
848
849 bool network_has_static_ipv6_configurations(Network *network) {
850 Address *address;
851 Route *route;
852 FdbEntry *fdb;
853 Neighbor *neighbor;
854
855 assert(network);
856
857 LIST_FOREACH(addresses, address, network->static_addresses)
858 if (address->family == AF_INET6)
859 return true;
860
861 LIST_FOREACH(routes, route, network->static_routes)
862 if (route->family == AF_INET6)
863 return true;
864
865 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
866 if (fdb->family == AF_INET6)
867 return true;
868
869 LIST_FOREACH(neighbors, neighbor, network->neighbors)
870 if (neighbor->family == AF_INET6)
871 return true;
872
873 if (!LIST_IS_EMPTY(network->address_labels))
874 return true;
875
876 if (!LIST_IS_EMPTY(network->static_prefixes))
877 return true;
878
879 return false;
880 }
881
882 int config_parse_stacked_netdev(const char *unit,
883 const char *filename,
884 unsigned line,
885 const char *section,
886 unsigned section_line,
887 const char *lvalue,
888 int ltype,
889 const char *rvalue,
890 void *data,
891 void *userdata) {
892 _cleanup_free_ char *name = NULL;
893 NetDevKind kind = ltype;
894 Hashmap **h = data;
895 int r;
896
897 assert(filename);
898 assert(lvalue);
899 assert(rvalue);
900 assert(data);
901 assert(IN_SET(kind,
902 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
903 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
904 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
905 NETDEV_KIND_XFRM));
906
907 if (!ifname_valid(rvalue)) {
908 log_syntax(unit, LOG_WARNING, filename, line, 0,
909 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
910 return 0;
911 }
912
913 name = strdup(rvalue);
914 if (!name)
915 return log_oom();
916
917 r = hashmap_ensure_allocated(h, &string_hash_ops);
918 if (r < 0)
919 return log_oom();
920
921 r = hashmap_put(*h, name, INT_TO_PTR(kind));
922 if (r < 0)
923 log_syntax(unit, LOG_WARNING, filename, line, r,
924 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
925 else if (r == 0)
926 log_syntax(unit, LOG_DEBUG, filename, line, r,
927 "NetDev '%s' specified twice, ignoring.", name);
928 else
929 name = NULL;
930
931 return 0;
932 }
933
934 int config_parse_domains(
935 const char *unit,
936 const char *filename,
937 unsigned line,
938 const char *section,
939 unsigned section_line,
940 const char *lvalue,
941 int ltype,
942 const char *rvalue,
943 void *data,
944 void *userdata) {
945
946 Network *n = data;
947 int r;
948
949 assert(n);
950 assert(lvalue);
951 assert(rvalue);
952
953 if (isempty(rvalue)) {
954 n->search_domains = ordered_set_free_free(n->search_domains);
955 n->route_domains = ordered_set_free_free(n->route_domains);
956 return 0;
957 }
958
959 for (const char *p = rvalue;;) {
960 _cleanup_free_ char *w = NULL, *normalized = NULL;
961 const char *domain;
962 bool is_route;
963
964 r = extract_first_word(&p, &w, NULL, 0);
965 if (r == -ENOMEM)
966 return log_oom();
967 if (r < 0) {
968 log_syntax(unit, LOG_WARNING, filename, line, r,
969 "Failed to extract search or route domain, ignoring: %s", rvalue);
970 return 0;
971 }
972 if (r == 0)
973 return 0;
974
975 is_route = w[0] == '~';
976 domain = is_route ? w + 1 : w;
977
978 if (dns_name_is_root(domain) || streq(domain, "*")) {
979 /* If the root domain appears as is, or the special token "*" is found, we'll
980 * consider this as routing domain, unconditionally. */
981 is_route = true;
982 domain = "."; /* make sure we don't allow empty strings, thus write the root
983 * domain as "." */
984 } else {
985 r = dns_name_normalize(domain, 0, &normalized);
986 if (r < 0) {
987 log_syntax(unit, LOG_WARNING, filename, line, r,
988 "'%s' is not a valid domain name, ignoring.", domain);
989 continue;
990 }
991
992 domain = normalized;
993
994 if (is_localhost(domain)) {
995 log_syntax(unit, LOG_WARNING, filename, line, 0,
996 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
997 domain);
998 continue;
999 }
1000 }
1001
1002 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
1003 r = ordered_set_ensure_allocated(set, &string_hash_ops);
1004 if (r < 0)
1005 return log_oom();
1006
1007 r = ordered_set_put_strdup(*set, domain);
1008 if (r < 0)
1009 return log_oom();
1010 }
1011 }
1012
1013 int config_parse_ipv6token(
1014 const char* unit,
1015 const char *filename,
1016 unsigned line,
1017 const char *section,
1018 unsigned section_line,
1019 const char *lvalue,
1020 int ltype,
1021 const char *rvalue,
1022 void *data,
1023 void *userdata) {
1024
1025 union in_addr_union buffer;
1026 struct in6_addr *token = data;
1027 int r;
1028
1029 assert(filename);
1030 assert(lvalue);
1031 assert(rvalue);
1032 assert(token);
1033
1034 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
1035 if (r < 0) {
1036 log_syntax(unit, LOG_WARNING, filename, line, r,
1037 "Failed to parse IPv6 token, ignoring: %s", rvalue);
1038 return 0;
1039 }
1040
1041 if (in_addr_is_null(AF_INET6, &buffer)) {
1042 log_syntax(unit, LOG_WARNING, filename, line, 0,
1043 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
1044 return 0;
1045 }
1046
1047 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
1048 log_syntax(unit, LOG_WARNING, filename, line, 0,
1049 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
1050 return 0;
1051 }
1052
1053 *token = buffer.in6;
1054
1055 return 0;
1056 }
1057
1058 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1059 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
1060 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
1061 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
1062 };
1063
1064 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
1065 IPV6_PRIVACY_EXTENSIONS_YES);
1066
1067 int config_parse_ipv6_privacy_extensions(
1068 const char* unit,
1069 const char *filename,
1070 unsigned line,
1071 const char *section,
1072 unsigned section_line,
1073 const char *lvalue,
1074 int ltype,
1075 const char *rvalue,
1076 void *data,
1077 void *userdata) {
1078
1079 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
1080
1081 assert(filename);
1082 assert(lvalue);
1083 assert(rvalue);
1084 assert(ipv6_privacy_extensions);
1085
1086 s = ipv6_privacy_extensions_from_string(rvalue);
1087 if (s < 0) {
1088 if (streq(rvalue, "kernel"))
1089 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1090 else {
1091 log_syntax(unit, LOG_WARNING, filename, line, 0,
1092 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1093 return 0;
1094 }
1095 }
1096
1097 *ipv6_privacy_extensions = s;
1098
1099 return 0;
1100 }
1101
1102 int config_parse_hostname(
1103 const char *unit,
1104 const char *filename,
1105 unsigned line,
1106 const char *section,
1107 unsigned section_line,
1108 const char *lvalue,
1109 int ltype,
1110 const char *rvalue,
1111 void *data,
1112 void *userdata) {
1113
1114 _cleanup_free_ char *hn = NULL;
1115 char **hostname = data;
1116 int r;
1117
1118 assert(filename);
1119 assert(lvalue);
1120 assert(rvalue);
1121
1122 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
1123 if (r < 0)
1124 return r;
1125
1126 if (!hostname_is_valid(hn, false)) {
1127 log_syntax(unit, LOG_WARNING, filename, line, 0,
1128 "Hostname is not valid, ignoring assignment: %s", rvalue);
1129 return 0;
1130 }
1131
1132 r = dns_name_is_valid(hn);
1133 if (r < 0) {
1134 log_syntax(unit, LOG_WARNING, filename, line, r,
1135 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
1136 return 0;
1137 }
1138 if (r == 0) {
1139 log_syntax(unit, LOG_WARNING, filename, line, 0,
1140 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
1141 return 0;
1142 }
1143
1144 return free_and_replace(*hostname, hn);
1145 }
1146
1147 int config_parse_timezone(
1148 const char *unit,
1149 const char *filename,
1150 unsigned line,
1151 const char *section,
1152 unsigned section_line,
1153 const char *lvalue,
1154 int ltype,
1155 const char *rvalue,
1156 void *data,
1157 void *userdata) {
1158
1159 _cleanup_free_ char *tz = NULL;
1160 char **datap = data;
1161 int r;
1162
1163 assert(filename);
1164 assert(lvalue);
1165 assert(rvalue);
1166
1167 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1168 if (r < 0)
1169 return r;
1170
1171 if (!timezone_is_valid(tz, LOG_WARNING)) {
1172 log_syntax(unit, LOG_WARNING, filename, line, 0,
1173 "Timezone is not valid, ignoring assignment: %s", rvalue);
1174 return 0;
1175 }
1176
1177 return free_and_replace(*datap, tz);
1178 }
1179
1180 int config_parse_dns(
1181 const char *unit,
1182 const char *filename,
1183 unsigned line,
1184 const char *section,
1185 unsigned section_line,
1186 const char *lvalue,
1187 int ltype,
1188 const char *rvalue,
1189 void *data,
1190 void *userdata) {
1191
1192 Network *n = userdata;
1193 int r;
1194
1195 assert(filename);
1196 assert(lvalue);
1197 assert(rvalue);
1198
1199 if (isempty(rvalue)) {
1200 for (unsigned i = 0; i < n->n_dns; i++)
1201 in_addr_full_free(n->dns[i]);
1202 n->dns = mfree(n->dns);
1203 n->n_dns = 0;
1204 return 0;
1205 }
1206
1207 for (const char *p = rvalue;;) {
1208 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
1209 _cleanup_free_ char *w = NULL;
1210 struct in_addr_full **m;
1211
1212 r = extract_first_word(&p, &w, NULL, 0);
1213 if (r == -ENOMEM)
1214 return log_oom();
1215 if (r < 0) {
1216 log_syntax(unit, LOG_WARNING, filename, line, r,
1217 "Invalid syntax, ignoring: %s", rvalue);
1218 return 0;
1219 }
1220 if (r == 0)
1221 return 0;
1222
1223 r = in_addr_full_new_from_string(w, &dns);
1224 if (r < 0) {
1225 log_syntax(unit, LOG_WARNING, filename, line, r,
1226 "Failed to parse dns server address, ignoring: %s", w);
1227 continue;
1228 }
1229
1230 if (IN_SET(dns->port, 53, 853))
1231 dns->port = 0;
1232
1233 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
1234 if (!m)
1235 return log_oom();
1236
1237 m[n->n_dns++] = TAKE_PTR(dns);
1238 n->dns = m;
1239 }
1240 }
1241
1242 int config_parse_dnssec_negative_trust_anchors(
1243 const char *unit,
1244 const char *filename,
1245 unsigned line,
1246 const char *section,
1247 unsigned section_line,
1248 const char *lvalue,
1249 int ltype,
1250 const char *rvalue,
1251 void *data,
1252 void *userdata) {
1253
1254 Network *n = data;
1255 int r;
1256
1257 assert(n);
1258 assert(lvalue);
1259 assert(rvalue);
1260
1261 if (isempty(rvalue)) {
1262 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1263 return 0;
1264 }
1265
1266 for (const char *p = rvalue;;) {
1267 _cleanup_free_ char *w = NULL;
1268
1269 r = extract_first_word(&p, &w, NULL, 0);
1270 if (r == -ENOMEM)
1271 return log_oom();
1272 if (r < 0) {
1273 log_syntax(unit, LOG_WARNING, filename, line, r,
1274 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1275 return 0;
1276 }
1277 if (r == 0)
1278 return 0;
1279
1280 r = dns_name_is_valid(w);
1281 if (r <= 0) {
1282 log_syntax(unit, LOG_WARNING, filename, line, r,
1283 "%s is not a valid domain name, ignoring.", w);
1284 continue;
1285 }
1286
1287 r = set_ensure_consume(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops, TAKE_PTR(w));
1288 if (r < 0)
1289 return log_oom();
1290 }
1291 }
1292
1293 int config_parse_ntp(
1294 const char *unit,
1295 const char *filename,
1296 unsigned line,
1297 const char *section,
1298 unsigned section_line,
1299 const char *lvalue,
1300 int ltype,
1301 const char *rvalue,
1302 void *data,
1303 void *userdata) {
1304
1305 char ***l = data;
1306 int r;
1307
1308 assert(l);
1309 assert(lvalue);
1310 assert(rvalue);
1311
1312 if (isempty(rvalue)) {
1313 *l = strv_free(*l);
1314 return 0;
1315 }
1316
1317 for (const char *p = rvalue;;) {
1318 _cleanup_free_ char *w = NULL;
1319
1320 r = extract_first_word(&p, &w, NULL, 0);
1321 if (r == -ENOMEM)
1322 return log_oom();
1323 if (r < 0) {
1324 log_syntax(unit, LOG_WARNING, filename, line, r,
1325 "Failed to extract NTP server name, ignoring: %s", rvalue);
1326 return 0;
1327 }
1328 if (r == 0)
1329 return 0;
1330
1331 r = dns_name_is_valid_or_address(w);
1332 if (r <= 0) {
1333 log_syntax(unit, LOG_WARNING, filename, line, r,
1334 "%s is not a valid domain name or IP address, ignoring.", w);
1335 continue;
1336 }
1337
1338 if (strv_length(*l) > MAX_NTP_SERVERS) {
1339 log_syntax(unit, LOG_WARNING, filename, line, 0,
1340 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1341 MAX_NTP_SERVERS, w);
1342 return 0;
1343 }
1344
1345 r = strv_consume(l, TAKE_PTR(w));
1346 if (r < 0)
1347 return log_oom();
1348 }
1349 }
1350
1351 int config_parse_required_for_online(
1352 const char *unit,
1353 const char *filename,
1354 unsigned line,
1355 const char *section,
1356 unsigned section_line,
1357 const char *lvalue,
1358 int ltype,
1359 const char *rvalue,
1360 void *data,
1361 void *userdata) {
1362
1363 Network *network = data;
1364 LinkOperationalStateRange range;
1365 bool required = true;
1366 int r;
1367
1368 if (isempty(rvalue)) {
1369 network->required_for_online = true;
1370 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1371 return 0;
1372 }
1373
1374 r = parse_operational_state_range(rvalue, &range);
1375 if (r < 0) {
1376 r = parse_boolean(rvalue);
1377 if (r < 0) {
1378 log_syntax(unit, LOG_WARNING, filename, line, r,
1379 "Failed to parse %s= setting, ignoring assignment: %s",
1380 lvalue, rvalue);
1381 return 0;
1382 }
1383
1384 required = r;
1385 range = LINK_OPERSTATE_RANGE_DEFAULT;
1386 }
1387
1388 network->required_for_online = required;
1389 network->required_operstate_for_online = range;
1390
1391 return 0;
1392 }
1393
1394 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1395 "Failed to parse KeepConfiguration= setting");
1396
1397 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1398 [KEEP_CONFIGURATION_NO] = "no",
1399 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1400 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1401 [KEEP_CONFIGURATION_STATIC] = "static",
1402 [KEEP_CONFIGURATION_YES] = "yes",
1403 };
1404
1405 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
1406
1407 static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1408 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1409 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1410 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1411 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1412 };
1413
1414 DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1415 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_link_local_address_gen_mode, ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode, "Failed to parse IPv6 link local address generation mode");