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_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 r = config_parse(NULL, filename, file,
91 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
92 config_item_perf_lookup, network_network_gperf_lookup,
93 false, false, true, network);
97 LIST_PREPEND(networks, manager->networks, network);
99 LIST_FOREACH(routes, route, network->static_routes) {
100 if (!route->family) {
101 log_warning("Route section without Gateway field configured in %s. "
102 "Ignoring", filename);
107 LIST_FOREACH(addresses, address, network->static_addresses) {
108 if (!address->family) {
109 log_warning("Address section without Address field configured in %s. "
110 "Ignoring", filename);
120 int network_load(Manager *manager) {
122 _cleanup_strv_free_ char **files = NULL;
128 while ((network = manager->networks))
129 network_free(network);
131 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
133 log_error("Failed to enumerate network files: %s", strerror(-r));
137 STRV_FOREACH_BACKWARDS(f, files) {
138 r = network_load_one(manager, *f);
146 void network_free(Network *network) {
155 free(network->filename);
157 free(network->match_mac);
158 free(network->match_path);
159 free(network->match_driver);
160 free(network->match_type);
161 free(network->match_name);
163 free(network->description);
164 free(network->dhcp_vendor_class_identifier);
166 strv_free(network->ntp);
167 strv_free(network->dns);
169 netdev_unref(network->bridge);
171 netdev_unref(network->bond);
173 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i)
174 netdev_unref(netdev);
175 hashmap_free(network->stacked_netdevs);
177 while ((route = network->static_routes))
180 while ((address = network->static_addresses))
181 address_free(address);
183 hashmap_free(network->addresses_by_section);
184 hashmap_free(network->routes_by_section);
186 if (network->manager && network->manager->networks)
187 LIST_REMOVE(networks, network->manager->networks, network);
189 condition_free_list(network->match_host);
190 condition_free_list(network->match_virt);
191 condition_free_list(network->match_kernel);
192 condition_free_list(network->match_arch);
197 int network_get(Manager *manager, struct udev_device *device,
198 const char *ifname, const struct ether_addr *address,
205 LIST_FOREACH(networks, network, manager->networks) {
206 if (net_match_config(network->match_mac, network->match_path,
207 network->match_driver, network->match_type,
208 network->match_name, network->match_host,
209 network->match_virt, network->match_kernel,
212 udev_device_get_property_value(device, "ID_PATH"),
213 udev_device_get_driver(udev_device_get_parent(device)),
214 udev_device_get_property_value(device, "ID_NET_DRIVER"),
215 udev_device_get_devtype(device),
217 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
229 int network_apply(Manager *manager, Network *network, Link *link) {
232 link->network = network;
234 if (network->ipv4ll_route) {
237 r = route_new_static(network, 0, &route);
241 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
247 route->family = AF_INET;
248 route->dst_prefixlen = 16;
249 route->scope = RT_SCOPE_LINK;
250 route->metrics = IPV4LL_ROUTE_METRIC;
251 route->protocol = RTPROT_STATIC;
254 if (network->dns || network->ntp) {
263 int config_parse_netdev(const char *unit,
264 const char *filename,
267 unsigned section_line,
273 Network *network = userdata;
274 _cleanup_free_ char *kind_string = NULL;
285 kind_string = strdup(lvalue);
289 /* the keys are CamelCase versions of the kind */
290 for (p = kind_string; *p; p++)
293 kind = netdev_kind_from_string(kind_string);
294 if (kind == _NETDEV_KIND_INVALID) {
295 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
296 "Invalid NetDev kind: %s", lvalue);
300 r = netdev_get(network->manager, rvalue, &netdev);
302 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
303 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
307 if (netdev->kind != kind) {
308 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
309 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
314 case NETDEV_KIND_BRIDGE:
315 network->bridge = netdev;
318 case NETDEV_KIND_BOND:
319 network->bond = netdev;
322 case NETDEV_KIND_VLAN:
323 case NETDEV_KIND_MACVLAN:
324 case NETDEV_KIND_VXLAN:
325 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
327 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
328 "Can not add VLAN '%s' to network: %s",
329 rvalue, strerror(-r));
335 assert_not_reached("Can not parse NetDev");
343 int config_parse_tunnel(const char *unit,
344 const char *filename,
347 unsigned section_line,
353 Network *network = userdata;
362 r = netdev_get(network->manager, rvalue, &netdev);
364 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
365 "Tunnel is invalid, ignoring assignment: %s", rvalue);
369 if (netdev->kind != NETDEV_KIND_IPIP &&
370 netdev->kind != NETDEV_KIND_SIT &&
371 netdev->kind != NETDEV_KIND_GRE &&
372 netdev->kind != NETDEV_KIND_VTI) {
373 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
374 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
378 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
380 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
381 "Can not add VLAN '%s' to network: %s",
382 rvalue, strerror(-r));