1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "path-util.h"
26 #include "conf-files.h"
27 #include "conf-parser.h"
30 #include "networkd-netdev.h"
31 #include "networkd-link.h"
32 #include "network-internal.h"
34 static int network_load_one(Manager
*manager
, const char *filename
) {
35 _cleanup_network_free_ Network
*network
= NULL
;
36 _cleanup_fclose_
FILE *file
= NULL
;
44 file
= fopen(filename
, "re");
52 if (null_or_empty_fd(fileno(file
))) {
53 log_debug("Skipping empty file: %s", filename
);
57 network
= new0(Network
, 1);
61 network
->manager
= manager
;
63 LIST_HEAD_INIT(network
->static_addresses
);
64 LIST_HEAD_INIT(network
->static_routes
);
65 LIST_HEAD_INIT(network
->static_fdb_entries
);
67 network
->stacked_netdevs
= hashmap_new(&string_hash_ops
);
68 if (!network
->stacked_netdevs
)
71 network
->addresses_by_section
= hashmap_new(NULL
);
72 if (!network
->addresses_by_section
)
75 network
->routes_by_section
= hashmap_new(NULL
);
76 if (!network
->routes_by_section
)
79 network
->fdb_entries_by_section
= hashmap_new(NULL
);
80 if (!network
->fdb_entries_by_section
)
83 network
->filename
= strdup(filename
);
84 if (!network
->filename
)
87 network
->dhcp
= DHCP_SUPPORT_NONE
;
88 network
->dhcp_ntp
= true;
89 network
->dhcp_dns
= true;
90 network
->dhcp_hostname
= true;
91 network
->dhcp_routes
= true;
92 network
->dhcp_sendhost
= true;
93 network
->dhcp_route_metric
= DHCP_ROUTE_METRIC
;
95 network
->llmnr
= LLMNR_SUPPORT_YES
;
97 r
= config_parse(NULL
, filename
, file
,
107 config_item_perf_lookup
, network_network_gperf_lookup
,
108 false, false, true, network
);
112 /* IPMasquerade=yes implies IPForward=yes */
113 if (network
->ip_masquerade
)
114 network
->ip_forward
= true;
116 LIST_PREPEND(networks
, manager
->networks
, network
);
118 LIST_FOREACH(routes
, route
, network
->static_routes
) {
119 if (!route
->family
) {
120 log_warning("Route section without Gateway field configured in %s. "
121 "Ignoring", filename
);
126 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
127 if (!address
->family
) {
128 log_warning("Address section without Address field configured in %s. "
129 "Ignoring", filename
);
139 int network_load(Manager
*manager
) {
141 _cleanup_strv_free_
char **files
= NULL
;
147 while ((network
= manager
->networks
))
148 network_free(network
);
150 r
= conf_files_list_strv(&files
, ".network", NULL
, network_dirs
);
152 return log_error_errno(r
, "Failed to enumerate network files: %m");
154 STRV_FOREACH_BACKWARDS(f
, files
) {
155 r
= network_load_one(manager
, *f
);
163 void network_free(Network
*network
) {
173 free(network
->filename
);
175 free(network
->match_mac
);
176 free(network
->match_path
);
177 free(network
->match_driver
);
178 free(network
->match_type
);
179 free(network
->match_name
);
181 free(network
->description
);
182 free(network
->dhcp_vendor_class_identifier
);
186 strv_free(network
->ntp
);
187 strv_free(network
->dns
);
188 strv_free(network
->domains
);
190 netdev_unref(network
->bridge
);
192 netdev_unref(network
->bond
);
194 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
195 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
196 netdev_unref(netdev
);
198 hashmap_free(network
->stacked_netdevs
);
200 while ((route
= network
->static_routes
))
203 while ((address
= network
->static_addresses
))
204 address_free(address
);
206 while ((fdb_entry
= network
->static_fdb_entries
))
207 fdb_entry_free(fdb_entry
);
209 hashmap_free(network
->addresses_by_section
);
210 hashmap_free(network
->routes_by_section
);
211 hashmap_free(network
->fdb_entries_by_section
);
213 if (network
->manager
&& network
->manager
->networks
)
214 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
216 condition_free_list(network
->match_host
);
217 condition_free_list(network
->match_virt
);
218 condition_free_list(network
->match_kernel
);
219 condition_free_list(network
->match_arch
);
224 int network_get(Manager
*manager
, struct udev_device
*device
,
225 const char *ifname
, const struct ether_addr
*address
,
232 LIST_FOREACH(networks
, network
, manager
->networks
) {
233 if (net_match_config(network
->match_mac
, network
->match_path
,
234 network
->match_driver
, network
->match_type
,
235 network
->match_name
, network
->match_host
,
236 network
->match_virt
, network
->match_kernel
,
239 udev_device_get_property_value(device
, "ID_PATH"),
240 udev_device_get_driver(udev_device_get_parent(device
)),
241 udev_device_get_property_value(device
, "ID_NET_DRIVER"),
242 udev_device_get_devtype(device
),
244 if (network
->match_name
) {
246 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
248 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
250 (void)safe_atou8(attr
, &name_assign_type
);
252 if (name_assign_type
== NET_NAME_ENUM
)
253 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
254 IFNAMSIZ
, ifname
, network
->filename
);
256 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
258 log_debug("%-*s: found matching network '%s'", IFNAMSIZ
, ifname
, network
->filename
);
270 int network_apply(Manager
*manager
, Network
*network
, Link
*link
) {
273 link
->network
= network
;
275 if (network
->ipv4ll_route
) {
278 r
= route_new_static(network
, 0, &route
);
282 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst_addr
.in
);
288 route
->family
= AF_INET
;
289 route
->dst_prefixlen
= 16;
290 route
->scope
= RT_SCOPE_LINK
;
291 route
->metrics
= IPV4LL_ROUTE_METRIC
;
292 route
->protocol
= RTPROT_STATIC
;
295 if (network
->dns
|| network
->ntp
) {
304 int config_parse_netdev(const char *unit
,
305 const char *filename
,
308 unsigned section_line
,
314 Network
*network
= userdata
;
315 _cleanup_free_
char *kind_string
= NULL
;
326 kind_string
= strdup(lvalue
);
330 /* the keys are CamelCase versions of the kind */
331 for (p
= kind_string
; *p
; p
++)
334 kind
= netdev_kind_from_string(kind_string
);
335 if (kind
== _NETDEV_KIND_INVALID
) {
336 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
337 "Invalid NetDev kind: %s", lvalue
);
341 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
343 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
344 "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
348 if (netdev
->kind
!= kind
) {
349 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
350 "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
355 case NETDEV_KIND_BRIDGE
:
356 network
->bridge
= netdev
;
359 case NETDEV_KIND_BOND
:
360 network
->bond
= netdev
;
363 case NETDEV_KIND_VLAN
:
364 case NETDEV_KIND_MACVLAN
:
365 case NETDEV_KIND_VXLAN
:
366 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
368 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
369 "Can not add VLAN '%s' to network: %s",
370 rvalue
, strerror(-r
));
376 assert_not_reached("Can not parse NetDev");
384 int config_parse_domains(const char *unit
,
385 const char *filename
,
388 unsigned section_line
,
394 Network
*network
= userdata
;
395 char ***domains
= data
;
399 r
= config_parse_strv(unit
, filename
, line
, section
, section_line
,
400 lvalue
, ltype
, rvalue
, domains
, userdata
);
405 network
->wildcard_domain
= !!strv_find(*domains
, "*");
407 STRV_FOREACH(domain
, *domains
) {
408 if (is_localhost(*domain
))
409 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain
);
410 else if (!hostname_is_valid(*domain
)) {
411 if (!streq(*domain
, "*"))
412 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
, "domain name is not valid, ignoring assignment: %s", *domain
);
416 strv_remove(*domains
, *domain
);
418 /* We removed one entry, make sure we don't skip the next one */
425 int config_parse_tunnel(const char *unit
,
426 const char *filename
,
429 unsigned section_line
,
435 Network
*network
= userdata
;
444 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
446 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
447 "Tunnel is invalid, ignoring assignment: %s", rvalue
);
451 if (netdev
->kind
!= NETDEV_KIND_IPIP
&&
452 netdev
->kind
!= NETDEV_KIND_SIT
&&
453 netdev
->kind
!= NETDEV_KIND_GRE
&&
454 netdev
->kind
!= NETDEV_KIND_VTI
) {
455 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
456 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
460 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
462 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
463 "Can not add VLAN '%s' to network: %s",
464 rvalue
, strerror(-r
));
473 static const char* const dhcp_support_table
[_DHCP_SUPPORT_MAX
] = {
474 [DHCP_SUPPORT_NONE
] = "none",
475 [DHCP_SUPPORT_BOTH
] = "both",
476 [DHCP_SUPPORT_V4
] = "v4",
477 [DHCP_SUPPORT_V6
] = "v6",
480 DEFINE_STRING_TABLE_LOOKUP(dhcp_support
, DHCPSupport
);
482 int config_parse_dhcp(
484 const char *filename
,
487 unsigned section_line
,
494 DHCPSupport
*dhcp
= data
;
502 /* Our enum shall be a superset of booleans, hence first try
503 * to parse as boolean, and then as enum */
505 k
= parse_boolean(rvalue
);
507 *dhcp
= DHCP_SUPPORT_BOTH
;
509 *dhcp
= DHCP_SUPPORT_NONE
;
513 s
= dhcp_support_from_string(rvalue
);
515 log_syntax(unit
, LOG_ERR
, filename
, line
, -s
, "Failed to parse DHCP option, ignoring: %s", rvalue
);
525 static const char* const llmnr_support_table
[_LLMNR_SUPPORT_MAX
] = {
526 [LLMNR_SUPPORT_NO
] = "no",
527 [LLMNR_SUPPORT_YES
] = "yes",
528 [LLMNR_SUPPORT_RESOLVE
] = "resolve",
531 DEFINE_STRING_TABLE_LOOKUP(llmnr_support
, LLMNRSupport
);
533 int config_parse_llmnr(
535 const char *filename
,
538 unsigned section_line
,
545 LLMNRSupport
*llmnr
= data
;
553 /* Our enum shall be a superset of booleans, hence first try
554 * to parse as boolean, and then as enum */
556 k
= parse_boolean(rvalue
);
558 *llmnr
= LLMNR_SUPPORT_YES
;
560 *llmnr
= LLMNR_SUPPORT_NO
;
564 s
= llmnr_support_from_string(rvalue
);
566 log_syntax(unit
, LOG_ERR
, filename
, line
, -s
, "Failed to parse LLMNR option, ignoring: %s", rvalue
);