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 "network-internal.h"
28 #include "path-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
33 static int network_load_one(Manager *manager, const char *filename) {
34 _cleanup_network_free_ Network *network = NULL;
35 _cleanup_fclose_ FILE *file = NULL;
43 file = fopen(filename, "re");
51 if (null_or_empty_fd(fileno(file))) {
52 log_debug("Skipping empty file: %s", filename);
56 network = new0(Network, 1);
60 network->manager = manager;
62 LIST_HEAD_INIT(network->static_addresses);
63 LIST_HEAD_INIT(network->static_routes);
65 network->stacked_netdevs = hashmap_new(string_hash_func, string_compare_func);
66 if (!network->stacked_netdevs)
69 network->addresses_by_section = hashmap_new(NULL, NULL);
70 if (!network->addresses_by_section)
73 network->routes_by_section = hashmap_new(NULL, NULL);
74 if (!network->routes_by_section)
77 network->filename = strdup(filename);
78 if (!network->filename)
81 network->ipv4ll_route = true;
83 network->dhcp = DHCP_SUPPORT_NONE;
84 network->dhcp_ntp = true;
85 network->dhcp_dns = true;
86 network->dhcp_hostname = true;
87 network->dhcp_domainname = true;
88 network->dhcp_routes = true;
89 network->dhcp_sendhost = true;
91 network->llmnr = LLMNR_SUPPORT_YES;
93 r = config_parse(NULL, filename, file,
94 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
95 config_item_perf_lookup, network_network_gperf_lookup,
96 false, false, true, network);
100 LIST_PREPEND(networks, manager->networks, network);
102 LIST_FOREACH(routes, route, network->static_routes) {
103 if (!route->family) {
104 log_warning("Route section without Gateway field configured in %s. "
105 "Ignoring", filename);
110 LIST_FOREACH(addresses, address, network->static_addresses) {
111 if (!address->family) {
112 log_warning("Address section without Address field configured in %s. "
113 "Ignoring", filename);
123 int network_load(Manager *manager) {
125 _cleanup_strv_free_ char **files = NULL;
131 while ((network = manager->networks))
132 network_free(network);
134 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
136 log_error("Failed to enumerate network files: %s", strerror(-r));
140 STRV_FOREACH_BACKWARDS(f, files) {
141 r = network_load_one(manager, *f);
149 void network_free(Network *network) {
158 free(network->filename);
160 free(network->match_mac);
161 free(network->match_path);
162 free(network->match_driver);
163 free(network->match_type);
164 free(network->match_name);
166 free(network->description);
167 free(network->dhcp_vendor_class_identifier);
169 strv_free(network->ntp);
170 strv_free(network->dns);
172 netdev_unref(network->bridge);
174 netdev_unref(network->bond);
176 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i)
177 netdev_unref(netdev);
178 hashmap_free(network->stacked_netdevs);
180 while ((route = network->static_routes))
183 while ((address = network->static_addresses))
184 address_free(address);
186 hashmap_free(network->addresses_by_section);
187 hashmap_free(network->routes_by_section);
189 if (network->manager && network->manager->networks)
190 LIST_REMOVE(networks, network->manager->networks, network);
192 condition_free_list(network->match_host);
193 condition_free_list(network->match_virt);
194 condition_free_list(network->match_kernel);
195 condition_free_list(network->match_arch);
200 int network_get(Manager *manager, struct udev_device *device,
201 const char *ifname, const struct ether_addr *address,
208 LIST_FOREACH(networks, network, manager->networks) {
209 if (net_match_config(network->match_mac, network->match_path,
210 network->match_driver, network->match_type,
211 network->match_name, network->match_host,
212 network->match_virt, network->match_kernel,
215 udev_device_get_property_value(device, "ID_PATH"),
216 udev_device_get_driver(udev_device_get_parent(device)),
217 udev_device_get_property_value(device, "ID_NET_DRIVER"),
218 udev_device_get_devtype(device),
220 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
232 int network_apply(Manager *manager, Network *network, Link *link) {
235 link->network = network;
237 if (network->ipv4ll_route) {
240 r = route_new_static(network, 0, &route);
244 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
250 route->family = AF_INET;
251 route->dst_prefixlen = 16;
252 route->scope = RT_SCOPE_LINK;
253 route->metrics = IPV4LL_ROUTE_METRIC;
254 route->protocol = RTPROT_STATIC;
257 if (network->dns || network->ntp) {
266 int config_parse_netdev(const char *unit,
267 const char *filename,
270 unsigned section_line,
276 Network *network = userdata;
277 _cleanup_free_ char *kind_string = NULL;
288 kind_string = strdup(lvalue);
292 /* the keys are CamelCase versions of the kind */
293 for (p = kind_string; *p; p++)
296 kind = netdev_kind_from_string(kind_string);
297 if (kind == _NETDEV_KIND_INVALID) {
298 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
299 "Invalid NetDev kind: %s", lvalue);
303 r = netdev_get(network->manager, rvalue, &netdev);
305 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
306 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
310 if (netdev->kind != kind) {
311 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
312 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
317 case NETDEV_KIND_BRIDGE:
318 network->bridge = netdev;
321 case NETDEV_KIND_BOND:
322 network->bond = netdev;
325 case NETDEV_KIND_VLAN:
326 case NETDEV_KIND_MACVLAN:
327 case NETDEV_KIND_VXLAN:
328 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
330 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
331 "Can not add VLAN '%s' to network: %s",
332 rvalue, strerror(-r));
338 assert_not_reached("Can not parse NetDev");
346 int config_parse_tunnel(const char *unit,
347 const char *filename,
350 unsigned section_line,
356 Network *network = userdata;
365 r = netdev_get(network->manager, rvalue, &netdev);
367 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
368 "Tunnel is invalid, ignoring assignment: %s", rvalue);
372 if (netdev->kind != NETDEV_KIND_IPIP &&
373 netdev->kind != NETDEV_KIND_SIT &&
374 netdev->kind != NETDEV_KIND_GRE &&
375 netdev->kind != NETDEV_KIND_VTI) {
376 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
377 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
381 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
383 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
384 "Can not add VLAN '%s' to network: %s",
385 rvalue, strerror(-r));
394 static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
395 [DHCP_SUPPORT_NONE] = "none",
396 [DHCP_SUPPORT_BOTH] = "both",
397 [DHCP_SUPPORT_V4] = "v4",
398 [DHCP_SUPPORT_V6] = "v6",
401 DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
403 int config_parse_dhcp(
405 const char *filename,
408 unsigned section_line,
415 DHCPSupport *dhcp = data;
423 /* Our enum shall be a superset of booleans, hence first try
424 * to parse as boolean, and then as enum */
426 k = parse_boolean(rvalue);
428 *dhcp = DHCP_SUPPORT_BOTH;
430 *dhcp = DHCP_SUPPORT_NONE;
434 s = dhcp_support_from_string(rvalue);
436 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
446 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
447 [LLMNR_SUPPORT_NO] = "no",
448 [LLMNR_SUPPORT_YES] = "yes",
449 [LLMNR_SUPPORT_RESOLVE] = "resolve",
452 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
454 int config_parse_llmnr(
456 const char *filename,
459 unsigned section_line,
466 LLMNRSupport *llmnr = data;
474 /* Our enum shall be a superset of booleans, hence first try
475 * to parse as boolean, and then as enum */
477 k = parse_boolean(rvalue);
479 *llmnr = LLMNR_SUPPORT_YES;
481 *llmnr = LLMNR_SUPPORT_NO;
485 s = llmnr_support_from_string(rvalue);
487 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);