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_domainname = true;
87 network->dhcp_routes = true;
88 network->dhcp_sendhost = true;
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);
171 netdev_unref(network->bridge);
173 netdev_unref(network->bond);
175 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i)
176 netdev_unref(netdev);
177 hashmap_free(network->stacked_netdevs);
179 while ((route = network->static_routes))
182 while ((address = network->static_addresses))
183 address_free(address);
185 hashmap_free(network->addresses_by_section);
186 hashmap_free(network->routes_by_section);
188 if (network->manager && network->manager->networks)
189 LIST_REMOVE(networks, network->manager->networks, network);
191 condition_free_list(network->match_host);
192 condition_free_list(network->match_virt);
193 condition_free_list(network->match_kernel);
194 condition_free_list(network->match_arch);
199 int network_get(Manager *manager, struct udev_device *device,
200 const char *ifname, const struct ether_addr *address,
207 LIST_FOREACH(networks, network, manager->networks) {
208 if (net_match_config(network->match_mac, network->match_path,
209 network->match_driver, network->match_type,
210 network->match_name, network->match_host,
211 network->match_virt, network->match_kernel,
214 udev_device_get_property_value(device, "ID_PATH"),
215 udev_device_get_driver(udev_device_get_parent(device)),
216 udev_device_get_property_value(device, "ID_NET_DRIVER"),
217 udev_device_get_devtype(device),
219 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
231 int network_apply(Manager *manager, Network *network, Link *link) {
234 link->network = network;
236 if (network->ipv4ll_route) {
239 r = route_new_static(network, 0, &route);
243 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
249 route->family = AF_INET;
250 route->dst_prefixlen = 16;
251 route->scope = RT_SCOPE_LINK;
252 route->metrics = IPV4LL_ROUTE_METRIC;
253 route->protocol = RTPROT_STATIC;
256 if (network->dns || network->ntp) {
265 int config_parse_netdev(const char *unit,
266 const char *filename,
269 unsigned section_line,
275 Network *network = userdata;
276 _cleanup_free_ char *kind_string = NULL;
287 kind_string = strdup(lvalue);
291 /* the keys are CamelCase versions of the kind */
292 for (p = kind_string; *p; p++)
295 kind = netdev_kind_from_string(kind_string);
296 if (kind == _NETDEV_KIND_INVALID) {
297 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
298 "Invalid NetDev kind: %s", lvalue);
302 r = netdev_get(network->manager, rvalue, &netdev);
304 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
305 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
309 if (netdev->kind != kind) {
310 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
311 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
316 case NETDEV_KIND_BRIDGE:
317 network->bridge = netdev;
320 case NETDEV_KIND_BOND:
321 network->bond = netdev;
324 case NETDEV_KIND_VLAN:
325 case NETDEV_KIND_MACVLAN:
326 case NETDEV_KIND_VXLAN:
327 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
329 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
330 "Can not add VLAN '%s' to network: %s",
331 rvalue, strerror(-r));
337 assert_not_reached("Can not parse NetDev");
345 int config_parse_tunnel(const char *unit,
346 const char *filename,
349 unsigned section_line,
355 Network *network = userdata;
364 r = netdev_get(network->manager, rvalue, &netdev);
366 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
367 "Tunnel is invalid, ignoring assignment: %s", rvalue);
371 if (netdev->kind != NETDEV_KIND_IPIP &&
372 netdev->kind != NETDEV_KIND_SIT &&
373 netdev->kind != NETDEV_KIND_GRE &&
374 netdev->kind != NETDEV_KIND_VTI) {
375 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
376 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
380 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
382 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
383 "Can not add VLAN '%s' to network: %s",
384 rvalue, strerror(-r));
393 static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
394 [DHCP_SUPPORT_NONE] = "none",
395 [DHCP_SUPPORT_BOTH] = "both",
396 [DHCP_SUPPORT_V4] = "v4",
397 [DHCP_SUPPORT_V6] = "v6",
400 DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
402 int config_parse_dhcp(
404 const char *filename,
407 unsigned section_line,
414 DHCPSupport *dhcp = data;
422 /* Our enum shall be a superset of booleans, hence first try
423 * to parse as boolean, and then as enum */
425 k = parse_boolean(rvalue);
427 *dhcp = DHCP_SUPPORT_BOTH;
429 *dhcp = DHCP_SUPPORT_NONE;
433 s = dhcp_support_from_string(rvalue);
435 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
445 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
446 [LLMNR_SUPPORT_NO] = "no",
447 [LLMNR_SUPPORT_YES] = "yes",
448 [LLMNR_SUPPORT_RESOLVE] = "resolve",
451 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
453 int config_parse_llmnr(
455 const char *filename,
458 unsigned section_line,
465 LLMNRSupport *llmnr = data;
473 /* Our enum shall be a superset of booleans, hence first try
474 * to parse as boolean, and then as enum */
476 k = parse_boolean(rvalue);
478 *llmnr = LLMNR_SUPPORT_YES;
480 *llmnr = LLMNR_SUPPORT_NO;
484 s = llmnr_support_from_string(rvalue);
486 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);