]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
efbbd58b9294d13b6456478e5faf10a2a52f0811
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <ctype.h>
4 #include <net/if.h>
5
6 #include "alloc-util.h"
7 #include "conf-files.h"
8 #include "conf-parser.h"
9 #include "dns-domain.h"
10 #include "fd-util.h"
11 #include "hostname-util.h"
12 #include "in-addr-util.h"
13 #include "missing_network.h"
14 #include "network-internal.h"
15 #include "networkd-manager.h"
16 #include "networkd-network.h"
17 #include "parse-util.h"
18 #include "set.h"
19 #include "socket-util.h"
20 #include "stat-util.h"
21 #include "string-table.h"
22 #include "string-util.h"
23 #include "strv.h"
24 #include "util.h"
25
26 /* Let's assume that anything above this number is a user misconfiguration. */
27 #define MAX_NTP_SERVERS 128
28
29 /* Set defaults following RFC7844 */
30 void network_apply_anonymize_if_set(Network *network) {
31 if (!network->dhcp_anonymize)
32 return;
33 /* RFC7844 3.7
34 SHOULD NOT send the Host Name option */
35 network->dhcp_send_hostname = false;
36 /* RFC7844 section 3.:
37 MAY contain the Client Identifier option
38 Section 3.5:
39 clients MUST use client identifiers based solely
40 on the link-layer address */
41 /* NOTE: Using MAC, as it does not reveal extra information,
42 * and some servers might not answer if this option is not sent */
43 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
44 /* RFC 7844 3.10:
45 SHOULD NOT use the Vendor Class Identifier option */
46 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
47 /* RFC7844 section 3.6.:
48 The client intending to protect its privacy SHOULD only request a
49 minimal number of options in the PRL and SHOULD also randomly shuffle
50 the ordering of option codes in the PRL. If this random ordering
51 cannot be implemented, the client MAY order the option codes in the
52 PRL by option code number (lowest to highest).
53 */
54 /* NOTE: dhcp_use_mtu is false by default,
55 * though it was not initiallized to any value in network_load_one.
56 * Maybe there should be another var called *send*?
57 * (to use the MTU sent by the server but to do not send
58 * the option in the PRL). */
59 network->dhcp_use_mtu = false;
60 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
61 * but this is needed to use them. */
62 network->dhcp_use_routes = true;
63 /* RFC7844 section 3.6.
64 * same comments as previous option */
65 network->dhcp_use_timezone = false;
66 }
67
68 static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
69 const char *kind_string;
70 NetDev *netdev;
71 int r;
72
73 /* For test-networkd-conf, the check must be earlier than the assertions. */
74 if (!name)
75 return 0;
76
77 assert(network);
78 assert(network->manager);
79 assert(network->filename);
80 assert(ret_netdev);
81
82 if (kind == _NETDEV_KIND_TUNNEL)
83 kind_string = "tunnel";
84 else {
85 kind_string = netdev_kind_to_string(kind);
86 if (!kind_string)
87 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
88 "%s: Invalid NetDev kind of %s, ignoring assignment.",
89 network->filename, name);
90 }
91
92 r = netdev_get(network->manager, name, &netdev);
93 if (r < 0)
94 return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
95 network->filename, name);
96
97 if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
98 IN_SET(netdev->kind,
99 NETDEV_KIND_IPIP,
100 NETDEV_KIND_SIT,
101 NETDEV_KIND_GRE,
102 NETDEV_KIND_GRETAP,
103 NETDEV_KIND_IP6GRE,
104 NETDEV_KIND_IP6GRETAP,
105 NETDEV_KIND_VTI,
106 NETDEV_KIND_VTI6,
107 NETDEV_KIND_IP6TNL)))
108 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
109 "%s: NetDev %s is not a %s, ignoring assignment",
110 network->filename, name, kind_string);
111
112 *ret_netdev = netdev_ref(netdev);
113 return 1;
114 }
115
116 static int network_resolve_stacked_netdevs(Network *network) {
117 void *name, *kind;
118 Iterator i;
119 int r;
120
121 assert(network);
122
123 HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
124 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
125
126 r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
127 if (r <= 0)
128 continue;
129
130 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
131 if (r < 0)
132 return log_oom();
133
134 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
135 if (r < 0)
136 return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
137 network->filename, (const char *) name);
138
139 netdev = NULL;
140 }
141
142 return 0;
143 }
144
145 static uint32_t network_get_stacked_netdevs_mtu(Network *network) {
146 uint32_t mtu = 0;
147 NetDev *dev;
148 Iterator i;
149
150 HASHMAP_FOREACH(dev, network->stacked_netdevs, i)
151 if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
152 /* See vlan_dev_change_mtu() in kernel.
153 * Note that the additional 4bytes may not be necessary for all devices. */
154 mtu = MAX(mtu, dev->mtu + 4);
155
156 else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
157 /* See macvlan_change_mtu() in kernel. */
158 mtu = dev->mtu;
159
160 return mtu;
161 }
162
163 int network_verify(Network *network) {
164 Address *address, *address_next;
165 Route *route, *route_next;
166 FdbEntry *fdb, *fdb_next;
167 Neighbor *neighbor, *neighbor_next;
168 AddressLabel *label, *label_next;
169 Prefix *prefix, *prefix_next;
170 RoutingPolicyRule *rule, *rule_next;
171 uint32_t mtu;
172
173 assert(network);
174 assert(network->filename);
175
176 /* skip out early if configuration does not match the environment */
177 if (!net_match_config(NULL, NULL, NULL, NULL, NULL,
178 network->match_host, network->match_virt, network->match_kernel_cmdline,
179 network->match_kernel_version, network->match_arch,
180 NULL, NULL, NULL, NULL, NULL))
181 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
182 "%s: Conditions in the file do not match the system environment, skipping.",
183 network->filename);
184
185 (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
186 (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
187 (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
188 (void) network_resolve_stacked_netdevs(network);
189
190 /* Free unnecessary entries. */
191 network->bond_name = mfree(network->bond_name);
192 network->bridge_name = mfree(network->bridge_name);
193 network->vrf_name = mfree(network->vrf_name);
194 network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
195
196 if (network->bond) {
197 /* Bonding slave does not support addressing. */
198 if (network->ipv6_accept_ra > 0) {
199 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
200 network->filename);
201 network->ipv6_accept_ra = 0;
202 }
203 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
204 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
205 network->filename);
206 network->link_local = ADDRESS_FAMILY_NO;
207 }
208 if (network->dhcp != ADDRESS_FAMILY_NO) {
209 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
210 network->filename);
211 network->dhcp = ADDRESS_FAMILY_NO;
212 }
213 if (network->dhcp_server) {
214 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
215 network->filename);
216 network->dhcp_server = false;
217 }
218 if (network->n_static_addresses > 0) {
219 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
220 network->filename);
221 while ((address = network->static_addresses))
222 address_free(address);
223 }
224 if (network->n_static_routes > 0) {
225 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
226 network->filename);
227 while ((route = network->static_routes))
228 route_free(route);
229 }
230 }
231
232 if (network->link_local < 0)
233 network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
234
235 if (network->ipv6_accept_ra < 0 && network->bridge)
236 network->ipv6_accept_ra = false;
237
238 /* IPMasquerade=yes implies IPForward=yes */
239 if (network->ip_masquerade)
240 network->ip_forward |= ADDRESS_FAMILY_IPV4;
241
242 network->mtu_is_set = network->mtu > 0;
243 mtu = network_get_stacked_netdevs_mtu(network);
244 if (network->mtu < mtu) {
245 if (network->mtu_is_set)
246 log_notice("%s: Bumping MTUBytes= from %"PRIu32" to %"PRIu32" because of stacked device",
247 network->filename, network->mtu, mtu);
248 network->mtu = mtu;
249 }
250
251 if (network->mtu_is_set && network->dhcp_use_mtu) {
252 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
253 "Disabling UseMTU=.", network->filename);
254 network->dhcp_use_mtu = false;
255 }
256
257 LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
258 if (address_section_verify(address) < 0)
259 address_free(address);
260
261 LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
262 if (route_section_verify(route, network) < 0)
263 route_free(route);
264
265 LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
266 if (section_is_invalid(fdb->section))
267 fdb_entry_free(fdb);
268
269 LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
270 if (section_is_invalid(neighbor->section))
271 neighbor_free(neighbor);
272
273 LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
274 if (section_is_invalid(label->section))
275 address_label_free(label);
276
277 LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
278 if (section_is_invalid(prefix->section))
279 prefix_free(prefix);
280
281 LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
282 if (section_is_invalid(rule->section))
283 routing_policy_rule_free(rule);
284
285 return 0;
286 }
287
288 int network_load_one(Manager *manager, const char *filename) {
289 _cleanup_free_ char *fname = NULL, *name = NULL;
290 _cleanup_(network_freep) Network *network = NULL;
291 _cleanup_fclose_ FILE *file = NULL;
292 const char *dropin_dirname;
293 char *d;
294 int r;
295
296 assert(manager);
297 assert(filename);
298
299 file = fopen(filename, "re");
300 if (!file) {
301 if (errno == ENOENT)
302 return 0;
303
304 return -errno;
305 }
306
307 if (null_or_empty_fd(fileno(file))) {
308 log_debug("Skipping empty file: %s", filename);
309 return 0;
310 }
311
312 fname = strdup(filename);
313 if (!fname)
314 return log_oom();
315
316 name = strdup(basename(filename));
317 if (!name)
318 return log_oom();
319
320 d = strrchr(name, '.');
321 if (!d)
322 return -EINVAL;
323
324 *d = '\0';
325
326 dropin_dirname = strjoina(name, ".network.d");
327
328 network = new(Network, 1);
329 if (!network)
330 return log_oom();
331
332 *network = (Network) {
333 .filename = TAKE_PTR(fname),
334 .name = TAKE_PTR(name),
335
336 .required_for_online = true,
337 .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
338 .dhcp = ADDRESS_FAMILY_NO,
339 .dhcp_use_ntp = true,
340 .dhcp_use_dns = true,
341 .dhcp_use_hostname = true,
342 .dhcp_use_routes = true,
343 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
344 .dhcp_send_hostname = true,
345 /* To enable/disable RFC7844 Anonymity Profiles */
346 .dhcp_anonymize = false,
347 .dhcp_route_metric = DHCP_ROUTE_METRIC,
348 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
349 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
350 .dhcp_route_table = RT_TABLE_MAIN,
351 .dhcp_route_table_set = false,
352 /* NOTE: from man: UseMTU=... Defaults to false*/
353 .dhcp_use_mtu = false,
354 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
355 .dhcp_use_timezone = false,
356 .rapid_commit = true,
357
358 .dhcp_server_emit_dns = true,
359 .dhcp_server_emit_ntp = true,
360 .dhcp_server_emit_router = true,
361 .dhcp_server_emit_timezone = true,
362
363 .router_emit_dns = true,
364 .router_emit_domains = true,
365
366 .use_bpdu = -1,
367 .hairpin = -1,
368 .fast_leave = -1,
369 .allow_port_to_be_root = -1,
370 .unicast_flood = -1,
371 .multicast_to_unicast = -1,
372 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
373
374 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
375
376 .dns_default_route = -1,
377 .llmnr = RESOLVE_SUPPORT_YES,
378 .mdns = RESOLVE_SUPPORT_NO,
379 .dnssec_mode = _DNSSEC_MODE_INVALID,
380 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
381
382 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
383 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
384
385 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
386 .ipv6_accept_ra = -1,
387 .ipv6_dad_transmits = -1,
388 .ipv6_hop_limit = -1,
389 .ipv6_proxy_ndp = -1,
390 .duid.type = _DUID_TYPE_INVALID,
391 .proxy_arp = -1,
392 .arp = -1,
393 .multicast = -1,
394 .allmulticast = -1,
395 .ipv6_accept_ra_use_dns = true,
396 .ipv6_accept_ra_use_autonomous_prefix = true,
397 .ipv6_accept_ra_use_onlink_prefix = true,
398 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
399 .ipv6_accept_ra_route_table_set = false,
400
401 .can_triple_sampling = -1,
402 };
403
404 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
405 "Match\0"
406 "Link\0"
407 "Network\0"
408 "Address\0"
409 "Neighbor\0"
410 "IPv6AddressLabel\0"
411 "RoutingPolicyRule\0"
412 "Route\0"
413 "DHCP\0"
414 "DHCPv4\0" /* compat */
415 "DHCPServer\0"
416 "IPv6AcceptRA\0"
417 "IPv6NDPProxyAddress\0"
418 "Bridge\0"
419 "BridgeFDB\0"
420 "BridgeVLAN\0"
421 "IPv6PrefixDelegation\0"
422 "IPv6Prefix\0"
423 "CAN\0",
424 config_item_perf_lookup, network_network_gperf_lookup,
425 CONFIG_PARSE_WARN, network);
426 if (r < 0)
427 return r;
428
429 network_apply_anonymize_if_set(network);
430
431 r = network_add_ipv4ll_route(network);
432 if (r < 0)
433 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
434
435 LIST_PREPEND(networks, manager->networks, network);
436 network->manager = manager;
437
438 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
439 if (r < 0)
440 return r;
441
442 r = hashmap_put(manager->networks_by_name, network->name, network);
443 if (r < 0)
444 return r;
445
446 if (network_verify(network) < 0)
447 return 0;
448
449 network = NULL;
450 return 0;
451 }
452
453 int network_load(Manager *manager) {
454 Network *network;
455 _cleanup_strv_free_ char **files = NULL;
456 char **f;
457 int r;
458
459 assert(manager);
460
461 while ((network = manager->networks))
462 network_free(network);
463
464 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
465 if (r < 0)
466 return log_error_errno(r, "Failed to enumerate network files: %m");
467
468 STRV_FOREACH_BACKWARDS(f, files) {
469 r = network_load_one(manager, *f);
470 if (r < 0)
471 return r;
472 }
473
474 return 0;
475 }
476
477 void network_free(Network *network) {
478 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
479 RoutingPolicyRule *rule;
480 FdbEntry *fdb_entry;
481 Neighbor *neighbor;
482 AddressLabel *label;
483 Prefix *prefix;
484 Address *address;
485 Route *route;
486
487 if (!network)
488 return;
489
490 free(network->filename);
491
492 set_free_free(network->match_mac);
493 strv_free(network->match_path);
494 strv_free(network->match_driver);
495 strv_free(network->match_type);
496 strv_free(network->match_name);
497
498 free(network->description);
499 free(network->dhcp_vendor_class_identifier);
500 strv_free(network->dhcp_user_class);
501 free(network->dhcp_hostname);
502
503 free(network->mac);
504
505 strv_free(network->ntp);
506 free(network->dns);
507 ordered_set_free_free(network->search_domains);
508 ordered_set_free_free(network->route_domains);
509 strv_free(network->bind_carrier);
510
511 ordered_set_free_free(network->router_search_domains);
512 free(network->router_dns);
513
514 free(network->bridge_name);
515 free(network->bond_name);
516 free(network->vrf_name);
517 hashmap_free_free_key(network->stacked_netdev_names);
518 netdev_unref(network->bridge);
519 netdev_unref(network->bond);
520 netdev_unref(network->vrf);
521 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
522
523 while ((route = network->static_routes))
524 route_free(route);
525
526 while ((address = network->static_addresses))
527 address_free(address);
528
529 while ((fdb_entry = network->static_fdb_entries))
530 fdb_entry_free(fdb_entry);
531
532 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
533 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
534
535 while ((neighbor = network->neighbors))
536 neighbor_free(neighbor);
537
538 while ((label = network->address_labels))
539 address_label_free(label);
540
541 while ((prefix = network->static_prefixes))
542 prefix_free(prefix);
543
544 while ((rule = network->rules))
545 routing_policy_rule_free(rule);
546
547 hashmap_free(network->addresses_by_section);
548 hashmap_free(network->routes_by_section);
549 hashmap_free(network->fdb_entries_by_section);
550 hashmap_free(network->neighbors_by_section);
551 hashmap_free(network->address_labels_by_section);
552 hashmap_free(network->prefixes_by_section);
553 hashmap_free(network->rules_by_section);
554
555 if (network->manager) {
556 if (network->manager->networks)
557 LIST_REMOVE(networks, network->manager->networks, network);
558
559 if (network->manager->networks_by_name && network->name)
560 hashmap_remove(network->manager->networks_by_name, network->name);
561
562 if (network->manager->duids_requesting_uuid)
563 set_remove(network->manager->duids_requesting_uuid, &network->duid);
564 }
565
566 free(network->name);
567
568 condition_free_list(network->match_host);
569 condition_free_list(network->match_virt);
570 condition_free_list(network->match_kernel_cmdline);
571 condition_free_list(network->match_kernel_version);
572 condition_free_list(network->match_arch);
573
574 free(network->dhcp_server_timezone);
575 free(network->dhcp_server_dns);
576 free(network->dhcp_server_ntp);
577
578 set_free_free(network->dnssec_negative_trust_anchors);
579
580 free(network);
581 }
582
583 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
584 Network *network;
585
586 assert(manager);
587 assert(name);
588 assert(ret);
589
590 network = hashmap_get(manager->networks_by_name, name);
591 if (!network)
592 return -ENOENT;
593
594 *ret = network;
595
596 return 0;
597 }
598
599 int network_get(Manager *manager, sd_device *device,
600 const char *ifname, const struct ether_addr *address,
601 Network **ret) {
602 const char *path = NULL, *driver = NULL, *devtype = NULL;
603 Network *network;
604
605 assert(manager);
606 assert(ret);
607
608 if (device) {
609 (void) sd_device_get_property_value(device, "ID_PATH", &path);
610
611 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
612
613 (void) sd_device_get_devtype(device, &devtype);
614 }
615
616 LIST_FOREACH(networks, network, manager->networks) {
617 if (net_match_config(network->match_mac, network->match_path,
618 network->match_driver, network->match_type,
619 network->match_name, network->match_host,
620 network->match_virt, network->match_kernel_cmdline,
621 network->match_kernel_version, network->match_arch,
622 address, path, driver, devtype, ifname)) {
623 if (network->match_name && device) {
624 const char *attr;
625 uint8_t name_assign_type = NET_NAME_UNKNOWN;
626
627 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
628 (void) safe_atou8(attr, &name_assign_type);
629
630 if (name_assign_type == NET_NAME_ENUM)
631 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
632 ifname, network->filename);
633 else
634 log_debug("%s: found matching network '%s'", ifname, network->filename);
635 } else
636 log_debug("%s: found matching network '%s'", ifname, network->filename);
637
638 *ret = network;
639 return 0;
640 }
641 }
642
643 *ret = NULL;
644
645 return -ENOENT;
646 }
647
648 int network_apply(Network *network, Link *link) {
649 assert(network);
650 assert(link);
651
652 link->network = network;
653
654 if (network->n_dns > 0 ||
655 !strv_isempty(network->ntp) ||
656 !ordered_set_isempty(network->search_domains) ||
657 !ordered_set_isempty(network->route_domains))
658 link_dirty(link);
659
660 return 0;
661 }
662
663 bool network_has_static_ipv6_addresses(Network *network) {
664 Address *address;
665
666 assert(network);
667
668 LIST_FOREACH(addresses, address, network->static_addresses) {
669 if (address->family == AF_INET6)
670 return true;
671 }
672
673 return false;
674 }
675
676 int config_parse_stacked_netdev(const char *unit,
677 const char *filename,
678 unsigned line,
679 const char *section,
680 unsigned section_line,
681 const char *lvalue,
682 int ltype,
683 const char *rvalue,
684 void *data,
685 void *userdata) {
686 _cleanup_free_ char *name = NULL;
687 NetDevKind kind = ltype;
688 Hashmap **h = data;
689 int r;
690
691 assert(filename);
692 assert(lvalue);
693 assert(rvalue);
694 assert(data);
695 assert(IN_SET(kind,
696 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
697 NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, _NETDEV_KIND_TUNNEL));
698
699 if (!ifname_valid(rvalue)) {
700 log_syntax(unit, LOG_ERR, filename, line, 0,
701 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
702 return 0;
703 }
704
705 name = strdup(rvalue);
706 if (!name)
707 return log_oom();
708
709 r = hashmap_ensure_allocated(h, &string_hash_ops);
710 if (r < 0)
711 return log_oom();
712
713 r = hashmap_put(*h, name, INT_TO_PTR(kind));
714 if (r < 0)
715 log_syntax(unit, LOG_ERR, filename, line, r,
716 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
717 else if (r == 0)
718 log_syntax(unit, LOG_DEBUG, filename, line, r,
719 "NetDev '%s' specified twice, ignoring.", name);
720 else
721 name = NULL;
722
723 return 0;
724 }
725
726 int config_parse_domains(
727 const char *unit,
728 const char *filename,
729 unsigned line,
730 const char *section,
731 unsigned section_line,
732 const char *lvalue,
733 int ltype,
734 const char *rvalue,
735 void *data,
736 void *userdata) {
737
738 const char *p;
739 Network *n = data;
740 int r;
741
742 assert(n);
743 assert(lvalue);
744 assert(rvalue);
745
746 if (isempty(rvalue)) {
747 n->search_domains = ordered_set_free_free(n->search_domains);
748 n->route_domains = ordered_set_free_free(n->route_domains);
749 return 0;
750 }
751
752 p = rvalue;
753 for (;;) {
754 _cleanup_free_ char *w = NULL, *normalized = NULL;
755 const char *domain;
756 bool is_route;
757
758 r = extract_first_word(&p, &w, NULL, 0);
759 if (r < 0) {
760 log_syntax(unit, LOG_ERR, filename, line, r,
761 "Failed to extract search or route domain, ignoring: %s", rvalue);
762 break;
763 }
764 if (r == 0)
765 break;
766
767 is_route = w[0] == '~';
768 domain = is_route ? w + 1 : w;
769
770 if (dns_name_is_root(domain) || streq(domain, "*")) {
771 /* If the root domain appears as is, or the special token "*" is found, we'll
772 * consider this as routing domain, unconditionally. */
773 is_route = true;
774 domain = "."; /* make sure we don't allow empty strings, thus write the root
775 * domain as "." */
776 } else {
777 r = dns_name_normalize(domain, 0, &normalized);
778 if (r < 0) {
779 log_syntax(unit, LOG_ERR, filename, line, r,
780 "'%s' is not a valid domain name, ignoring.", domain);
781 continue;
782 }
783
784 domain = normalized;
785
786 if (is_localhost(domain)) {
787 log_syntax(unit, LOG_ERR, filename, line, 0,
788 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
789 domain);
790 continue;
791 }
792 }
793
794 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
795 r = ordered_set_ensure_allocated(set, &string_hash_ops);
796 if (r < 0)
797 return r;
798
799 r = ordered_set_put_strdup(*set, domain);
800 if (r < 0)
801 return log_oom();
802 }
803
804 return 0;
805 }
806
807 int config_parse_ipv4ll(
808 const char* unit,
809 const char *filename,
810 unsigned line,
811 const char *section,
812 unsigned section_line,
813 const char *lvalue,
814 int ltype,
815 const char *rvalue,
816 void *data,
817 void *userdata) {
818
819 AddressFamilyBoolean *link_local = data;
820
821 assert(filename);
822 assert(lvalue);
823 assert(rvalue);
824 assert(data);
825
826 /* Note that this is mostly like
827 * config_parse_address_family_boolean(), except that it
828 * applies only to IPv4 */
829
830 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
831
832 return 0;
833 }
834
835 int config_parse_dhcp(
836 const char* unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846
847 AddressFamilyBoolean *dhcp = data, s;
848
849 assert(filename);
850 assert(lvalue);
851 assert(rvalue);
852 assert(data);
853
854 /* Note that this is mostly like
855 * config_parse_address_family_boolean(), except that it
856 * understands some old names for the enum values */
857
858 s = address_family_boolean_from_string(rvalue);
859 if (s < 0) {
860
861 /* Previously, we had a slightly different enum here,
862 * support its values for compatbility. */
863
864 if (streq(rvalue, "none"))
865 s = ADDRESS_FAMILY_NO;
866 else if (streq(rvalue, "v4"))
867 s = ADDRESS_FAMILY_IPV4;
868 else if (streq(rvalue, "v6"))
869 s = ADDRESS_FAMILY_IPV6;
870 else if (streq(rvalue, "both"))
871 s = ADDRESS_FAMILY_YES;
872 else {
873 log_syntax(unit, LOG_ERR, filename, line, 0,
874 "Failed to parse DHCP option, ignoring: %s", rvalue);
875 return 0;
876 }
877
878 log_syntax(unit, LOG_WARNING, filename, line, 0,
879 "DHCP=%s is deprecated, please use DHCP=%s instead.",
880 rvalue, address_family_boolean_to_string(s));
881 }
882
883 *dhcp = s;
884 return 0;
885 }
886
887 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
888 [DHCP_CLIENT_ID_MAC] = "mac",
889 [DHCP_CLIENT_ID_DUID] = "duid",
890 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
891 };
892
893 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
894 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
895 "Failed to parse client identifier type");
896
897 int config_parse_ipv6token(
898 const char* unit,
899 const char *filename,
900 unsigned line,
901 const char *section,
902 unsigned section_line,
903 const char *lvalue,
904 int ltype,
905 const char *rvalue,
906 void *data,
907 void *userdata) {
908
909 union in_addr_union buffer;
910 struct in6_addr *token = data;
911 int r;
912
913 assert(filename);
914 assert(lvalue);
915 assert(rvalue);
916 assert(token);
917
918 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
919 if (r < 0) {
920 log_syntax(unit, LOG_ERR, filename, line, r,
921 "Failed to parse IPv6 token, ignoring: %s", rvalue);
922 return 0;
923 }
924
925 if (in_addr_is_null(AF_INET6, &buffer)) {
926 log_syntax(unit, LOG_ERR, filename, line, 0,
927 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
928 return 0;
929 }
930
931 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
932 log_syntax(unit, LOG_ERR, filename, line, 0,
933 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
934 return 0;
935 }
936
937 *token = buffer.in6;
938
939 return 0;
940 }
941
942 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
943 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
944 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
945 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
946 };
947
948 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
949
950 int config_parse_ipv6_privacy_extensions(
951 const char* unit,
952 const char *filename,
953 unsigned line,
954 const char *section,
955 unsigned section_line,
956 const char *lvalue,
957 int ltype,
958 const char *rvalue,
959 void *data,
960 void *userdata) {
961
962 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
963 int k;
964
965 assert(filename);
966 assert(lvalue);
967 assert(rvalue);
968 assert(ipv6_privacy_extensions);
969
970 /* Our enum shall be a superset of booleans, hence first try
971 * to parse as boolean, and then as enum */
972
973 k = parse_boolean(rvalue);
974 if (k > 0)
975 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
976 else if (k == 0)
977 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
978 else {
979 IPv6PrivacyExtensions s;
980
981 s = ipv6_privacy_extensions_from_string(rvalue);
982 if (s < 0) {
983
984 if (streq(rvalue, "kernel"))
985 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
986 else {
987 log_syntax(unit, LOG_ERR, filename, line, 0,
988 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
989 return 0;
990 }
991 }
992
993 *ipv6_privacy_extensions = s;
994 }
995
996 return 0;
997 }
998
999 int config_parse_hostname(
1000 const char *unit,
1001 const char *filename,
1002 unsigned line,
1003 const char *section,
1004 unsigned section_line,
1005 const char *lvalue,
1006 int ltype,
1007 const char *rvalue,
1008 void *data,
1009 void *userdata) {
1010
1011 _cleanup_free_ char *hn = NULL;
1012 char **hostname = data;
1013 int r;
1014
1015 assert(filename);
1016 assert(lvalue);
1017 assert(rvalue);
1018
1019 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
1020 if (r < 0)
1021 return r;
1022
1023 if (!hostname_is_valid(hn, false)) {
1024 log_syntax(unit, LOG_ERR, filename, line, 0,
1025 "Hostname is not valid, ignoring assignment: %s", rvalue);
1026 return 0;
1027 }
1028
1029 r = dns_name_is_valid(hn);
1030 if (r < 0) {
1031 log_syntax(unit, LOG_ERR, filename, line, r,
1032 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
1033 return 0;
1034 }
1035 if (r == 0) {
1036 log_syntax(unit, LOG_ERR, filename, line, 0,
1037 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
1038 return 0;
1039 }
1040
1041 return free_and_replace(*hostname, hn);
1042 }
1043
1044 int config_parse_timezone(
1045 const char *unit,
1046 const char *filename,
1047 unsigned line,
1048 const char *section,
1049 unsigned section_line,
1050 const char *lvalue,
1051 int ltype,
1052 const char *rvalue,
1053 void *data,
1054 void *userdata) {
1055
1056 _cleanup_free_ char *tz = NULL;
1057 char **datap = data;
1058 int r;
1059
1060 assert(filename);
1061 assert(lvalue);
1062 assert(rvalue);
1063
1064 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1065 if (r < 0)
1066 return r;
1067
1068 if (!timezone_is_valid(tz, LOG_ERR)) {
1069 log_syntax(unit, LOG_ERR, filename, line, 0,
1070 "Timezone is not valid, ignoring assignment: %s", rvalue);
1071 return 0;
1072 }
1073
1074 return free_and_replace(*datap, tz);
1075 }
1076
1077 int config_parse_dhcp_server_dns(
1078 const char *unit,
1079 const char *filename,
1080 unsigned line,
1081 const char *section,
1082 unsigned section_line,
1083 const char *lvalue,
1084 int ltype,
1085 const char *rvalue,
1086 void *data,
1087 void *userdata) {
1088
1089 Network *n = data;
1090 const char *p = rvalue;
1091 int r;
1092
1093 assert(filename);
1094 assert(lvalue);
1095 assert(rvalue);
1096
1097 for (;;) {
1098 _cleanup_free_ char *w = NULL;
1099 struct in_addr a, *m;
1100
1101 r = extract_first_word(&p, &w, NULL, 0);
1102 if (r == -ENOMEM)
1103 return log_oom();
1104 if (r < 0) {
1105 log_syntax(unit, LOG_ERR, filename, line, r,
1106 "Failed to extract word, ignoring: %s", rvalue);
1107 return 0;
1108 }
1109 if (r == 0)
1110 break;
1111
1112 if (inet_pton(AF_INET, w, &a) <= 0) {
1113 log_syntax(unit, LOG_ERR, filename, line, 0,
1114 "Failed to parse DNS server address, ignoring: %s", w);
1115 continue;
1116 }
1117
1118 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1119 if (!m)
1120 return log_oom();
1121
1122 m[n->n_dhcp_server_dns++] = a;
1123 n->dhcp_server_dns = m;
1124 }
1125
1126 return 0;
1127 }
1128
1129 int config_parse_radv_dns(
1130 const char *unit,
1131 const char *filename,
1132 unsigned line,
1133 const char *section,
1134 unsigned section_line,
1135 const char *lvalue,
1136 int ltype,
1137 const char *rvalue,
1138 void *data,
1139 void *userdata) {
1140
1141 Network *n = data;
1142 const char *p = rvalue;
1143 int r;
1144
1145 assert(filename);
1146 assert(lvalue);
1147 assert(rvalue);
1148
1149 for (;;) {
1150 _cleanup_free_ char *w = NULL;
1151 union in_addr_union a;
1152
1153 r = extract_first_word(&p, &w, NULL, 0);
1154 if (r == -ENOMEM)
1155 return log_oom();
1156 if (r < 0) {
1157 log_syntax(unit, LOG_ERR, filename, line, r,
1158 "Failed to extract word, ignoring: %s", rvalue);
1159 return 0;
1160 }
1161 if (r == 0)
1162 break;
1163
1164 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1165 struct in6_addr *m;
1166
1167 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1168 if (!m)
1169 return log_oom();
1170
1171 m[n->n_router_dns++] = a.in6;
1172 n->router_dns = m;
1173
1174 } else
1175 log_syntax(unit, LOG_ERR, filename, line, 0,
1176 "Failed to parse DNS server address, ignoring: %s", w);
1177 }
1178
1179 return 0;
1180 }
1181
1182 int config_parse_radv_search_domains(
1183 const char *unit,
1184 const char *filename,
1185 unsigned line,
1186 const char *section,
1187 unsigned section_line,
1188 const char *lvalue,
1189 int ltype,
1190 const char *rvalue,
1191 void *data,
1192 void *userdata) {
1193
1194 Network *n = data;
1195 const char *p = rvalue;
1196 int r;
1197
1198 assert(filename);
1199 assert(lvalue);
1200 assert(rvalue);
1201
1202 for (;;) {
1203 _cleanup_free_ char *w = NULL, *idna = NULL;
1204
1205 r = extract_first_word(&p, &w, NULL, 0);
1206 if (r == -ENOMEM)
1207 return log_oom();
1208 if (r < 0) {
1209 log_syntax(unit, LOG_ERR, filename, line, r,
1210 "Failed to extract word, ignoring: %s", rvalue);
1211 return 0;
1212 }
1213 if (r == 0)
1214 break;
1215
1216 r = dns_name_apply_idna(w, &idna);
1217 if (r < 0) {
1218 log_syntax(unit, LOG_ERR, filename, line, r,
1219 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1220 continue;
1221 } else if (r == 0)
1222 /* transfer ownership to simplify subsequent operations */
1223 idna = TAKE_PTR(w);
1224
1225 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1226 if (r < 0)
1227 return r;
1228
1229 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1230 if (r < 0)
1231 return r;
1232 }
1233
1234 return 0;
1235 }
1236
1237 int config_parse_dhcp_server_ntp(
1238 const char *unit,
1239 const char *filename,
1240 unsigned line,
1241 const char *section,
1242 unsigned section_line,
1243 const char *lvalue,
1244 int ltype,
1245 const char *rvalue,
1246 void *data,
1247 void *userdata) {
1248
1249 Network *n = data;
1250 const char *p = rvalue;
1251 int r;
1252
1253 assert(filename);
1254 assert(lvalue);
1255 assert(rvalue);
1256
1257 for (;;) {
1258 _cleanup_free_ char *w = NULL;
1259 struct in_addr a, *m;
1260
1261 r = extract_first_word(&p, &w, NULL, 0);
1262 if (r == -ENOMEM)
1263 return log_oom();
1264 if (r < 0) {
1265 log_syntax(unit, LOG_ERR, filename, line, r,
1266 "Failed to extract word, ignoring: %s", rvalue);
1267 return 0;
1268 }
1269 if (r == 0)
1270 return 0;
1271
1272 if (inet_pton(AF_INET, w, &a) <= 0) {
1273 log_syntax(unit, LOG_ERR, filename, line, 0,
1274 "Failed to parse NTP server address, ignoring: %s", w);
1275 continue;
1276 }
1277
1278 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1279 if (!m)
1280 return log_oom();
1281
1282 m[n->n_dhcp_server_ntp++] = a;
1283 n->dhcp_server_ntp = m;
1284 }
1285 }
1286
1287 int config_parse_dns(
1288 const char *unit,
1289 const char *filename,
1290 unsigned line,
1291 const char *section,
1292 unsigned section_line,
1293 const char *lvalue,
1294 int ltype,
1295 const char *rvalue,
1296 void *data,
1297 void *userdata) {
1298
1299 Network *n = userdata;
1300 int r;
1301
1302 assert(filename);
1303 assert(lvalue);
1304 assert(rvalue);
1305
1306 for (;;) {
1307 _cleanup_free_ char *w = NULL;
1308 union in_addr_union a;
1309 struct in_addr_data *m;
1310 int family;
1311
1312 r = extract_first_word(&rvalue, &w, NULL, 0);
1313 if (r == -ENOMEM)
1314 return log_oom();
1315 if (r < 0) {
1316 log_syntax(unit, LOG_ERR, filename, line, r,
1317 "Invalid syntax, ignoring: %s", rvalue);
1318 break;
1319 }
1320 if (r == 0)
1321 break;
1322
1323 r = in_addr_from_string_auto(w, &family, &a);
1324 if (r < 0) {
1325 log_syntax(unit, LOG_ERR, filename, line, r,
1326 "Failed to parse dns server address, ignoring: %s", w);
1327 continue;
1328 }
1329
1330 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1331 if (!m)
1332 return log_oom();
1333
1334 m[n->n_dns++] = (struct in_addr_data) {
1335 .family = family,
1336 .address = a,
1337 };
1338
1339 n->dns = m;
1340 }
1341
1342 return 0;
1343 }
1344
1345 int config_parse_dnssec_negative_trust_anchors(
1346 const char *unit,
1347 const char *filename,
1348 unsigned line,
1349 const char *section,
1350 unsigned section_line,
1351 const char *lvalue,
1352 int ltype,
1353 const char *rvalue,
1354 void *data,
1355 void *userdata) {
1356
1357 const char *p = rvalue;
1358 Network *n = data;
1359 int r;
1360
1361 assert(n);
1362 assert(lvalue);
1363 assert(rvalue);
1364
1365 if (isempty(rvalue)) {
1366 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1367 return 0;
1368 }
1369
1370 for (;;) {
1371 _cleanup_free_ char *w = NULL;
1372
1373 r = extract_first_word(&p, &w, NULL, 0);
1374 if (r < 0) {
1375 log_syntax(unit, LOG_ERR, filename, line, r,
1376 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1377 break;
1378 }
1379 if (r == 0)
1380 break;
1381
1382 r = dns_name_is_valid(w);
1383 if (r <= 0) {
1384 log_syntax(unit, LOG_ERR, filename, line, r,
1385 "%s is not a valid domain name, ignoring.", w);
1386 continue;
1387 }
1388
1389 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1390 if (r < 0)
1391 return log_oom();
1392
1393 r = set_put(n->dnssec_negative_trust_anchors, w);
1394 if (r < 0)
1395 return log_oom();
1396 if (r > 0)
1397 w = NULL;
1398 }
1399
1400 return 0;
1401 }
1402
1403 int config_parse_ntp(
1404 const char *unit,
1405 const char *filename,
1406 unsigned line,
1407 const char *section,
1408 unsigned section_line,
1409 const char *lvalue,
1410 int ltype,
1411 const char *rvalue,
1412 void *data,
1413 void *userdata) {
1414
1415 char ***l = data;
1416 int r;
1417
1418 assert(l);
1419 assert(lvalue);
1420 assert(rvalue);
1421
1422 if (isempty(rvalue)) {
1423 *l = strv_free(*l);
1424 return 0;
1425 }
1426
1427 for (;;) {
1428 _cleanup_free_ char *w = NULL;
1429
1430 r = extract_first_word(&rvalue, &w, NULL, 0);
1431 if (r == -ENOMEM)
1432 return log_oom();
1433 if (r < 0) {
1434 log_syntax(unit, LOG_ERR, filename, line, r,
1435 "Failed to extract NTP server name, ignoring: %s", rvalue);
1436 break;
1437 }
1438 if (r == 0)
1439 break;
1440
1441 r = dns_name_is_valid_or_address(w);
1442 if (r <= 0) {
1443 log_syntax(unit, LOG_ERR, filename, line, r,
1444 "%s is not a valid domain name or IP address, ignoring.", w);
1445 continue;
1446 }
1447
1448 if (strv_length(*l) > MAX_NTP_SERVERS) {
1449 log_syntax(unit, LOG_WARNING, filename, line, 0,
1450 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1451 MAX_NTP_SERVERS, w);
1452 break;
1453 }
1454
1455 r = strv_consume(l, TAKE_PTR(w));
1456 if (r < 0)
1457 return log_oom();
1458 }
1459
1460 return 0;
1461 }
1462
1463 int config_parse_dhcp_user_class(
1464 const char *unit,
1465 const char *filename,
1466 unsigned line,
1467 const char *section,
1468 unsigned section_line,
1469 const char *lvalue,
1470 int ltype,
1471 const char *rvalue,
1472 void *data,
1473 void *userdata) {
1474
1475 char ***l = data;
1476 int r;
1477
1478 assert(l);
1479 assert(lvalue);
1480 assert(rvalue);
1481
1482 if (isempty(rvalue)) {
1483 *l = strv_free(*l);
1484 return 0;
1485 }
1486
1487 for (;;) {
1488 _cleanup_free_ char *w = NULL;
1489
1490 r = extract_first_word(&rvalue, &w, NULL, 0);
1491 if (r == -ENOMEM)
1492 return log_oom();
1493 if (r < 0) {
1494 log_syntax(unit, LOG_ERR, filename, line, r,
1495 "Failed to split user classes option, ignoring: %s", rvalue);
1496 break;
1497 }
1498 if (r == 0)
1499 break;
1500
1501 if (strlen(w) > 255) {
1502 log_syntax(unit, LOG_ERR, filename, line, 0,
1503 "%s length is not in the range 1-255, ignoring.", w);
1504 continue;
1505 }
1506
1507 r = strv_push(l, w);
1508 if (r < 0)
1509 return log_oom();
1510
1511 w = NULL;
1512 }
1513
1514 return 0;
1515 }
1516
1517 int config_parse_section_route_table(
1518 const char *unit,
1519 const char *filename,
1520 unsigned line,
1521 const char *section,
1522 unsigned section_line,
1523 const char *lvalue,
1524 int ltype,
1525 const char *rvalue,
1526 void *data,
1527 void *userdata) {
1528
1529 Network *network = data;
1530 uint32_t rt;
1531 int r;
1532
1533 assert(filename);
1534 assert(lvalue);
1535 assert(rvalue);
1536 assert(data);
1537
1538 r = safe_atou32(rvalue, &rt);
1539 if (r < 0) {
1540 log_syntax(unit, LOG_ERR, filename, line, r,
1541 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
1542 return 0;
1543 }
1544
1545 if (streq_ptr(section, "DHCP")) {
1546 network->dhcp_route_table = rt;
1547 network->dhcp_route_table_set = true;
1548 } else { /* section is IPv6AcceptRA */
1549 network->ipv6_accept_ra_route_table = rt;
1550 network->ipv6_accept_ra_route_table_set = true;
1551 }
1552
1553 return 0;
1554 }
1555
1556 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1557 "Failed to parse DHCP use domains setting");
1558
1559 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1560 [DHCP_USE_DOMAINS_NO] = "no",
1561 [DHCP_USE_DOMAINS_ROUTE] = "route",
1562 [DHCP_USE_DOMAINS_YES] = "yes",
1563 };
1564
1565 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1566
1567 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1568
1569 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1570 [LLDP_MODE_NO] = "no",
1571 [LLDP_MODE_YES] = "yes",
1572 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1573 };
1574
1575 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
1576
1577 int config_parse_iaid(const char *unit,
1578 const char *filename,
1579 unsigned line,
1580 const char *section,
1581 unsigned section_line,
1582 const char *lvalue,
1583 int ltype,
1584 const char *rvalue,
1585 void *data,
1586 void *userdata) {
1587 Network *network = data;
1588 uint32_t iaid;
1589 int r;
1590
1591 assert(filename);
1592 assert(lvalue);
1593 assert(rvalue);
1594 assert(network);
1595
1596 r = safe_atou32(rvalue, &iaid);
1597 if (r < 0) {
1598 log_syntax(unit, LOG_ERR, filename, line, r,
1599 "Unable to read IAID, ignoring assignment: %s", rvalue);
1600 return 0;
1601 }
1602
1603 network->iaid = iaid;
1604 network->iaid_set = true;
1605
1606 return 0;
1607 }
1608
1609 int config_parse_required_for_online(
1610 const char *unit,
1611 const char *filename,
1612 unsigned line,
1613 const char *section,
1614 unsigned section_line,
1615 const char *lvalue,
1616 int ltype,
1617 const char *rvalue,
1618 void *data,
1619 void *userdata) {
1620
1621 Network *network = data;
1622 LinkOperationalState s;
1623 bool required = true;
1624 int r;
1625
1626 if (isempty(rvalue)) {
1627 network->required_for_online = true;
1628 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1629 return 0;
1630 }
1631
1632 s = link_operstate_from_string(rvalue);
1633 if (s < 0) {
1634 r = parse_boolean(rvalue);
1635 if (r < 0) {
1636 log_syntax(unit, LOG_ERR, filename, line, r,
1637 "Failed to parse %s= setting, ignoring assignment: %s",
1638 lvalue, rvalue);
1639 return 0;
1640 }
1641
1642 required = r;
1643 s = LINK_OPERSTATE_DEGRADED;
1644 }
1645
1646 network->required_for_online = required;
1647 network->required_operstate_for_online = s;
1648
1649 return 0;
1650 }