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_func, string_compare_func);
67 if (!network->stacked_netdevs)
70 network->addresses_by_section = hashmap_new(NULL, NULL);
71 if (!network->addresses_by_section)
74 network->routes_by_section = hashmap_new(NULL, 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;
89 network->llmnr = LLMNR_SUPPORT_YES;
91 r = config_parse(NULL, filename, file,
92 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
93 config_item_perf_lookup, network_network_gperf_lookup,
94 false, false, true, network);
98 LIST_PREPEND(networks, manager->networks, network);
100 LIST_FOREACH(routes, route, network->static_routes) {
101 if (!route->family) {
102 log_warning("Route section without Gateway field configured in %s. "
103 "Ignoring", filename);
108 LIST_FOREACH(addresses, address, network->static_addresses) {
109 if (!address->family) {
110 log_warning("Address section without Address field configured in %s. "
111 "Ignoring", filename);
121 int network_load(Manager *manager) {
123 _cleanup_strv_free_ char **files = NULL;
129 while ((network = manager->networks))
130 network_free(network);
132 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
134 log_error("Failed to enumerate network files: %s", strerror(-r));
138 STRV_FOREACH_BACKWARDS(f, files) {
139 r = network_load_one(manager, *f);
147 void network_free(Network *network) {
156 free(network->filename);
158 free(network->match_mac);
159 free(network->match_path);
160 free(network->match_driver);
161 free(network->match_type);
162 free(network->match_name);
164 free(network->description);
165 free(network->dhcp_vendor_class_identifier);
167 strv_free(network->ntp);
168 strv_free(network->dns);
170 netdev_unref(network->bridge);
172 netdev_unref(network->bond);
174 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i)
175 netdev_unref(netdev);
176 hashmap_free(network->stacked_netdevs);
178 while ((route = network->static_routes))
181 while ((address = network->static_addresses))
182 address_free(address);
184 hashmap_free(network->addresses_by_section);
185 hashmap_free(network->routes_by_section);
187 if (network->manager && network->manager->networks)
188 LIST_REMOVE(networks, network->manager->networks, network);
190 condition_free_list(network->match_host);
191 condition_free_list(network->match_virt);
192 condition_free_list(network->match_kernel);
193 condition_free_list(network->match_arch);
198 int network_get(Manager *manager, struct udev_device *device,
199 const char *ifname, const struct ether_addr *address,
206 LIST_FOREACH(networks, network, manager->networks) {
207 if (net_match_config(network->match_mac, network->match_path,
208 network->match_driver, network->match_type,
209 network->match_name, network->match_host,
210 network->match_virt, network->match_kernel,
213 udev_device_get_property_value(device, "ID_PATH"),
214 udev_device_get_driver(udev_device_get_parent(device)),
215 udev_device_get_property_value(device, "ID_NET_DRIVER"),
216 udev_device_get_devtype(device),
218 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
230 int network_apply(Manager *manager, Network *network, Link *link) {
233 link->network = network;
235 if (network->ipv4ll_route) {
238 r = route_new_static(network, 0, &route);
242 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
248 route->family = AF_INET;
249 route->dst_prefixlen = 16;
250 route->scope = RT_SCOPE_LINK;
251 route->metrics = IPV4LL_ROUTE_METRIC;
252 route->protocol = RTPROT_STATIC;
255 if (network->dns || network->ntp) {
264 int config_parse_netdev(const char *unit,
265 const char *filename,
268 unsigned section_line,
274 Network *network = userdata;
275 _cleanup_free_ char *kind_string = NULL;
286 kind_string = strdup(lvalue);
290 /* the keys are CamelCase versions of the kind */
291 for (p = kind_string; *p; p++)
294 kind = netdev_kind_from_string(kind_string);
295 if (kind == _NETDEV_KIND_INVALID) {
296 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
297 "Invalid NetDev kind: %s", lvalue);
301 r = netdev_get(network->manager, rvalue, &netdev);
303 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
304 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
308 if (netdev->kind != kind) {
309 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
310 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
315 case NETDEV_KIND_BRIDGE:
316 network->bridge = netdev;
319 case NETDEV_KIND_BOND:
320 network->bond = netdev;
323 case NETDEV_KIND_VLAN:
324 case NETDEV_KIND_MACVLAN:
325 case NETDEV_KIND_VXLAN:
326 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
328 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
329 "Can not add VLAN '%s' to network: %s",
330 rvalue, strerror(-r));
336 assert_not_reached("Can not parse NetDev");
344 int config_parse_domains(const char *unit,
345 const char *filename,
348 unsigned section_line,
354 Network *network = userdata;
355 char ***domains = data;
359 r = config_parse_strv(unit, filename, line, section, section_line,
360 lvalue, ltype, rvalue, domains, userdata);
366 if (strv_isempty(*domains))
367 network->wildcard_domain = false;
368 else if (strv_find(*domains, "*"))
369 network->wildcard_domain = true;
371 STRV_FOREACH(domain, *domains)
372 if (is_localhost(*domain) || !hostname_is_valid(*domain))
373 strv_remove(*domains, *domain);
378 int config_parse_tunnel(const char *unit,
379 const char *filename,
382 unsigned section_line,
388 Network *network = userdata;
397 r = netdev_get(network->manager, rvalue, &netdev);
399 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
400 "Tunnel is invalid, ignoring assignment: %s", rvalue);
404 if (netdev->kind != NETDEV_KIND_IPIP &&
405 netdev->kind != NETDEV_KIND_SIT &&
406 netdev->kind != NETDEV_KIND_GRE &&
407 netdev->kind != NETDEV_KIND_VTI) {
408 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
409 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
413 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
415 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
416 "Can not add VLAN '%s' to network: %s",
417 rvalue, strerror(-r));
426 static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
427 [DHCP_SUPPORT_NONE] = "none",
428 [DHCP_SUPPORT_BOTH] = "both",
429 [DHCP_SUPPORT_V4] = "v4",
430 [DHCP_SUPPORT_V6] = "v6",
433 DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
435 int config_parse_dhcp(
437 const char *filename,
440 unsigned section_line,
447 DHCPSupport *dhcp = data;
455 /* Our enum shall be a superset of booleans, hence first try
456 * to parse as boolean, and then as enum */
458 k = parse_boolean(rvalue);
460 *dhcp = DHCP_SUPPORT_BOTH;
462 *dhcp = DHCP_SUPPORT_NONE;
466 s = dhcp_support_from_string(rvalue);
468 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
478 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
479 [LLMNR_SUPPORT_NO] = "no",
480 [LLMNR_SUPPORT_YES] = "yes",
481 [LLMNR_SUPPORT_RESOLVE] = "resolve",
484 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
486 int config_parse_llmnr(
488 const char *filename,
491 unsigned section_line,
498 LLMNRSupport *llmnr = data;
506 /* Our enum shall be a superset of booleans, hence first try
507 * to parse as boolean, and then as enum */
509 k = parse_boolean(rvalue);
511 *llmnr = LLMNR_SUPPORT_YES;
513 *llmnr = LLMNR_SUPPORT_NO;
517 s = llmnr_support_from_string(rvalue);
519 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);