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/>.
26 #include "networkd-netdev.h"
27 #include "networkd-link.h"
28 #include "network-internal.h"
29 #include "path-util.h"
30 #include "conf-files.h"
31 #include "conf-parser.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);
66 network->stacked_netdevs = hashmap_new(&string_hash_ops);
67 if (!network->stacked_netdevs)
70 network->addresses_by_section = hashmap_new(NULL);
71 if (!network->addresses_by_section)
74 network->routes_by_section = hashmap_new(NULL);
75 if (!network->routes_by_section)
78 network->filename = strdup(filename);
79 if (!network->filename)
82 network->dhcp = DHCP_SUPPORT_NONE;
83 network->dhcp_ntp = true;
84 network->dhcp_dns = true;
85 network->dhcp_hostname = true;
86 network->dhcp_routes = true;
87 network->dhcp_sendhost = true;
88 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
90 network->llmnr = LLMNR_SUPPORT_YES;
92 r = config_parse(NULL, filename, file,
93 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
94 config_item_perf_lookup, network_network_gperf_lookup,
95 false, false, true, network);
99 LIST_PREPEND(networks, manager->networks, network);
101 LIST_FOREACH(routes, route, network->static_routes) {
102 if (!route->family) {
103 log_warning("Route section without Gateway field configured in %s. "
104 "Ignoring", filename);
109 LIST_FOREACH(addresses, address, network->static_addresses) {
110 if (!address->family) {
111 log_warning("Address section without Address field configured in %s. "
112 "Ignoring", filename);
122 int network_load(Manager *manager) {
124 _cleanup_strv_free_ char **files = NULL;
130 while ((network = manager->networks))
131 network_free(network);
133 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
135 log_error("Failed to enumerate network files: %s", strerror(-r));
139 STRV_FOREACH_BACKWARDS(f, files) {
140 r = network_load_one(manager, *f);
148 void network_free(Network *network) {
157 free(network->filename);
159 free(network->match_mac);
160 free(network->match_path);
161 free(network->match_driver);
162 free(network->match_type);
163 free(network->match_name);
165 free(network->description);
166 free(network->dhcp_vendor_class_identifier);
168 strv_free(network->ntp);
169 strv_free(network->dns);
170 strv_free(network->domains);
172 netdev_unref(network->bridge);
174 netdev_unref(network->bond);
176 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
177 hashmap_remove(network->stacked_netdevs, netdev->ifname);
178 netdev_unref(netdev);
180 hashmap_free(network->stacked_netdevs);
182 while ((route = network->static_routes))
185 while ((address = network->static_addresses))
186 address_free(address);
188 hashmap_free(network->addresses_by_section);
189 hashmap_free(network->routes_by_section);
191 if (network->manager && network->manager->networks)
192 LIST_REMOVE(networks, network->manager->networks, network);
194 condition_free_list(network->match_host);
195 condition_free_list(network->match_virt);
196 condition_free_list(network->match_kernel);
197 condition_free_list(network->match_arch);
202 int network_get(Manager *manager, struct udev_device *device,
203 const char *ifname, const struct ether_addr *address,
210 LIST_FOREACH(networks, network, manager->networks) {
211 if (net_match_config(network->match_mac, network->match_path,
212 network->match_driver, network->match_type,
213 network->match_name, network->match_host,
214 network->match_virt, network->match_kernel,
217 udev_device_get_property_value(device, "ID_PATH"),
218 udev_device_get_driver(udev_device_get_parent(device)),
219 udev_device_get_property_value(device, "ID_NET_DRIVER"),
220 udev_device_get_devtype(device),
222 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
234 int network_apply(Manager *manager, Network *network, Link *link) {
237 link->network = network;
239 if (network->ipv4ll_route) {
242 r = route_new_static(network, 0, &route);
246 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
252 route->family = AF_INET;
253 route->dst_prefixlen = 16;
254 route->scope = RT_SCOPE_LINK;
255 route->metrics = IPV4LL_ROUTE_METRIC;
256 route->protocol = RTPROT_STATIC;
259 if (network->dns || network->ntp) {
268 int config_parse_netdev(const char *unit,
269 const char *filename,
272 unsigned section_line,
278 Network *network = userdata;
279 _cleanup_free_ char *kind_string = NULL;
290 kind_string = strdup(lvalue);
294 /* the keys are CamelCase versions of the kind */
295 for (p = kind_string; *p; p++)
298 kind = netdev_kind_from_string(kind_string);
299 if (kind == _NETDEV_KIND_INVALID) {
300 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
301 "Invalid NetDev kind: %s", lvalue);
305 r = netdev_get(network->manager, rvalue, &netdev);
307 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
308 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
312 if (netdev->kind != kind) {
313 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
314 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
319 case NETDEV_KIND_BRIDGE:
320 network->bridge = netdev;
323 case NETDEV_KIND_BOND:
324 network->bond = netdev;
327 case NETDEV_KIND_VLAN:
328 case NETDEV_KIND_MACVLAN:
329 case NETDEV_KIND_VXLAN:
330 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
333 "Can not add VLAN '%s' to network: %s",
334 rvalue, strerror(-r));
340 assert_not_reached("Can not parse NetDev");
348 int config_parse_domains(const char *unit,
349 const char *filename,
352 unsigned section_line,
358 Network *network = userdata;
359 char ***domains = data;
363 r = config_parse_strv(unit, filename, line, section, section_line,
364 lvalue, ltype, rvalue, domains, userdata);
369 network->wildcard_domain = !!strv_find(*domains, "*");
371 STRV_FOREACH(domain, *domains) {
372 if (is_localhost(*domain))
373 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
374 else if (!hostname_is_valid(*domain)) {
375 if (!streq(*domain, "*"))
376 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
380 strv_remove(*domains, *domain);
382 /* We removed one entry, make sure we don't skip the next one */
389 int config_parse_tunnel(const char *unit,
390 const char *filename,
393 unsigned section_line,
399 Network *network = userdata;
408 r = netdev_get(network->manager, rvalue, &netdev);
410 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
411 "Tunnel is invalid, ignoring assignment: %s", rvalue);
415 if (netdev->kind != NETDEV_KIND_IPIP &&
416 netdev->kind != NETDEV_KIND_SIT &&
417 netdev->kind != NETDEV_KIND_GRE &&
418 netdev->kind != NETDEV_KIND_VTI) {
419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
420 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
424 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
426 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
427 "Can not add VLAN '%s' to network: %s",
428 rvalue, strerror(-r));
437 static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
438 [DHCP_SUPPORT_NONE] = "none",
439 [DHCP_SUPPORT_BOTH] = "both",
440 [DHCP_SUPPORT_V4] = "v4",
441 [DHCP_SUPPORT_V6] = "v6",
444 DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
446 int config_parse_dhcp(
448 const char *filename,
451 unsigned section_line,
458 DHCPSupport *dhcp = data;
466 /* Our enum shall be a superset of booleans, hence first try
467 * to parse as boolean, and then as enum */
469 k = parse_boolean(rvalue);
471 *dhcp = DHCP_SUPPORT_BOTH;
473 *dhcp = DHCP_SUPPORT_NONE;
477 s = dhcp_support_from_string(rvalue);
479 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
489 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
490 [LLMNR_SUPPORT_NO] = "no",
491 [LLMNR_SUPPORT_YES] = "yes",
492 [LLMNR_SUPPORT_RESOLVE] = "resolve",
495 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
497 int config_parse_llmnr(
499 const char *filename,
502 unsigned section_line,
509 LLMNRSupport *llmnr = data;
517 /* Our enum shall be a superset of booleans, hence first try
518 * to parse as boolean, and then as enum */
520 k = parse_boolean(rvalue);
522 *llmnr = LLMNR_SUPPORT_YES;
524 *llmnr = LLMNR_SUPPORT_NO;
528 s = llmnr_support_from_string(rvalue);
530 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);