2 This file is part of systemd.
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "conf-files.h"
25 #include "conf-parser.h"
26 #include "dns-domain.h"
28 #include "hostname-util.h"
29 #include "network-internal.h"
30 #include "networkd-manager.h"
31 #include "networkd-network.h"
32 #include "parse-util.h"
34 #include "stat-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
39 static void network_config_hash_func(const void *p
, struct siphash
*state
) {
40 const NetworkConfigSection
*c
= p
;
42 siphash24_compress(c
->filename
, strlen(c
->filename
), state
);
43 siphash24_compress(&c
->line
, sizeof(c
->line
), state
);
46 static int network_config_compare_func(const void *a
, const void *b
) {
47 const NetworkConfigSection
*x
= a
, *y
= b
;
50 r
= strcmp(x
->filename
, y
->filename
);
54 return y
->line
- x
->line
;
57 const struct hash_ops network_config_hash_ops
= {
58 .hash
= network_config_hash_func
,
59 .compare
= network_config_compare_func
,
62 int network_config_section_new(const char *filename
, unsigned line
, NetworkConfigSection
**s
) {
63 NetworkConfigSection
*cs
;
65 cs
= malloc0(offsetof(NetworkConfigSection
, filename
) + strlen(filename
) + 1);
69 strcpy(cs
->filename
, filename
);
78 void network_config_section_free(NetworkConfigSection
*cs
) {
82 static int network_load_one(Manager
*manager
, const char *filename
) {
83 _cleanup_network_free_ Network
*network
= NULL
;
84 _cleanup_fclose_
FILE *file
= NULL
;
86 const char *dropin_dirname
;
94 file
= fopen(filename
, "re");
102 if (null_or_empty_fd(fileno(file
))) {
103 log_debug("Skipping empty file: %s", filename
);
107 network
= new0(Network
, 1);
111 network
->manager
= manager
;
113 LIST_HEAD_INIT(network
->static_addresses
);
114 LIST_HEAD_INIT(network
->static_routes
);
115 LIST_HEAD_INIT(network
->static_fdb_entries
);
116 LIST_HEAD_INIT(network
->ipv6_proxy_ndp_addresses
);
117 LIST_HEAD_INIT(network
->address_labels
);
118 LIST_HEAD_INIT(network
->static_prefixes
);
120 network
->stacked_netdevs
= hashmap_new(&string_hash_ops
);
121 if (!network
->stacked_netdevs
)
124 network
->addresses_by_section
= hashmap_new(&network_config_hash_ops
);
125 if (!network
->addresses_by_section
)
128 network
->routes_by_section
= hashmap_new(&network_config_hash_ops
);
129 if (!network
->routes_by_section
)
132 network
->fdb_entries_by_section
= hashmap_new(NULL
);
133 if (!network
->fdb_entries_by_section
)
136 network
->address_labels_by_section
= hashmap_new(&network_config_hash_ops
);
137 if (!network
->address_labels_by_section
)
140 network
->prefixes_by_section
= hashmap_new(&network_config_hash_ops
);
141 if (!network
->prefixes_by_section
)
144 network
->filename
= strdup(filename
);
145 if (!network
->filename
)
148 network
->name
= strdup(basename(filename
));
152 d
= strrchr(network
->name
, '.');
156 assert(streq(d
, ".network"));
160 network
->dhcp
= ADDRESS_FAMILY_NO
;
161 network
->dhcp_use_ntp
= true;
162 network
->dhcp_use_dns
= true;
163 network
->dhcp_use_hostname
= true;
164 network
->dhcp_use_routes
= true;
165 network
->dhcp_send_hostname
= true;
166 network
->dhcp_route_metric
= DHCP_ROUTE_METRIC
;
167 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
;
168 network
->dhcp_route_table
= RT_TABLE_MAIN
;
170 network
->dhcp_server_emit_dns
= true;
171 network
->dhcp_server_emit_ntp
= true;
172 network
->dhcp_server_emit_router
= true;
173 network
->dhcp_server_emit_timezone
= true;
175 network
->use_bpdu
= true;
176 network
->allow_port_to_be_root
= true;
177 network
->unicast_flood
= true;
178 network
->priority
= LINK_BRIDGE_PORT_PRIORITY_INVALID
;
180 network
->lldp_mode
= LLDP_MODE_ROUTERS_ONLY
;
182 network
->llmnr
= RESOLVE_SUPPORT_YES
;
183 network
->mdns
= RESOLVE_SUPPORT_NO
;
184 network
->dnssec_mode
= _DNSSEC_MODE_INVALID
;
186 network
->link_local
= ADDRESS_FAMILY_IPV6
;
188 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
189 network
->ipv6_accept_ra
= -1;
190 network
->ipv6_dad_transmits
= -1;
191 network
->ipv6_hop_limit
= -1;
192 network
->ipv6_proxy_ndp
= -1;
193 network
->duid
.type
= _DUID_TYPE_INVALID
;
194 network
->proxy_arp
= -1;
196 network
->ipv6_accept_ra_use_dns
= true;
197 network
->ipv6_accept_ra_route_table
= RT_TABLE_MAIN
;
199 dropin_dirname
= strjoina(network
->name
, ".network.d");
201 r
= config_parse_many(filename
, network_dirs
, dropin_dirname
,
209 "DHCPv4\0" /* compat */
212 "IPv6NDPProxyAddress\0"
216 "IPv6PrefixDelegation\0"
218 config_item_perf_lookup
, network_network_gperf_lookup
,
223 /* IPMasquerade=yes implies IPForward=yes */
224 if (network
->ip_masquerade
)
225 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
227 LIST_PREPEND(networks
, manager
->networks
, network
);
229 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
233 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
237 LIST_FOREACH(routes
, route
, network
->static_routes
) {
238 if (!route
->family
) {
239 log_warning("Route section without Gateway field configured in %s. "
240 "Ignoring", filename
);
245 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
246 if (!address
->family
) {
247 log_warning("Address section without Address field configured in %s. "
248 "Ignoring", filename
);
258 int network_load(Manager
*manager
) {
260 _cleanup_strv_free_
char **files
= NULL
;
266 while ((network
= manager
->networks
))
267 network_free(network
);
269 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
271 return log_error_errno(r
, "Failed to enumerate network files: %m");
273 STRV_FOREACH_BACKWARDS(f
, files
) {
274 r
= network_load_one(manager
, *f
);
282 void network_free(Network
*network
) {
287 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
295 free(network
->filename
);
297 free(network
->match_mac
);
298 strv_free(network
->match_path
);
299 strv_free(network
->match_driver
);
300 strv_free(network
->match_type
);
301 strv_free(network
->match_name
);
303 free(network
->description
);
304 free(network
->dhcp_vendor_class_identifier
);
305 free(network
->dhcp_hostname
);
309 strv_free(network
->ntp
);
311 strv_free(network
->search_domains
);
312 strv_free(network
->route_domains
);
313 strv_free(network
->bind_carrier
);
315 netdev_unref(network
->bridge
);
316 netdev_unref(network
->bond
);
317 netdev_unref(network
->vrf
);
319 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
320 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
321 netdev_unref(netdev
);
323 hashmap_free(network
->stacked_netdevs
);
325 while ((route
= network
->static_routes
))
328 while ((address
= network
->static_addresses
))
329 address_free(address
);
331 while ((fdb_entry
= network
->static_fdb_entries
))
332 fdb_entry_free(fdb_entry
);
334 while ((ipv6_proxy_ndp_address
= network
->ipv6_proxy_ndp_addresses
))
335 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address
);
337 while ((label
= network
->address_labels
))
338 address_label_free(label
);
340 while ((prefix
= network
->static_prefixes
))
343 hashmap_free(network
->addresses_by_section
);
344 hashmap_free(network
->routes_by_section
);
345 hashmap_free(network
->fdb_entries_by_section
);
346 hashmap_free(network
->address_labels_by_section
);
347 hashmap_free(network
->prefixes_by_section
);
349 if (network
->manager
) {
350 if (network
->manager
->networks
)
351 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
353 if (network
->manager
->networks_by_name
)
354 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
359 condition_free_list(network
->match_host
);
360 condition_free_list(network
->match_virt
);
361 condition_free_list(network
->match_kernel
);
362 condition_free_list(network
->match_arch
);
364 free(network
->dhcp_server_timezone
);
365 free(network
->dhcp_server_dns
);
366 free(network
->dhcp_server_ntp
);
368 set_free_free(network
->dnssec_negative_trust_anchors
);
373 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
380 network
= hashmap_get(manager
->networks_by_name
, name
);
389 int network_get(Manager
*manager
, struct udev_device
*device
,
390 const char *ifname
, const struct ether_addr
*address
,
393 struct udev_device
*parent
;
394 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
400 path
= udev_device_get_property_value(device
, "ID_PATH");
402 parent
= udev_device_get_parent(device
);
404 parent_driver
= udev_device_get_driver(parent
);
406 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
408 devtype
= udev_device_get_devtype(device
);
411 LIST_FOREACH(networks
, network
, manager
->networks
) {
412 if (net_match_config(network
->match_mac
, network
->match_path
,
413 network
->match_driver
, network
->match_type
,
414 network
->match_name
, network
->match_host
,
415 network
->match_virt
, network
->match_kernel
,
417 address
, path
, parent_driver
, driver
,
419 if (network
->match_name
&& device
) {
421 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
423 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
425 (void) safe_atou8(attr
, &name_assign_type
);
427 if (name_assign_type
== NET_NAME_ENUM
)
428 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
429 ifname
, network
->filename
);
431 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
433 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
445 int network_apply(Network
*network
, Link
*link
) {
451 link
->network
= network
;
453 if (network
->ipv4ll_route
) {
456 r
= route_new_static(network
, NULL
, 0, &route
);
460 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
466 route
->family
= AF_INET
;
467 route
->dst_prefixlen
= 16;
468 route
->scope
= RT_SCOPE_LINK
;
469 route
->priority
= IPV4LL_ROUTE_METRIC
;
470 route
->protocol
= RTPROT_STATIC
;
473 if (network
->n_dns
> 0 ||
474 !strv_isempty(network
->ntp
) ||
475 !strv_isempty(network
->search_domains
) ||
476 !strv_isempty(network
->route_domains
))
482 bool network_has_static_ipv6_addresses(Network
*network
) {
487 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
488 if (address
->family
== AF_INET6
)
495 int config_parse_netdev(const char *unit
,
496 const char *filename
,
499 unsigned section_line
,
505 Network
*network
= userdata
;
506 _cleanup_free_
char *kind_string
= NULL
;
517 kind_string
= strdup(lvalue
);
521 /* the keys are CamelCase versions of the kind */
522 for (p
= kind_string
; *p
; p
++)
525 kind
= netdev_kind_from_string(kind_string
);
526 if (kind
== _NETDEV_KIND_INVALID
) {
527 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
531 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
533 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
537 if (netdev
->kind
!= kind
) {
538 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
543 case NETDEV_KIND_BRIDGE
:
544 network
->bridge
= netdev
;
547 case NETDEV_KIND_BOND
:
548 network
->bond
= netdev
;
551 case NETDEV_KIND_VRF
:
552 network
->vrf
= netdev
;
555 case NETDEV_KIND_VLAN
:
556 case NETDEV_KIND_MACVLAN
:
557 case NETDEV_KIND_MACVTAP
:
558 case NETDEV_KIND_IPVLAN
:
559 case NETDEV_KIND_VXLAN
:
560 case NETDEV_KIND_VCAN
:
561 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
563 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Can not add NetDev '%s' to network: %m", rvalue
);
569 assert_not_reached("Can not parse NetDev");
577 int config_parse_domains(
579 const char *filename
,
582 unsigned section_line
,
597 if (isempty(rvalue
)) {
598 n
->search_domains
= strv_free(n
->search_domains
);
599 n
->route_domains
= strv_free(n
->route_domains
);
605 _cleanup_free_
char *w
= NULL
, *normalized
= NULL
;
609 r
= extract_first_word(&p
, &w
, NULL
, 0);
611 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract search or route domain, ignoring: %s", rvalue
);
617 is_route
= w
[0] == '~';
618 domain
= is_route
? w
+ 1 : w
;
620 if (dns_name_is_root(domain
) || streq(domain
, "*")) {
621 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
622 * routing domain, unconditionally. */
624 domain
= "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
627 r
= dns_name_normalize(domain
, &normalized
);
629 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "'%s' is not a valid domain name, ignoring.", domain
);
635 if (is_localhost(domain
)) {
636 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain
);
642 r
= strv_extend(&n
->route_domains
, domain
);
647 r
= strv_extend(&n
->search_domains
, domain
);
653 strv_uniq(n
->route_domains
);
654 strv_uniq(n
->search_domains
);
659 int config_parse_tunnel(const char *unit
,
660 const char *filename
,
663 unsigned section_line
,
669 Network
*network
= userdata
;
678 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
680 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
684 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
685 netdev
->kind
!= NETDEV_KIND_SIT
&&
686 netdev
->kind
!= NETDEV_KIND_GRE
&&
687 netdev
->kind
!= NETDEV_KIND_GRETAP
&&
688 netdev
->kind
!= NETDEV_KIND_IP6GRE
&&
689 netdev
->kind
!= NETDEV_KIND_IP6GRETAP
&&
690 netdev
->kind
!= NETDEV_KIND_VTI
&&
691 netdev
->kind
!= NETDEV_KIND_VTI6
&&
692 netdev
->kind
!= NETDEV_KIND_IP6TNL
694 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
695 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
699 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
701 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
710 int config_parse_ipv4ll(
712 const char *filename
,
715 unsigned section_line
,
722 AddressFamilyBoolean
*link_local
= data
;
729 /* Note that this is mostly like
730 * config_parse_address_family_boolean(), except that it
731 * applies only to IPv4 */
733 SET_FLAG(*link_local
, ADDRESS_FAMILY_IPV4
, parse_boolean(rvalue
));
738 int config_parse_dhcp(
740 const char *filename
,
743 unsigned section_line
,
750 AddressFamilyBoolean
*dhcp
= data
, s
;
757 /* Note that this is mostly like
758 * config_parse_address_family_boolean(), except that it
759 * understands some old names for the enum values */
761 s
= address_family_boolean_from_string(rvalue
);
764 /* Previously, we had a slightly different enum here,
765 * support its values for compatbility. */
767 if (streq(rvalue
, "none"))
768 s
= ADDRESS_FAMILY_NO
;
769 else if (streq(rvalue
, "v4"))
770 s
= ADDRESS_FAMILY_IPV4
;
771 else if (streq(rvalue
, "v6"))
772 s
= ADDRESS_FAMILY_IPV6
;
773 else if (streq(rvalue
, "both"))
774 s
= ADDRESS_FAMILY_YES
;
776 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
785 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
786 [DHCP_CLIENT_ID_MAC
] = "mac",
787 [DHCP_CLIENT_ID_DUID
] = "duid"
790 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DHCPClientIdentifier
);
791 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DHCPClientIdentifier
, "Failed to parse client identifier type");
793 int config_parse_ipv6token(
795 const char *filename
,
798 unsigned section_line
,
805 union in_addr_union buffer
;
806 struct in6_addr
*token
= data
;
814 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
816 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
820 r
= in_addr_is_null(AF_INET6
, &buffer
);
822 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token can not be the ANY address, ignoring: %s", rvalue
);
826 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
827 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue
);
836 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
837 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
838 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
839 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
842 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
844 int config_parse_ipv6_privacy_extensions(
846 const char *filename
,
849 unsigned section_line
,
856 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
862 assert(ipv6_privacy_extensions
);
864 /* Our enum shall be a superset of booleans, hence first try
865 * to parse as boolean, and then as enum */
867 k
= parse_boolean(rvalue
);
869 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
871 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
873 IPv6PrivacyExtensions s
;
875 s
= ipv6_privacy_extensions_from_string(rvalue
);
878 if (streq(rvalue
, "kernel"))
879 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
881 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
886 *ipv6_privacy_extensions
= s
;
892 int config_parse_hostname(
894 const char *filename
,
897 unsigned section_line
,
904 char **hostname
= data
, *hn
= NULL
;
911 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
915 if (!hostname_is_valid(hn
, false)) {
916 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
922 *hostname
= hostname_cleanup(hn
);
926 int config_parse_timezone(
928 const char *filename
,
931 unsigned section_line
,
938 char **datap
= data
, *tz
= NULL
;
945 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
949 if (!timezone_is_valid(tz
)) {
950 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
961 int config_parse_dhcp_server_dns(
963 const char *filename
,
966 unsigned section_line
,
974 const char *p
= rvalue
;
982 _cleanup_free_
char *w
= NULL
;
983 struct in_addr a
, *m
;
985 r
= extract_first_word(&p
, &w
, NULL
, 0);
989 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
995 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
996 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1000 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
1004 m
[n
->n_dhcp_server_dns
++] = a
;
1005 n
->dhcp_server_dns
= m
;
1011 int config_parse_dhcp_server_ntp(
1013 const char *filename
,
1015 const char *section
,
1016 unsigned section_line
,
1024 const char *p
= rvalue
;
1032 _cleanup_free_
char *w
= NULL
;
1033 struct in_addr a
, *m
;
1035 r
= extract_first_word(&p
, &w
, NULL
, 0);
1039 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1045 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1046 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
1050 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
1054 m
[n
->n_dhcp_server_ntp
++] = a
;
1055 n
->dhcp_server_ntp
= m
;
1059 int config_parse_dns(
1061 const char *filename
,
1063 const char *section
,
1064 unsigned section_line
,
1071 Network
*n
= userdata
;
1079 _cleanup_free_
char *w
= NULL
;
1080 union in_addr_union a
;
1081 struct in_addr_data
*m
;
1084 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1088 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1094 r
= in_addr_from_string_auto(w
, &family
, &a
);
1096 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse dns server address, ignoring: %s", w
);
1100 m
= realloc(n
->dns
, (n
->n_dns
+ 1) * sizeof(struct in_addr_data
));
1104 m
[n
->n_dns
++] = (struct in_addr_data
) {
1115 int config_parse_dnssec_negative_trust_anchors(
1117 const char *filename
,
1119 const char *section
,
1120 unsigned section_line
,
1127 const char *p
= rvalue
;
1135 if (isempty(rvalue
)) {
1136 n
->dnssec_negative_trust_anchors
= set_free_free(n
->dnssec_negative_trust_anchors
);
1141 _cleanup_free_
char *w
= NULL
;
1143 r
= extract_first_word(&p
, &w
, NULL
, 0);
1145 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue
);
1151 r
= dns_name_is_valid(w
);
1153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name, ignoring.", w
);
1157 r
= set_ensure_allocated(&n
->dnssec_negative_trust_anchors
, &dns_name_hash_ops
);
1161 r
= set_put(n
->dnssec_negative_trust_anchors
, w
);
1171 int config_parse_ntp(
1173 const char *filename
,
1175 const char *section
,
1176 unsigned section_line
,
1190 if (isempty(rvalue
)) {
1196 _cleanup_free_
char *w
= NULL
;
1198 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1202 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract NTP server name, ignoring: %s", rvalue
);
1208 r
= dns_name_is_valid_or_address(w
);
1210 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name or IP address, ignoring.", w
);
1214 r
= strv_push(l
, w
);
1224 int config_parse_dhcp_route_table(const char *unit
,
1225 const char *filename
,
1227 const char *section
,
1228 unsigned section_line
,
1242 r
= safe_atou32(rvalue
, &rt
);
1244 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1245 "Unable to read RouteTable, ignoring assignment: %s", rvalue
);
1249 *((uint32_t *)data
) = rt
;
1254 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains
, dhcp_use_domains
, DHCPUseDomains
, "Failed to parse DHCP use domains setting");
1256 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
1257 [DHCP_USE_DOMAINS_NO
] = "no",
1258 [DHCP_USE_DOMAINS_ROUTE
] = "route",
1259 [DHCP_USE_DOMAINS_YES
] = "yes",
1262 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
1264 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode
, lldp_mode
, LLDPMode
, "Failed to parse LLDP= setting.");
1266 static const char* const lldp_mode_table
[_LLDP_MODE_MAX
] = {
1267 [LLDP_MODE_NO
] = "no",
1268 [LLDP_MODE_YES
] = "yes",
1269 [LLDP_MODE_ROUTERS_ONLY
] = "routers-only",
1272 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode
, LLDPMode
, LLDP_MODE_YES
);