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->vlans = hashmap_new(string_hash_func, string_compare_func);
69 network->macvlans = hashmap_new(string_hash_func, string_compare_func);
70 if (!network->macvlans)
73 network->vxlans = hashmap_new(string_hash_func, string_compare_func);
77 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
78 if (!network->addresses_by_section)
81 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
82 if (!network->routes_by_section)
85 network->filename = strdup(filename);
86 if (!network->filename)
89 network->ipv4ll_route = true;
91 network->dhcp_ntp = true;
92 network->dhcp_dns = true;
93 network->dhcp_hostname = true;
94 network->dhcp_domainname = true;
95 network->dhcp_routes = true;
96 network->dhcp_sendhost = true;
98 r = config_parse(NULL, filename, file,
99 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
100 config_item_perf_lookup, network_network_gperf_lookup,
101 false, false, true, network);
105 LIST_PREPEND(networks, manager->networks, network);
107 LIST_FOREACH(routes, route, network->static_routes) {
108 if (!route->family) {
109 log_warning("Route section without Gateway field configured in %s. "
110 "Ignoring", filename);
115 LIST_FOREACH(addresses, address, network->static_addresses) {
116 if (!address->family) {
117 log_warning("Address section without Address field configured in %s. "
118 "Ignoring", filename);
128 int network_load(Manager *manager) {
130 _cleanup_strv_free_ char **files = NULL;
136 while ((network = manager->networks))
137 network_free(network);
139 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
141 log_error("Failed to enumerate network files: %s", strerror(-r));
145 STRV_FOREACH_BACKWARDS(f, files) {
146 r = network_load_one(manager, *f);
154 void network_free(Network *network) {
163 free(network->filename);
165 free(network->match_mac);
166 free(network->match_path);
167 free(network->match_driver);
168 free(network->match_type);
169 free(network->match_name);
171 free(network->description);
172 free(network->dhcp_vendor_class_identifier);
174 strv_free(network->ntp);
175 strv_free(network->dns);
177 netdev_unref(network->bridge);
179 netdev_unref(network->bond);
181 netdev_unref(network->tunnel);
183 HASHMAP_FOREACH(netdev, network->vlans, i)
184 netdev_unref(netdev);
185 hashmap_free(network->vlans);
187 HASHMAP_FOREACH(netdev, network->macvlans, i)
188 netdev_unref(netdev);
189 hashmap_free(network->macvlans);
191 HASHMAP_FOREACH(netdev, network->vxlans, i)
192 netdev_unref(netdev);
193 hashmap_free(network->vxlans);
195 while ((route = network->static_routes))
198 while ((address = network->static_addresses))
199 address_free(address);
201 hashmap_free(network->addresses_by_section);
202 hashmap_free(network->routes_by_section);
204 if (network->manager && network->manager->networks)
205 LIST_REMOVE(networks, network->manager->networks, network);
207 condition_free_list(network->match_host);
208 condition_free_list(network->match_virt);
209 condition_free_list(network->match_kernel);
210 condition_free_list(network->match_arch);
215 int network_get(Manager *manager, struct udev_device *device,
216 const char *ifname, const struct ether_addr *address,
223 LIST_FOREACH(networks, network, manager->networks) {
224 if (net_match_config(network->match_mac, network->match_path,
225 network->match_driver, network->match_type,
226 network->match_name, network->match_host,
227 network->match_virt, network->match_kernel,
230 udev_device_get_property_value(device, "ID_PATH"),
231 udev_device_get_driver(udev_device_get_parent(device)),
232 udev_device_get_property_value(device, "ID_NET_DRIVER"),
233 udev_device_get_devtype(device),
235 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
247 int network_apply(Manager *manager, Network *network, Link *link) {
250 link->network = network;
252 if (network->ipv4ll_route) {
255 r = route_new_static(network, 0, &route);
259 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
265 route->family = AF_INET;
266 route->dst_prefixlen = 16;
267 route->scope = RT_SCOPE_LINK;
268 route->metrics = IPV4LL_ROUTE_METRIC;
269 route->protocol = RTPROT_STATIC;
272 if (network->dns || network->ntp) {
281 int config_parse_netdev(const char *unit,
282 const char *filename,
285 unsigned section_line,
291 Network *network = userdata;
292 _cleanup_free_ char *kind_string = NULL;
303 kind_string = strdup(lvalue);
307 /* the keys are CamelCase versions of the kind */
308 for (p = kind_string; *p; p++)
311 kind = netdev_kind_from_string(kind_string);
312 if (kind == _NETDEV_KIND_INVALID) {
313 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
314 "Invalid NetDev kind: %s", lvalue);
318 r = netdev_get(network->manager, rvalue, &netdev);
320 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
321 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
325 if (netdev->kind != kind) {
326 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
332 case NETDEV_KIND_BRIDGE:
333 network->bridge = netdev;
336 case NETDEV_KIND_BOND:
337 network->bond = netdev;
340 case NETDEV_KIND_VLAN:
341 r = hashmap_put(network->vlans, netdev->ifname, netdev);
343 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
344 "Can not add VLAN '%s' to network: %s",
345 rvalue, strerror(-r));
350 case NETDEV_KIND_MACVLAN:
351 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
353 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
354 "Can not add MACVLAN '%s' to network: %s",
355 rvalue, strerror(-r));
360 case NETDEV_KIND_VXLAN:
361 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
363 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
364 "Can not add VXLAN '%s' to network: %s",
365 rvalue, strerror(-r));
371 assert_not_reached("Can not parse NetDev");
379 int config_parse_tunnel(const char *unit,
380 const char *filename,
383 unsigned section_line,
389 Network *network = userdata;
398 r = netdev_get(network->manager, rvalue, &netdev);
400 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
401 "Tunnel is invalid, ignoring assignment: %s", rvalue);
405 if (netdev->kind != NETDEV_KIND_IPIP &&
406 netdev->kind != NETDEV_KIND_SIT &&
407 netdev->kind != NETDEV_KIND_GRE &&
408 netdev->kind != NETDEV_KIND_VTI) {
409 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
410 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
414 network->tunnel = netdev;