]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #16514 from keszybz/zstd-decompress-fix
[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_assign_prefix = true,
424
425 .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
426 .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
427 .dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
428
429 .dhcp_server_emit_router = true,
430 .dhcp_server_emit_timezone = true,
431
432 .router_prefix_subnet_id = -1,
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 "DHCPServer\0"
505 "IPv6AcceptRA\0"
506 "IPv6NDPProxyAddress\0"
507 "Bridge\0"
508 "BridgeFDB\0"
509 "BridgeVLAN\0"
510 "IPv6PrefixDelegation\0"
511 "IPv6Prefix\0"
512 "IPv6RoutePrefix\0"
513 "LLDP\0"
514 "TrafficControlQueueingDiscipline\0"
515 "CAN\0"
516 "QDisc\0"
517 "BFIFO\0"
518 "CAKE\0"
519 "ControlledDelay\0"
520 "DeficitRoundRobinScheduler\0"
521 "DeficitRoundRobinSchedulerClass\0"
522 "EnhancedTransmissionSelection\0"
523 "FairQueueing\0"
524 "FairQueueingControlledDelay\0"
525 "GenericRandomEarlyDetection\0"
526 "HeavyHitterFilter\0"
527 "HierarchyTokenBucket\0"
528 "HierarchyTokenBucketClass\0"
529 "NetworkEmulator\0"
530 "PFIFO\0"
531 "PFIFOFast\0"
532 "PFIFOHeadDrop\0"
533 "PIE\0"
534 "QuickFairQueueing\0"
535 "QuickFairQueueingClass\0"
536 "StochasticFairBlue\0"
537 "StochasticFairnessQueueing\0"
538 "TokenBucketFilter\0"
539 "TrivialLinkEqualizer\0",
540 config_item_perf_lookup, network_network_gperf_lookup,
541 CONFIG_PARSE_WARN,
542 network,
543 &network->timestamp);
544 if (r < 0)
545 return r;
546
547 network_apply_anonymize_if_set(network);
548
549 r = network_add_ipv4ll_route(network);
550 if (r < 0)
551 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
552
553 r = network_add_default_route_on_device(network);
554 if (r < 0)
555 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
556 network->filename);
557
558 if (network_verify(network) < 0)
559 /* Ignore .network files that do not match the conditions. */
560 return 0;
561
562 r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops);
563 if (r < 0)
564 return r;
565
566 r = ordered_hashmap_put(*networks, network->name, network);
567 if (r < 0)
568 return r;
569
570 network = NULL;
571 return 0;
572 }
573
574 int network_load(Manager *manager, OrderedHashmap **networks) {
575 _cleanup_strv_free_ char **files = NULL;
576 char **f;
577 int r;
578
579 assert(manager);
580
581 ordered_hashmap_clear_with_destructor(*networks, network_unref);
582
583 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
584 if (r < 0)
585 return log_error_errno(r, "Failed to enumerate network files: %m");
586
587 STRV_FOREACH(f, files) {
588 r = network_load_one(manager, networks, *f);
589 if (r < 0)
590 log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
591 }
592
593 return 0;
594 }
595
596 int network_reload(Manager *manager) {
597 OrderedHashmap *new_networks = NULL;
598 Network *n, *old;
599 Iterator i;
600 int r;
601
602 assert(manager);
603
604 r = network_load(manager, &new_networks);
605 if (r < 0)
606 goto failure;
607
608 ORDERED_HASHMAP_FOREACH(n, new_networks, i) {
609 r = network_get_by_name(manager, n->name, &old);
610 if (r < 0)
611 continue; /* The .network file is new. */
612
613 if (n->timestamp != old->timestamp)
614 continue; /* The .network file is modified. */
615
616 if (!streq(n->filename, old->filename))
617 continue;
618
619 r = ordered_hashmap_replace(new_networks, old->name, old);
620 if (r < 0)
621 goto failure;
622
623 network_ref(old);
624 network_unref(n);
625 }
626
627 ordered_hashmap_free_with_destructor(manager->networks, network_unref);
628 manager->networks = new_networks;
629
630 return 0;
631
632 failure:
633 ordered_hashmap_free_with_destructor(new_networks, network_unref);
634
635 return r;
636 }
637
638 static Network *network_free(Network *network) {
639 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
640 RoutePrefix *route_prefix;
641 RoutingPolicyRule *rule;
642 AddressLabel *label;
643 FdbEntry *fdb_entry;
644 Neighbor *neighbor;
645 Address *address;
646 NextHop *nexthop;
647 Prefix *prefix;
648 Route *route;
649
650 if (!network)
651 return NULL;
652
653 free(network->filename);
654
655 set_free_free(network->match_mac);
656 set_free_free(network->match_permanent_mac);
657 strv_free(network->match_path);
658 strv_free(network->match_driver);
659 strv_free(network->match_type);
660 strv_free(network->match_name);
661 strv_free(network->match_property);
662 strv_free(network->match_wlan_iftype);
663 strv_free(network->match_ssid);
664 set_free_free(network->match_bssid);
665 condition_free_list(network->conditions);
666
667 free(network->description);
668 free(network->dhcp_vendor_class_identifier);
669 free(network->dhcp_mudurl);
670 strv_free(network->dhcp_user_class);
671 free(network->dhcp_hostname);
672 set_free(network->dhcp_deny_listed_ip);
673 set_free(network->dhcp_allow_listed_ip);
674 set_free(network->dhcp_request_options);
675 set_free(network->dhcp6_request_options);
676 free(network->mac);
677 free(network->dhcp6_mudurl);
678 strv_free(network->dhcp6_user_class);
679 strv_free(network->dhcp6_vendor_class);
680
681 if (network->dhcp_acd)
682 sd_ipv4acd_unref(network->dhcp_acd);
683
684 strv_free(network->ntp);
685 for (unsigned i = 0; i < network->n_dns; i++)
686 in_addr_full_free(network->dns[i]);
687 free(network->dns);
688 ordered_set_free_free(network->search_domains);
689 ordered_set_free_free(network->route_domains);
690 strv_free(network->bind_carrier);
691
692 ordered_set_free_free(network->router_search_domains);
693 free(network->router_dns);
694 set_free_free(network->ndisc_deny_listed_prefix);
695
696 free(network->bridge_name);
697 free(network->bond_name);
698 free(network->vrf_name);
699 hashmap_free_free_key(network->stacked_netdev_names);
700 netdev_unref(network->bridge);
701 netdev_unref(network->bond);
702 netdev_unref(network->vrf);
703 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
704
705 while ((route = network->static_routes))
706 route_free(route);
707
708 while ((nexthop = network->static_nexthops))
709 nexthop_free(nexthop);
710
711 while ((address = network->static_addresses))
712 address_free(address);
713
714 while ((fdb_entry = network->static_fdb_entries))
715 fdb_entry_free(fdb_entry);
716
717 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
718 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
719
720 while ((neighbor = network->neighbors))
721 neighbor_free(neighbor);
722
723 while ((label = network->address_labels))
724 address_label_free(label);
725
726 while ((prefix = network->static_prefixes))
727 prefix_free(prefix);
728
729 while ((route_prefix = network->static_route_prefixes))
730 route_prefix_free(route_prefix);
731
732 while ((rule = network->rules))
733 routing_policy_rule_free(rule);
734
735 hashmap_free(network->addresses_by_section);
736 hashmap_free(network->routes_by_section);
737 hashmap_free(network->nexthops_by_section);
738 hashmap_free(network->fdb_entries_by_section);
739 hashmap_free(network->neighbors_by_section);
740 hashmap_free(network->address_labels_by_section);
741 hashmap_free(network->prefixes_by_section);
742 hashmap_free(network->route_prefixes_by_section);
743 hashmap_free(network->rules_by_section);
744 ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
745 ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
746
747 if (network->manager &&
748 network->manager->duids_requesting_uuid)
749 set_remove(network->manager->duids_requesting_uuid, &network->duid);
750
751 free(network->name);
752
753 free(network->dhcp_server_timezone);
754
755 for (sd_dhcp_lease_server_type t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
756 free(network->dhcp_server_emit[t].addresses);
757
758 set_free_free(network->dnssec_negative_trust_anchors);
759
760 free(network->lldp_mud);
761
762 ordered_hashmap_free(network->dhcp_client_send_options);
763 ordered_hashmap_free(network->dhcp_client_send_vendor_options);
764 ordered_hashmap_free(network->dhcp_server_send_options);
765 ordered_hashmap_free(network->dhcp_server_send_vendor_options);
766 ordered_hashmap_free(network->ipv6_tokens);
767 ordered_hashmap_free(network->dhcp6_client_send_options);
768 ordered_hashmap_free(network->dhcp6_client_send_vendor_options);
769
770 return mfree(network);
771 }
772
773 DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
774
775 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
776 Network *network;
777
778 assert(manager);
779 assert(name);
780 assert(ret);
781
782 network = ordered_hashmap_get(manager->networks, name);
783 if (!network)
784 return -ENOENT;
785
786 *ret = network;
787
788 return 0;
789 }
790
791 int network_get(Manager *manager, unsigned short iftype, sd_device *device,
792 const char *ifname, char * const *alternative_names, const char *driver,
793 const struct ether_addr *mac, const struct ether_addr *permanent_mac,
794 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
795 Network **ret) {
796 Network *network;
797 Iterator i;
798
799 assert(manager);
800 assert(ret);
801
802 ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
803 if (net_match_config(network->match_mac, network->match_permanent_mac,
804 network->match_path, network->match_driver,
805 network->match_type, network->match_name, network->match_property,
806 network->match_wlan_iftype, network->match_ssid, network->match_bssid,
807 device, mac, permanent_mac, driver, iftype,
808 ifname, alternative_names, wlan_iftype, ssid, bssid)) {
809 if (network->match_name && device) {
810 const char *attr;
811 uint8_t name_assign_type = NET_NAME_UNKNOWN;
812
813 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
814 (void) safe_atou8(attr, &name_assign_type);
815
816 if (name_assign_type == NET_NAME_ENUM)
817 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
818 ifname, network->filename);
819 else
820 log_debug("%s: found matching network '%s'", ifname, network->filename);
821 } else
822 log_debug("%s: found matching network '%s'", ifname, network->filename);
823
824 *ret = network;
825 return 0;
826 }
827
828 *ret = NULL;
829
830 return -ENOENT;
831 }
832
833 int network_apply(Network *network, Link *link) {
834 assert(network);
835 assert(link);
836
837 link->network = network_ref(network);
838
839 if (network->n_dns > 0 ||
840 !strv_isempty(network->ntp) ||
841 !ordered_set_isempty(network->search_domains) ||
842 !ordered_set_isempty(network->route_domains))
843 link_dirty(link);
844
845 return 0;
846 }
847
848 bool network_has_static_ipv6_configurations(Network *network) {
849 Address *address;
850 Route *route;
851 FdbEntry *fdb;
852 Neighbor *neighbor;
853
854 assert(network);
855
856 LIST_FOREACH(addresses, address, network->static_addresses)
857 if (address->family == AF_INET6)
858 return true;
859
860 LIST_FOREACH(routes, route, network->static_routes)
861 if (route->family == AF_INET6)
862 return true;
863
864 LIST_FOREACH(static_fdb_entries, fdb, network->static_fdb_entries)
865 if (fdb->family == AF_INET6)
866 return true;
867
868 LIST_FOREACH(neighbors, neighbor, network->neighbors)
869 if (neighbor->family == AF_INET6)
870 return true;
871
872 if (!LIST_IS_EMPTY(network->address_labels))
873 return true;
874
875 if (!LIST_IS_EMPTY(network->static_prefixes))
876 return true;
877
878 return false;
879 }
880
881 int config_parse_stacked_netdev(const char *unit,
882 const char *filename,
883 unsigned line,
884 const char *section,
885 unsigned section_line,
886 const char *lvalue,
887 int ltype,
888 const char *rvalue,
889 void *data,
890 void *userdata) {
891 _cleanup_free_ char *name = NULL;
892 NetDevKind kind = ltype;
893 Hashmap **h = data;
894 int r;
895
896 assert(filename);
897 assert(lvalue);
898 assert(rvalue);
899 assert(data);
900 assert(IN_SET(kind,
901 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
902 NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
903 NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
904 NETDEV_KIND_XFRM));
905
906 if (!ifname_valid(rvalue)) {
907 log_syntax(unit, LOG_WARNING, filename, line, 0,
908 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
909 return 0;
910 }
911
912 name = strdup(rvalue);
913 if (!name)
914 return log_oom();
915
916 r = hashmap_ensure_allocated(h, &string_hash_ops);
917 if (r < 0)
918 return log_oom();
919
920 r = hashmap_put(*h, name, INT_TO_PTR(kind));
921 if (r < 0)
922 log_syntax(unit, LOG_WARNING, filename, line, r,
923 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
924 else if (r == 0)
925 log_syntax(unit, LOG_DEBUG, filename, line, r,
926 "NetDev '%s' specified twice, ignoring.", name);
927 else
928 name = NULL;
929
930 return 0;
931 }
932
933 int config_parse_domains(
934 const char *unit,
935 const char *filename,
936 unsigned line,
937 const char *section,
938 unsigned section_line,
939 const char *lvalue,
940 int ltype,
941 const char *rvalue,
942 void *data,
943 void *userdata) {
944
945 Network *n = data;
946 int r;
947
948 assert(n);
949 assert(lvalue);
950 assert(rvalue);
951
952 if (isempty(rvalue)) {
953 n->search_domains = ordered_set_free_free(n->search_domains);
954 n->route_domains = ordered_set_free_free(n->route_domains);
955 return 0;
956 }
957
958 for (const char *p = rvalue;;) {
959 _cleanup_free_ char *w = NULL, *normalized = NULL;
960 const char *domain;
961 bool is_route;
962
963 r = extract_first_word(&p, &w, NULL, 0);
964 if (r == -ENOMEM)
965 return log_oom();
966 if (r < 0) {
967 log_syntax(unit, LOG_WARNING, filename, line, r,
968 "Failed to extract search or route domain, ignoring: %s", rvalue);
969 return 0;
970 }
971 if (r == 0)
972 return 0;
973
974 is_route = w[0] == '~';
975 domain = is_route ? w + 1 : w;
976
977 if (dns_name_is_root(domain) || streq(domain, "*")) {
978 /* If the root domain appears as is, or the special token "*" is found, we'll
979 * consider this as routing domain, unconditionally. */
980 is_route = true;
981 domain = "."; /* make sure we don't allow empty strings, thus write the root
982 * domain as "." */
983 } else {
984 r = dns_name_normalize(domain, 0, &normalized);
985 if (r < 0) {
986 log_syntax(unit, LOG_WARNING, filename, line, r,
987 "'%s' is not a valid domain name, ignoring.", domain);
988 continue;
989 }
990
991 domain = normalized;
992
993 if (is_localhost(domain)) {
994 log_syntax(unit, LOG_WARNING, filename, line, 0,
995 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
996 domain);
997 continue;
998 }
999 }
1000
1001 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
1002 r = ordered_set_ensure_allocated(set, &string_hash_ops);
1003 if (r < 0)
1004 return log_oom();
1005
1006 r = ordered_set_put_strdup(*set, domain);
1007 if (r < 0)
1008 return log_oom();
1009 }
1010 }
1011
1012 int config_parse_ipv6token(
1013 const char* unit,
1014 const char *filename,
1015 unsigned line,
1016 const char *section,
1017 unsigned section_line,
1018 const char *lvalue,
1019 int ltype,
1020 const char *rvalue,
1021 void *data,
1022 void *userdata) {
1023
1024 union in_addr_union buffer;
1025 struct in6_addr *token = data;
1026 int r;
1027
1028 assert(filename);
1029 assert(lvalue);
1030 assert(rvalue);
1031 assert(token);
1032
1033 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
1034 if (r < 0) {
1035 log_syntax(unit, LOG_WARNING, filename, line, r,
1036 "Failed to parse IPv6 token, ignoring: %s", rvalue);
1037 return 0;
1038 }
1039
1040 if (in_addr_is_null(AF_INET6, &buffer)) {
1041 log_syntax(unit, LOG_WARNING, filename, line, 0,
1042 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
1043 return 0;
1044 }
1045
1046 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
1047 log_syntax(unit, LOG_WARNING, filename, line, 0,
1048 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
1049 return 0;
1050 }
1051
1052 *token = buffer.in6;
1053
1054 return 0;
1055 }
1056
1057 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1058 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
1059 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
1060 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
1061 };
1062
1063 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_privacy_extensions, IPv6PrivacyExtensions,
1064 IPV6_PRIVACY_EXTENSIONS_YES);
1065
1066 int config_parse_ipv6_privacy_extensions(
1067 const char* unit,
1068 const char *filename,
1069 unsigned line,
1070 const char *section,
1071 unsigned section_line,
1072 const char *lvalue,
1073 int ltype,
1074 const char *rvalue,
1075 void *data,
1076 void *userdata) {
1077
1078 IPv6PrivacyExtensions s, *ipv6_privacy_extensions = data;
1079
1080 assert(filename);
1081 assert(lvalue);
1082 assert(rvalue);
1083 assert(ipv6_privacy_extensions);
1084
1085 s = ipv6_privacy_extensions_from_string(rvalue);
1086 if (s < 0) {
1087 if (streq(rvalue, "kernel"))
1088 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1089 else {
1090 log_syntax(unit, LOG_WARNING, filename, line, 0,
1091 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1092 return 0;
1093 }
1094 }
1095
1096 *ipv6_privacy_extensions = s;
1097
1098 return 0;
1099 }
1100
1101 int config_parse_hostname(
1102 const char *unit,
1103 const char *filename,
1104 unsigned line,
1105 const char *section,
1106 unsigned section_line,
1107 const char *lvalue,
1108 int ltype,
1109 const char *rvalue,
1110 void *data,
1111 void *userdata) {
1112
1113 _cleanup_free_ char *hn = NULL;
1114 char **hostname = data;
1115 int r;
1116
1117 assert(filename);
1118 assert(lvalue);
1119 assert(rvalue);
1120
1121 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
1122 if (r < 0)
1123 return r;
1124
1125 if (!hostname_is_valid(hn, false)) {
1126 log_syntax(unit, LOG_WARNING, filename, line, 0,
1127 "Hostname is not valid, ignoring assignment: %s", rvalue);
1128 return 0;
1129 }
1130
1131 r = dns_name_is_valid(hn);
1132 if (r < 0) {
1133 log_syntax(unit, LOG_WARNING, filename, line, r,
1134 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
1135 return 0;
1136 }
1137 if (r == 0) {
1138 log_syntax(unit, LOG_WARNING, filename, line, 0,
1139 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
1140 return 0;
1141 }
1142
1143 return free_and_replace(*hostname, hn);
1144 }
1145
1146 int config_parse_timezone(
1147 const char *unit,
1148 const char *filename,
1149 unsigned line,
1150 const char *section,
1151 unsigned section_line,
1152 const char *lvalue,
1153 int ltype,
1154 const char *rvalue,
1155 void *data,
1156 void *userdata) {
1157
1158 _cleanup_free_ char *tz = NULL;
1159 char **datap = data;
1160 int r;
1161
1162 assert(filename);
1163 assert(lvalue);
1164 assert(rvalue);
1165
1166 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1167 if (r < 0)
1168 return r;
1169
1170 if (!timezone_is_valid(tz, LOG_WARNING)) {
1171 log_syntax(unit, LOG_WARNING, filename, line, 0,
1172 "Timezone is not valid, ignoring assignment: %s", rvalue);
1173 return 0;
1174 }
1175
1176 return free_and_replace(*datap, tz);
1177 }
1178
1179 int config_parse_dns(
1180 const char *unit,
1181 const char *filename,
1182 unsigned line,
1183 const char *section,
1184 unsigned section_line,
1185 const char *lvalue,
1186 int ltype,
1187 const char *rvalue,
1188 void *data,
1189 void *userdata) {
1190
1191 Network *n = userdata;
1192 int r;
1193
1194 assert(filename);
1195 assert(lvalue);
1196 assert(rvalue);
1197
1198 if (isempty(rvalue)) {
1199 for (unsigned i = 0; i < n->n_dns; i++)
1200 in_addr_full_free(n->dns[i]);
1201 n->dns = mfree(n->dns);
1202 n->n_dns = 0;
1203 return 0;
1204 }
1205
1206 for (const char *p = rvalue;;) {
1207 _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
1208 _cleanup_free_ char *w = NULL;
1209 struct in_addr_full **m;
1210
1211 r = extract_first_word(&p, &w, NULL, 0);
1212 if (r == -ENOMEM)
1213 return log_oom();
1214 if (r < 0) {
1215 log_syntax(unit, LOG_WARNING, filename, line, r,
1216 "Invalid syntax, ignoring: %s", rvalue);
1217 return 0;
1218 }
1219 if (r == 0)
1220 return 0;
1221
1222 r = in_addr_full_new_from_string(w, &dns);
1223 if (r < 0) {
1224 log_syntax(unit, LOG_WARNING, filename, line, r,
1225 "Failed to parse dns server address, ignoring: %s", w);
1226 continue;
1227 }
1228
1229 if (IN_SET(dns->port, 53, 853))
1230 dns->port = 0;
1231
1232 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
1233 if (!m)
1234 return log_oom();
1235
1236 m[n->n_dns++] = TAKE_PTR(dns);
1237 n->dns = m;
1238 }
1239 }
1240
1241 int config_parse_dnssec_negative_trust_anchors(
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 *n = data;
1254 int r;
1255
1256 assert(n);
1257 assert(lvalue);
1258 assert(rvalue);
1259
1260 if (isempty(rvalue)) {
1261 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1262 return 0;
1263 }
1264
1265 for (const char *p = rvalue;;) {
1266 _cleanup_free_ char *w = NULL;
1267
1268 r = extract_first_word(&p, &w, NULL, 0);
1269 if (r == -ENOMEM)
1270 return log_oom();
1271 if (r < 0) {
1272 log_syntax(unit, LOG_WARNING, filename, line, r,
1273 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1274 return 0;
1275 }
1276 if (r == 0)
1277 return 0;
1278
1279 r = dns_name_is_valid(w);
1280 if (r <= 0) {
1281 log_syntax(unit, LOG_WARNING, filename, line, r,
1282 "%s is not a valid domain name, ignoring.", w);
1283 continue;
1284 }
1285
1286 r = set_ensure_consume(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops, TAKE_PTR(w));
1287 if (r < 0)
1288 return log_oom();
1289 }
1290 }
1291
1292 int config_parse_ntp(
1293 const char *unit,
1294 const char *filename,
1295 unsigned line,
1296 const char *section,
1297 unsigned section_line,
1298 const char *lvalue,
1299 int ltype,
1300 const char *rvalue,
1301 void *data,
1302 void *userdata) {
1303
1304 char ***l = data;
1305 int r;
1306
1307 assert(l);
1308 assert(lvalue);
1309 assert(rvalue);
1310
1311 if (isempty(rvalue)) {
1312 *l = strv_free(*l);
1313 return 0;
1314 }
1315
1316 for (const char *p = rvalue;;) {
1317 _cleanup_free_ char *w = NULL;
1318
1319 r = extract_first_word(&p, &w, NULL, 0);
1320 if (r == -ENOMEM)
1321 return log_oom();
1322 if (r < 0) {
1323 log_syntax(unit, LOG_WARNING, filename, line, r,
1324 "Failed to extract NTP server name, ignoring: %s", rvalue);
1325 return 0;
1326 }
1327 if (r == 0)
1328 return 0;
1329
1330 r = dns_name_is_valid_or_address(w);
1331 if (r <= 0) {
1332 log_syntax(unit, LOG_WARNING, filename, line, r,
1333 "%s is not a valid domain name or IP address, ignoring.", w);
1334 continue;
1335 }
1336
1337 if (strv_length(*l) > MAX_NTP_SERVERS) {
1338 log_syntax(unit, LOG_WARNING, filename, line, 0,
1339 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1340 MAX_NTP_SERVERS, w);
1341 return 0;
1342 }
1343
1344 r = strv_consume(l, TAKE_PTR(w));
1345 if (r < 0)
1346 return log_oom();
1347 }
1348 }
1349
1350 int config_parse_required_for_online(
1351 const char *unit,
1352 const char *filename,
1353 unsigned line,
1354 const char *section,
1355 unsigned section_line,
1356 const char *lvalue,
1357 int ltype,
1358 const char *rvalue,
1359 void *data,
1360 void *userdata) {
1361
1362 Network *network = data;
1363 LinkOperationalStateRange range;
1364 bool required = true;
1365 int r;
1366
1367 if (isempty(rvalue)) {
1368 network->required_for_online = true;
1369 network->required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT;
1370 return 0;
1371 }
1372
1373 r = parse_operational_state_range(rvalue, &range);
1374 if (r < 0) {
1375 r = parse_boolean(rvalue);
1376 if (r < 0) {
1377 log_syntax(unit, LOG_WARNING, filename, line, r,
1378 "Failed to parse %s= setting, ignoring assignment: %s",
1379 lvalue, rvalue);
1380 return 0;
1381 }
1382
1383 required = r;
1384 range = LINK_OPERSTATE_RANGE_DEFAULT;
1385 }
1386
1387 network->required_for_online = required;
1388 network->required_operstate_for_online = range;
1389
1390 return 0;
1391 }
1392
1393 DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1394 "Failed to parse KeepConfiguration= setting");
1395
1396 static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1397 [KEEP_CONFIGURATION_NO] = "no",
1398 [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1399 [KEEP_CONFIGURATION_DHCP] = "dhcp",
1400 [KEEP_CONFIGURATION_STATIC] = "static",
1401 [KEEP_CONFIGURATION_YES] = "yes",
1402 };
1403
1404 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
1405
1406 static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX] = {
1407 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_EUI64] = "eui64",
1408 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_NONE] = "none",
1409 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY] = "stable-privacy",
1410 [IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM] = "random",
1411 };
1412
1413 DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode);
1414 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");