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