]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
networkd: Add bridge port capabilities
[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_flood = -1,
372 .multicast_to_unicast = -1,
373 .neighbor_suppression = -1,
374 .learning = -1,
375 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
376
377 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
378
379 .dns_default_route = -1,
380 .llmnr = RESOLVE_SUPPORT_YES,
381 .mdns = RESOLVE_SUPPORT_NO,
382 .dnssec_mode = _DNSSEC_MODE_INVALID,
383 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
384
385 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
386 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
387
388 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
389 .ipv6_accept_ra = -1,
390 .ipv6_dad_transmits = -1,
391 .ipv6_hop_limit = -1,
392 .ipv6_proxy_ndp = -1,
393 .duid.type = _DUID_TYPE_INVALID,
394 .proxy_arp = -1,
395 .arp = -1,
396 .multicast = -1,
397 .allmulticast = -1,
398 .ipv6_accept_ra_use_dns = true,
399 .ipv6_accept_ra_use_autonomous_prefix = true,
400 .ipv6_accept_ra_use_onlink_prefix = true,
401 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
402 .ipv6_accept_ra_route_table_set = false,
403
404 .can_triple_sampling = -1,
405 };
406
407 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
408 "Match\0"
409 "Link\0"
410 "Network\0"
411 "Address\0"
412 "Neighbor\0"
413 "IPv6AddressLabel\0"
414 "RoutingPolicyRule\0"
415 "Route\0"
416 "DHCP\0"
417 "DHCPv4\0" /* compat */
418 "DHCPServer\0"
419 "IPv6AcceptRA\0"
420 "IPv6NDPProxyAddress\0"
421 "Bridge\0"
422 "BridgeFDB\0"
423 "BridgeVLAN\0"
424 "IPv6PrefixDelegation\0"
425 "IPv6Prefix\0"
426 "CAN\0",
427 config_item_perf_lookup, network_network_gperf_lookup,
428 CONFIG_PARSE_WARN, network);
429 if (r < 0)
430 return r;
431
432 network_apply_anonymize_if_set(network);
433
434 r = network_add_ipv4ll_route(network);
435 if (r < 0)
436 log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
437
438 LIST_PREPEND(networks, manager->networks, network);
439 network->manager = manager;
440
441 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
442 if (r < 0)
443 return r;
444
445 r = hashmap_put(manager->networks_by_name, network->name, network);
446 if (r < 0)
447 return r;
448
449 if (network_verify(network) < 0)
450 return 0;
451
452 network = NULL;
453 return 0;
454 }
455
456 int network_load(Manager *manager) {
457 Network *network;
458 _cleanup_strv_free_ char **files = NULL;
459 char **f;
460 int r;
461
462 assert(manager);
463
464 while ((network = manager->networks))
465 network_free(network);
466
467 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
468 if (r < 0)
469 return log_error_errno(r, "Failed to enumerate network files: %m");
470
471 STRV_FOREACH_BACKWARDS(f, files) {
472 r = network_load_one(manager, *f);
473 if (r < 0)
474 return r;
475 }
476
477 return 0;
478 }
479
480 void network_free(Network *network) {
481 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
482 RoutingPolicyRule *rule;
483 FdbEntry *fdb_entry;
484 Neighbor *neighbor;
485 AddressLabel *label;
486 Prefix *prefix;
487 Address *address;
488 Route *route;
489
490 if (!network)
491 return;
492
493 free(network->filename);
494
495 set_free_free(network->match_mac);
496 strv_free(network->match_path);
497 strv_free(network->match_driver);
498 strv_free(network->match_type);
499 strv_free(network->match_name);
500
501 free(network->description);
502 free(network->dhcp_vendor_class_identifier);
503 strv_free(network->dhcp_user_class);
504 free(network->dhcp_hostname);
505
506 free(network->mac);
507
508 strv_free(network->ntp);
509 free(network->dns);
510 ordered_set_free_free(network->search_domains);
511 ordered_set_free_free(network->route_domains);
512 strv_free(network->bind_carrier);
513
514 ordered_set_free_free(network->router_search_domains);
515 free(network->router_dns);
516
517 free(network->bridge_name);
518 free(network->bond_name);
519 free(network->vrf_name);
520 hashmap_free_free_key(network->stacked_netdev_names);
521 netdev_unref(network->bridge);
522 netdev_unref(network->bond);
523 netdev_unref(network->vrf);
524 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
525
526 while ((route = network->static_routes))
527 route_free(route);
528
529 while ((address = network->static_addresses))
530 address_free(address);
531
532 while ((fdb_entry = network->static_fdb_entries))
533 fdb_entry_free(fdb_entry);
534
535 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
536 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
537
538 while ((neighbor = network->neighbors))
539 neighbor_free(neighbor);
540
541 while ((label = network->address_labels))
542 address_label_free(label);
543
544 while ((prefix = network->static_prefixes))
545 prefix_free(prefix);
546
547 while ((rule = network->rules))
548 routing_policy_rule_free(rule);
549
550 hashmap_free(network->addresses_by_section);
551 hashmap_free(network->routes_by_section);
552 hashmap_free(network->fdb_entries_by_section);
553 hashmap_free(network->neighbors_by_section);
554 hashmap_free(network->address_labels_by_section);
555 hashmap_free(network->prefixes_by_section);
556 hashmap_free(network->rules_by_section);
557
558 if (network->manager) {
559 if (network->manager->networks)
560 LIST_REMOVE(networks, network->manager->networks, network);
561
562 if (network->manager->networks_by_name && network->name)
563 hashmap_remove(network->manager->networks_by_name, network->name);
564
565 if (network->manager->duids_requesting_uuid)
566 set_remove(network->manager->duids_requesting_uuid, &network->duid);
567 }
568
569 free(network->name);
570
571 condition_free_list(network->match_host);
572 condition_free_list(network->match_virt);
573 condition_free_list(network->match_kernel_cmdline);
574 condition_free_list(network->match_kernel_version);
575 condition_free_list(network->match_arch);
576
577 free(network->dhcp_server_timezone);
578 free(network->dhcp_server_dns);
579 free(network->dhcp_server_ntp);
580
581 set_free_free(network->dnssec_negative_trust_anchors);
582
583 free(network);
584 }
585
586 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
587 Network *network;
588
589 assert(manager);
590 assert(name);
591 assert(ret);
592
593 network = hashmap_get(manager->networks_by_name, name);
594 if (!network)
595 return -ENOENT;
596
597 *ret = network;
598
599 return 0;
600 }
601
602 int network_get(Manager *manager, sd_device *device,
603 const char *ifname, const struct ether_addr *address,
604 Network **ret) {
605 const char *path = NULL, *driver = NULL, *devtype = NULL;
606 Network *network;
607
608 assert(manager);
609 assert(ret);
610
611 if (device) {
612 (void) sd_device_get_property_value(device, "ID_PATH", &path);
613
614 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
615
616 (void) sd_device_get_devtype(device, &devtype);
617 }
618
619 LIST_FOREACH(networks, network, manager->networks) {
620 if (net_match_config(network->match_mac, network->match_path,
621 network->match_driver, network->match_type,
622 network->match_name, network->match_host,
623 network->match_virt, network->match_kernel_cmdline,
624 network->match_kernel_version, network->match_arch,
625 address, path, driver, devtype, ifname)) {
626 if (network->match_name && device) {
627 const char *attr;
628 uint8_t name_assign_type = NET_NAME_UNKNOWN;
629
630 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
631 (void) safe_atou8(attr, &name_assign_type);
632
633 if (name_assign_type == NET_NAME_ENUM)
634 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
635 ifname, network->filename);
636 else
637 log_debug("%s: found matching network '%s'", ifname, network->filename);
638 } else
639 log_debug("%s: found matching network '%s'", ifname, network->filename);
640
641 *ret = network;
642 return 0;
643 }
644 }
645
646 *ret = NULL;
647
648 return -ENOENT;
649 }
650
651 int network_apply(Network *network, Link *link) {
652 assert(network);
653 assert(link);
654
655 link->network = network;
656
657 if (network->n_dns > 0 ||
658 !strv_isempty(network->ntp) ||
659 !ordered_set_isempty(network->search_domains) ||
660 !ordered_set_isempty(network->route_domains))
661 link_dirty(link);
662
663 return 0;
664 }
665
666 bool network_has_static_ipv6_addresses(Network *network) {
667 Address *address;
668
669 assert(network);
670
671 LIST_FOREACH(addresses, address, network->static_addresses) {
672 if (address->family == AF_INET6)
673 return true;
674 }
675
676 return false;
677 }
678
679 int config_parse_stacked_netdev(const char *unit,
680 const char *filename,
681 unsigned line,
682 const char *section,
683 unsigned section_line,
684 const char *lvalue,
685 int ltype,
686 const char *rvalue,
687 void *data,
688 void *userdata) {
689 _cleanup_free_ char *name = NULL;
690 NetDevKind kind = ltype;
691 Hashmap **h = data;
692 int r;
693
694 assert(filename);
695 assert(lvalue);
696 assert(rvalue);
697 assert(data);
698 assert(IN_SET(kind,
699 NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
700 NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, _NETDEV_KIND_TUNNEL));
701
702 if (!ifname_valid(rvalue)) {
703 log_syntax(unit, LOG_ERR, filename, line, 0,
704 "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
705 return 0;
706 }
707
708 name = strdup(rvalue);
709 if (!name)
710 return log_oom();
711
712 r = hashmap_ensure_allocated(h, &string_hash_ops);
713 if (r < 0)
714 return log_oom();
715
716 r = hashmap_put(*h, name, INT_TO_PTR(kind));
717 if (r < 0)
718 log_syntax(unit, LOG_ERR, filename, line, r,
719 "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
720 else if (r == 0)
721 log_syntax(unit, LOG_DEBUG, filename, line, r,
722 "NetDev '%s' specified twice, ignoring.", name);
723 else
724 name = NULL;
725
726 return 0;
727 }
728
729 int config_parse_domains(
730 const char *unit,
731 const char *filename,
732 unsigned line,
733 const char *section,
734 unsigned section_line,
735 const char *lvalue,
736 int ltype,
737 const char *rvalue,
738 void *data,
739 void *userdata) {
740
741 const char *p;
742 Network *n = data;
743 int r;
744
745 assert(n);
746 assert(lvalue);
747 assert(rvalue);
748
749 if (isempty(rvalue)) {
750 n->search_domains = ordered_set_free_free(n->search_domains);
751 n->route_domains = ordered_set_free_free(n->route_domains);
752 return 0;
753 }
754
755 p = rvalue;
756 for (;;) {
757 _cleanup_free_ char *w = NULL, *normalized = NULL;
758 const char *domain;
759 bool is_route;
760
761 r = extract_first_word(&p, &w, NULL, 0);
762 if (r < 0) {
763 log_syntax(unit, LOG_ERR, filename, line, r,
764 "Failed to extract search or route domain, ignoring: %s", rvalue);
765 break;
766 }
767 if (r == 0)
768 break;
769
770 is_route = w[0] == '~';
771 domain = is_route ? w + 1 : w;
772
773 if (dns_name_is_root(domain) || streq(domain, "*")) {
774 /* If the root domain appears as is, or the special token "*" is found, we'll
775 * consider this as routing domain, unconditionally. */
776 is_route = true;
777 domain = "."; /* make sure we don't allow empty strings, thus write the root
778 * domain as "." */
779 } else {
780 r = dns_name_normalize(domain, 0, &normalized);
781 if (r < 0) {
782 log_syntax(unit, LOG_ERR, filename, line, r,
783 "'%s' is not a valid domain name, ignoring.", domain);
784 continue;
785 }
786
787 domain = normalized;
788
789 if (is_localhost(domain)) {
790 log_syntax(unit, LOG_ERR, filename, line, 0,
791 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
792 domain);
793 continue;
794 }
795 }
796
797 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
798 r = ordered_set_ensure_allocated(set, &string_hash_ops);
799 if (r < 0)
800 return r;
801
802 r = ordered_set_put_strdup(*set, domain);
803 if (r < 0)
804 return log_oom();
805 }
806
807 return 0;
808 }
809
810 int config_parse_ipv4ll(
811 const char* unit,
812 const char *filename,
813 unsigned line,
814 const char *section,
815 unsigned section_line,
816 const char *lvalue,
817 int ltype,
818 const char *rvalue,
819 void *data,
820 void *userdata) {
821
822 AddressFamilyBoolean *link_local = data;
823
824 assert(filename);
825 assert(lvalue);
826 assert(rvalue);
827 assert(data);
828
829 /* Note that this is mostly like
830 * config_parse_address_family_boolean(), except that it
831 * applies only to IPv4 */
832
833 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
834
835 return 0;
836 }
837
838 int config_parse_dhcp(
839 const char* unit,
840 const char *filename,
841 unsigned line,
842 const char *section,
843 unsigned section_line,
844 const char *lvalue,
845 int ltype,
846 const char *rvalue,
847 void *data,
848 void *userdata) {
849
850 AddressFamilyBoolean *dhcp = data, s;
851
852 assert(filename);
853 assert(lvalue);
854 assert(rvalue);
855 assert(data);
856
857 /* Note that this is mostly like
858 * config_parse_address_family_boolean(), except that it
859 * understands some old names for the enum values */
860
861 s = address_family_boolean_from_string(rvalue);
862 if (s < 0) {
863
864 /* Previously, we had a slightly different enum here,
865 * support its values for compatbility. */
866
867 if (streq(rvalue, "none"))
868 s = ADDRESS_FAMILY_NO;
869 else if (streq(rvalue, "v4"))
870 s = ADDRESS_FAMILY_IPV4;
871 else if (streq(rvalue, "v6"))
872 s = ADDRESS_FAMILY_IPV6;
873 else if (streq(rvalue, "both"))
874 s = ADDRESS_FAMILY_YES;
875 else {
876 log_syntax(unit, LOG_ERR, filename, line, 0,
877 "Failed to parse DHCP option, ignoring: %s", rvalue);
878 return 0;
879 }
880
881 log_syntax(unit, LOG_WARNING, filename, line, 0,
882 "DHCP=%s is deprecated, please use DHCP=%s instead.",
883 rvalue, address_family_boolean_to_string(s));
884 }
885
886 *dhcp = s;
887 return 0;
888 }
889
890 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
891 [DHCP_CLIENT_ID_MAC] = "mac",
892 [DHCP_CLIENT_ID_DUID] = "duid",
893 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
894 };
895
896 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
897 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
898 "Failed to parse client identifier type");
899
900 int config_parse_ipv6token(
901 const char* unit,
902 const char *filename,
903 unsigned line,
904 const char *section,
905 unsigned section_line,
906 const char *lvalue,
907 int ltype,
908 const char *rvalue,
909 void *data,
910 void *userdata) {
911
912 union in_addr_union buffer;
913 struct in6_addr *token = data;
914 int r;
915
916 assert(filename);
917 assert(lvalue);
918 assert(rvalue);
919 assert(token);
920
921 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
922 if (r < 0) {
923 log_syntax(unit, LOG_ERR, filename, line, r,
924 "Failed to parse IPv6 token, ignoring: %s", rvalue);
925 return 0;
926 }
927
928 if (in_addr_is_null(AF_INET6, &buffer)) {
929 log_syntax(unit, LOG_ERR, filename, line, 0,
930 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
931 return 0;
932 }
933
934 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
935 log_syntax(unit, LOG_ERR, filename, line, 0,
936 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
937 return 0;
938 }
939
940 *token = buffer.in6;
941
942 return 0;
943 }
944
945 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
946 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
947 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
948 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
949 };
950
951 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
952
953 int config_parse_ipv6_privacy_extensions(
954 const char* unit,
955 const char *filename,
956 unsigned line,
957 const char *section,
958 unsigned section_line,
959 const char *lvalue,
960 int ltype,
961 const char *rvalue,
962 void *data,
963 void *userdata) {
964
965 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
966 int k;
967
968 assert(filename);
969 assert(lvalue);
970 assert(rvalue);
971 assert(ipv6_privacy_extensions);
972
973 /* Our enum shall be a superset of booleans, hence first try
974 * to parse as boolean, and then as enum */
975
976 k = parse_boolean(rvalue);
977 if (k > 0)
978 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
979 else if (k == 0)
980 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
981 else {
982 IPv6PrivacyExtensions s;
983
984 s = ipv6_privacy_extensions_from_string(rvalue);
985 if (s < 0) {
986
987 if (streq(rvalue, "kernel"))
988 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
989 else {
990 log_syntax(unit, LOG_ERR, filename, line, 0,
991 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
992 return 0;
993 }
994 }
995
996 *ipv6_privacy_extensions = s;
997 }
998
999 return 0;
1000 }
1001
1002 int config_parse_hostname(
1003 const char *unit,
1004 const char *filename,
1005 unsigned line,
1006 const char *section,
1007 unsigned section_line,
1008 const char *lvalue,
1009 int ltype,
1010 const char *rvalue,
1011 void *data,
1012 void *userdata) {
1013
1014 _cleanup_free_ char *hn = NULL;
1015 char **hostname = data;
1016 int r;
1017
1018 assert(filename);
1019 assert(lvalue);
1020 assert(rvalue);
1021
1022 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
1023 if (r < 0)
1024 return r;
1025
1026 if (!hostname_is_valid(hn, false)) {
1027 log_syntax(unit, LOG_ERR, filename, line, 0,
1028 "Hostname is not valid, ignoring assignment: %s", rvalue);
1029 return 0;
1030 }
1031
1032 r = dns_name_is_valid(hn);
1033 if (r < 0) {
1034 log_syntax(unit, LOG_ERR, filename, line, r,
1035 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
1036 return 0;
1037 }
1038 if (r == 0) {
1039 log_syntax(unit, LOG_ERR, filename, line, 0,
1040 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
1041 return 0;
1042 }
1043
1044 return free_and_replace(*hostname, hn);
1045 }
1046
1047 int config_parse_timezone(
1048 const char *unit,
1049 const char *filename,
1050 unsigned line,
1051 const char *section,
1052 unsigned section_line,
1053 const char *lvalue,
1054 int ltype,
1055 const char *rvalue,
1056 void *data,
1057 void *userdata) {
1058
1059 _cleanup_free_ char *tz = NULL;
1060 char **datap = data;
1061 int r;
1062
1063 assert(filename);
1064 assert(lvalue);
1065 assert(rvalue);
1066
1067 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1068 if (r < 0)
1069 return r;
1070
1071 if (!timezone_is_valid(tz, LOG_ERR)) {
1072 log_syntax(unit, LOG_ERR, filename, line, 0,
1073 "Timezone is not valid, ignoring assignment: %s", rvalue);
1074 return 0;
1075 }
1076
1077 return free_and_replace(*datap, tz);
1078 }
1079
1080 int config_parse_dhcp_server_dns(
1081 const char *unit,
1082 const char *filename,
1083 unsigned line,
1084 const char *section,
1085 unsigned section_line,
1086 const char *lvalue,
1087 int ltype,
1088 const char *rvalue,
1089 void *data,
1090 void *userdata) {
1091
1092 Network *n = data;
1093 const char *p = rvalue;
1094 int r;
1095
1096 assert(filename);
1097 assert(lvalue);
1098 assert(rvalue);
1099
1100 for (;;) {
1101 _cleanup_free_ char *w = NULL;
1102 struct in_addr a, *m;
1103
1104 r = extract_first_word(&p, &w, NULL, 0);
1105 if (r == -ENOMEM)
1106 return log_oom();
1107 if (r < 0) {
1108 log_syntax(unit, LOG_ERR, filename, line, r,
1109 "Failed to extract word, ignoring: %s", rvalue);
1110 return 0;
1111 }
1112 if (r == 0)
1113 break;
1114
1115 if (inet_pton(AF_INET, w, &a) <= 0) {
1116 log_syntax(unit, LOG_ERR, filename, line, 0,
1117 "Failed to parse DNS server address, ignoring: %s", w);
1118 continue;
1119 }
1120
1121 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1122 if (!m)
1123 return log_oom();
1124
1125 m[n->n_dhcp_server_dns++] = a;
1126 n->dhcp_server_dns = m;
1127 }
1128
1129 return 0;
1130 }
1131
1132 int config_parse_radv_dns(
1133 const char *unit,
1134 const char *filename,
1135 unsigned line,
1136 const char *section,
1137 unsigned section_line,
1138 const char *lvalue,
1139 int ltype,
1140 const char *rvalue,
1141 void *data,
1142 void *userdata) {
1143
1144 Network *n = data;
1145 const char *p = rvalue;
1146 int r;
1147
1148 assert(filename);
1149 assert(lvalue);
1150 assert(rvalue);
1151
1152 for (;;) {
1153 _cleanup_free_ char *w = NULL;
1154 union in_addr_union a;
1155
1156 r = extract_first_word(&p, &w, NULL, 0);
1157 if (r == -ENOMEM)
1158 return log_oom();
1159 if (r < 0) {
1160 log_syntax(unit, LOG_ERR, filename, line, r,
1161 "Failed to extract word, ignoring: %s", rvalue);
1162 return 0;
1163 }
1164 if (r == 0)
1165 break;
1166
1167 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1168 struct in6_addr *m;
1169
1170 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1171 if (!m)
1172 return log_oom();
1173
1174 m[n->n_router_dns++] = a.in6;
1175 n->router_dns = m;
1176
1177 } else
1178 log_syntax(unit, LOG_ERR, filename, line, 0,
1179 "Failed to parse DNS server address, ignoring: %s", w);
1180 }
1181
1182 return 0;
1183 }
1184
1185 int config_parse_radv_search_domains(
1186 const char *unit,
1187 const char *filename,
1188 unsigned line,
1189 const char *section,
1190 unsigned section_line,
1191 const char *lvalue,
1192 int ltype,
1193 const char *rvalue,
1194 void *data,
1195 void *userdata) {
1196
1197 Network *n = data;
1198 const char *p = rvalue;
1199 int r;
1200
1201 assert(filename);
1202 assert(lvalue);
1203 assert(rvalue);
1204
1205 for (;;) {
1206 _cleanup_free_ char *w = NULL, *idna = NULL;
1207
1208 r = extract_first_word(&p, &w, NULL, 0);
1209 if (r == -ENOMEM)
1210 return log_oom();
1211 if (r < 0) {
1212 log_syntax(unit, LOG_ERR, filename, line, r,
1213 "Failed to extract word, ignoring: %s", rvalue);
1214 return 0;
1215 }
1216 if (r == 0)
1217 break;
1218
1219 r = dns_name_apply_idna(w, &idna);
1220 if (r < 0) {
1221 log_syntax(unit, LOG_ERR, filename, line, r,
1222 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1223 continue;
1224 } else if (r == 0)
1225 /* transfer ownership to simplify subsequent operations */
1226 idna = TAKE_PTR(w);
1227
1228 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1229 if (r < 0)
1230 return r;
1231
1232 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1233 if (r < 0)
1234 return r;
1235 }
1236
1237 return 0;
1238 }
1239
1240 int config_parse_dhcp_server_ntp(
1241 const char *unit,
1242 const char *filename,
1243 unsigned line,
1244 const char *section,
1245 unsigned section_line,
1246 const char *lvalue,
1247 int ltype,
1248 const char *rvalue,
1249 void *data,
1250 void *userdata) {
1251
1252 Network *n = data;
1253 const char *p = rvalue;
1254 int r;
1255
1256 assert(filename);
1257 assert(lvalue);
1258 assert(rvalue);
1259
1260 for (;;) {
1261 _cleanup_free_ char *w = NULL;
1262 struct in_addr a, *m;
1263
1264 r = extract_first_word(&p, &w, NULL, 0);
1265 if (r == -ENOMEM)
1266 return log_oom();
1267 if (r < 0) {
1268 log_syntax(unit, LOG_ERR, filename, line, r,
1269 "Failed to extract word, ignoring: %s", rvalue);
1270 return 0;
1271 }
1272 if (r == 0)
1273 return 0;
1274
1275 if (inet_pton(AF_INET, w, &a) <= 0) {
1276 log_syntax(unit, LOG_ERR, filename, line, 0,
1277 "Failed to parse NTP server address, ignoring: %s", w);
1278 continue;
1279 }
1280
1281 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1282 if (!m)
1283 return log_oom();
1284
1285 m[n->n_dhcp_server_ntp++] = a;
1286 n->dhcp_server_ntp = m;
1287 }
1288 }
1289
1290 int config_parse_dns(
1291 const char *unit,
1292 const char *filename,
1293 unsigned line,
1294 const char *section,
1295 unsigned section_line,
1296 const char *lvalue,
1297 int ltype,
1298 const char *rvalue,
1299 void *data,
1300 void *userdata) {
1301
1302 Network *n = userdata;
1303 int r;
1304
1305 assert(filename);
1306 assert(lvalue);
1307 assert(rvalue);
1308
1309 for (;;) {
1310 _cleanup_free_ char *w = NULL;
1311 union in_addr_union a;
1312 struct in_addr_data *m;
1313 int family;
1314
1315 r = extract_first_word(&rvalue, &w, NULL, 0);
1316 if (r == -ENOMEM)
1317 return log_oom();
1318 if (r < 0) {
1319 log_syntax(unit, LOG_ERR, filename, line, r,
1320 "Invalid syntax, ignoring: %s", rvalue);
1321 break;
1322 }
1323 if (r == 0)
1324 break;
1325
1326 r = in_addr_from_string_auto(w, &family, &a);
1327 if (r < 0) {
1328 log_syntax(unit, LOG_ERR, filename, line, r,
1329 "Failed to parse dns server address, ignoring: %s", w);
1330 continue;
1331 }
1332
1333 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1334 if (!m)
1335 return log_oom();
1336
1337 m[n->n_dns++] = (struct in_addr_data) {
1338 .family = family,
1339 .address = a,
1340 };
1341
1342 n->dns = m;
1343 }
1344
1345 return 0;
1346 }
1347
1348 int config_parse_dnssec_negative_trust_anchors(
1349 const char *unit,
1350 const char *filename,
1351 unsigned line,
1352 const char *section,
1353 unsigned section_line,
1354 const char *lvalue,
1355 int ltype,
1356 const char *rvalue,
1357 void *data,
1358 void *userdata) {
1359
1360 const char *p = rvalue;
1361 Network *n = data;
1362 int r;
1363
1364 assert(n);
1365 assert(lvalue);
1366 assert(rvalue);
1367
1368 if (isempty(rvalue)) {
1369 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1370 return 0;
1371 }
1372
1373 for (;;) {
1374 _cleanup_free_ char *w = NULL;
1375
1376 r = extract_first_word(&p, &w, NULL, 0);
1377 if (r < 0) {
1378 log_syntax(unit, LOG_ERR, filename, line, r,
1379 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1380 break;
1381 }
1382 if (r == 0)
1383 break;
1384
1385 r = dns_name_is_valid(w);
1386 if (r <= 0) {
1387 log_syntax(unit, LOG_ERR, filename, line, r,
1388 "%s is not a valid domain name, ignoring.", w);
1389 continue;
1390 }
1391
1392 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1393 if (r < 0)
1394 return log_oom();
1395
1396 r = set_put(n->dnssec_negative_trust_anchors, w);
1397 if (r < 0)
1398 return log_oom();
1399 if (r > 0)
1400 w = NULL;
1401 }
1402
1403 return 0;
1404 }
1405
1406 int config_parse_ntp(
1407 const char *unit,
1408 const char *filename,
1409 unsigned line,
1410 const char *section,
1411 unsigned section_line,
1412 const char *lvalue,
1413 int ltype,
1414 const char *rvalue,
1415 void *data,
1416 void *userdata) {
1417
1418 char ***l = data;
1419 int r;
1420
1421 assert(l);
1422 assert(lvalue);
1423 assert(rvalue);
1424
1425 if (isempty(rvalue)) {
1426 *l = strv_free(*l);
1427 return 0;
1428 }
1429
1430 for (;;) {
1431 _cleanup_free_ char *w = NULL;
1432
1433 r = extract_first_word(&rvalue, &w, NULL, 0);
1434 if (r == -ENOMEM)
1435 return log_oom();
1436 if (r < 0) {
1437 log_syntax(unit, LOG_ERR, filename, line, r,
1438 "Failed to extract NTP server name, ignoring: %s", rvalue);
1439 break;
1440 }
1441 if (r == 0)
1442 break;
1443
1444 r = dns_name_is_valid_or_address(w);
1445 if (r <= 0) {
1446 log_syntax(unit, LOG_ERR, filename, line, r,
1447 "%s is not a valid domain name or IP address, ignoring.", w);
1448 continue;
1449 }
1450
1451 if (strv_length(*l) > MAX_NTP_SERVERS) {
1452 log_syntax(unit, LOG_WARNING, filename, line, 0,
1453 "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1454 MAX_NTP_SERVERS, w);
1455 break;
1456 }
1457
1458 r = strv_consume(l, TAKE_PTR(w));
1459 if (r < 0)
1460 return log_oom();
1461 }
1462
1463 return 0;
1464 }
1465
1466 int config_parse_dhcp_user_class(
1467 const char *unit,
1468 const char *filename,
1469 unsigned line,
1470 const char *section,
1471 unsigned section_line,
1472 const char *lvalue,
1473 int ltype,
1474 const char *rvalue,
1475 void *data,
1476 void *userdata) {
1477
1478 char ***l = data;
1479 int r;
1480
1481 assert(l);
1482 assert(lvalue);
1483 assert(rvalue);
1484
1485 if (isempty(rvalue)) {
1486 *l = strv_free(*l);
1487 return 0;
1488 }
1489
1490 for (;;) {
1491 _cleanup_free_ char *w = NULL;
1492
1493 r = extract_first_word(&rvalue, &w, NULL, 0);
1494 if (r == -ENOMEM)
1495 return log_oom();
1496 if (r < 0) {
1497 log_syntax(unit, LOG_ERR, filename, line, r,
1498 "Failed to split user classes option, ignoring: %s", rvalue);
1499 break;
1500 }
1501 if (r == 0)
1502 break;
1503
1504 if (strlen(w) > 255) {
1505 log_syntax(unit, LOG_ERR, filename, line, 0,
1506 "%s length is not in the range 1-255, ignoring.", w);
1507 continue;
1508 }
1509
1510 r = strv_push(l, w);
1511 if (r < 0)
1512 return log_oom();
1513
1514 w = NULL;
1515 }
1516
1517 return 0;
1518 }
1519
1520 int config_parse_section_route_table(
1521 const char *unit,
1522 const char *filename,
1523 unsigned line,
1524 const char *section,
1525 unsigned section_line,
1526 const char *lvalue,
1527 int ltype,
1528 const char *rvalue,
1529 void *data,
1530 void *userdata) {
1531
1532 Network *network = data;
1533 uint32_t rt;
1534 int r;
1535
1536 assert(filename);
1537 assert(lvalue);
1538 assert(rvalue);
1539 assert(data);
1540
1541 r = safe_atou32(rvalue, &rt);
1542 if (r < 0) {
1543 log_syntax(unit, LOG_ERR, filename, line, r,
1544 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
1545 return 0;
1546 }
1547
1548 if (streq_ptr(section, "DHCP")) {
1549 network->dhcp_route_table = rt;
1550 network->dhcp_route_table_set = true;
1551 } else { /* section is IPv6AcceptRA */
1552 network->ipv6_accept_ra_route_table = rt;
1553 network->ipv6_accept_ra_route_table_set = true;
1554 }
1555
1556 return 0;
1557 }
1558
1559 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1560 "Failed to parse DHCP use domains setting");
1561
1562 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1563 [DHCP_USE_DOMAINS_NO] = "no",
1564 [DHCP_USE_DOMAINS_ROUTE] = "route",
1565 [DHCP_USE_DOMAINS_YES] = "yes",
1566 };
1567
1568 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1569
1570 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1571
1572 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1573 [LLDP_MODE_NO] = "no",
1574 [LLDP_MODE_YES] = "yes",
1575 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1576 };
1577
1578 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
1579
1580 int config_parse_iaid(const char *unit,
1581 const char *filename,
1582 unsigned line,
1583 const char *section,
1584 unsigned section_line,
1585 const char *lvalue,
1586 int ltype,
1587 const char *rvalue,
1588 void *data,
1589 void *userdata) {
1590 Network *network = data;
1591 uint32_t iaid;
1592 int r;
1593
1594 assert(filename);
1595 assert(lvalue);
1596 assert(rvalue);
1597 assert(network);
1598
1599 r = safe_atou32(rvalue, &iaid);
1600 if (r < 0) {
1601 log_syntax(unit, LOG_ERR, filename, line, r,
1602 "Unable to read IAID, ignoring assignment: %s", rvalue);
1603 return 0;
1604 }
1605
1606 network->iaid = iaid;
1607 network->iaid_set = true;
1608
1609 return 0;
1610 }
1611
1612 int config_parse_required_for_online(
1613 const char *unit,
1614 const char *filename,
1615 unsigned line,
1616 const char *section,
1617 unsigned section_line,
1618 const char *lvalue,
1619 int ltype,
1620 const char *rvalue,
1621 void *data,
1622 void *userdata) {
1623
1624 Network *network = data;
1625 LinkOperationalState s;
1626 bool required = true;
1627 int r;
1628
1629 if (isempty(rvalue)) {
1630 network->required_for_online = true;
1631 network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1632 return 0;
1633 }
1634
1635 s = link_operstate_from_string(rvalue);
1636 if (s < 0) {
1637 r = parse_boolean(rvalue);
1638 if (r < 0) {
1639 log_syntax(unit, LOG_ERR, filename, line, r,
1640 "Failed to parse %s= setting, ignoring assignment: %s",
1641 lvalue, rvalue);
1642 return 0;
1643 }
1644
1645 required = r;
1646 s = LINK_OPERSTATE_DEGRADED;
1647 }
1648
1649 network->required_for_online = required;
1650 network->required_operstate_for_online = s;
1651
1652 return 0;
1653 }