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->dhcp_ntp = true;
90 network->dhcp_dns = true;
91 network->dhcp_hostname = true;
92 network->dhcp_domainname = true;
93 network->dhcp_routes = true;
94 network->dhcp_sendhost = true;
96 r = config_parse(NULL, filename, file,
97 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
98 config_item_perf_lookup, network_network_gperf_lookup,
99 false, false, true, network);
103 LIST_PREPEND(networks, manager->networks, network);
105 LIST_FOREACH(routes, route, network->static_routes) {
106 if (!route->family) {
107 log_warning("Route section without Gateway field configured in %s. "
108 "Ignoring", filename);
113 LIST_FOREACH(addresses, address, network->static_addresses) {
114 if (!address->family) {
115 log_warning("Address section without Address field configured in %s. "
116 "Ignoring", filename);
126 int network_load(Manager *manager) {
128 _cleanup_strv_free_ char **files = NULL;
134 while ((network = manager->networks))
135 network_free(network);
137 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
139 log_error("Failed to enumerate network files: %s", strerror(-r));
143 STRV_FOREACH_BACKWARDS(f, files) {
144 r = network_load_one(manager, *f);
152 void network_free(Network *network) {
161 free(network->filename);
163 free(network->match_mac);
164 free(network->match_path);
165 free(network->match_driver);
166 free(network->match_type);
167 free(network->match_name);
169 free(network->description);
170 free(network->dhcp_vendor_class_identifier);
172 while ((address = network->ntp)) {
173 LIST_REMOVE(addresses, network->ntp, address);
174 address_free(address);
177 while ((address = network->dns)) {
178 LIST_REMOVE(addresses, network->dns, address);
179 address_free(address);
182 netdev_unref(network->bridge);
184 netdev_unref(network->bond);
186 netdev_unref(network->tunnel);
188 HASHMAP_FOREACH(netdev, network->vlans, i)
189 netdev_unref(netdev);
190 hashmap_free(network->vlans);
192 HASHMAP_FOREACH(netdev, network->macvlans, i)
193 netdev_unref(netdev);
194 hashmap_free(network->macvlans);
196 HASHMAP_FOREACH(netdev, network->vxlans, i)
197 netdev_unref(netdev);
198 hashmap_free(network->vxlans);
200 while ((route = network->static_routes))
203 while ((address = network->static_addresses))
204 address_free(address);
206 hashmap_free(network->addresses_by_section);
207 hashmap_free(network->routes_by_section);
209 if (network->manager && network->manager->networks)
210 LIST_REMOVE(networks, network->manager->networks, network);
212 condition_free_list(network->match_host);
213 condition_free_list(network->match_virt);
214 condition_free_list(network->match_kernel);
215 condition_free_list(network->match_arch);
220 int network_get(Manager *manager, struct udev_device *device,
221 const char *ifname, const struct ether_addr *address,
228 LIST_FOREACH(networks, network, manager->networks) {
229 if (net_match_config(network->match_mac, network->match_path,
230 network->match_driver, network->match_type,
231 network->match_name, network->match_host,
232 network->match_virt, network->match_kernel,
235 udev_device_get_property_value(device, "ID_PATH"),
236 udev_device_get_driver(udev_device_get_parent(device)),
237 udev_device_get_property_value(device, "ID_NET_DRIVER"),
238 udev_device_get_devtype(device),
240 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
252 int network_apply(Manager *manager, Network *network, Link *link) {
255 link->network = network;
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 r = hashmap_put(network->vlans, 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));
335 case NETDEV_KIND_MACVLAN:
336 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
338 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
339 "Can not add MACVLAN '%s' to network: %s",
340 rvalue, strerror(-r));
345 case NETDEV_KIND_VXLAN:
346 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
348 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
349 "Can not add VXLAN '%s' to network: %s",
350 rvalue, strerror(-r));
356 assert_not_reached("Can not parse NetDev");
364 int config_parse_tunnel(const char *unit,
365 const char *filename,
368 unsigned section_line,
374 Network *network = userdata;
383 r = netdev_get(network->manager, rvalue, &netdev);
385 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
386 "Tunnel is invalid, ignoring assignment: %s", rvalue);
390 if (netdev->kind != NETDEV_KIND_IPIP &&
391 netdev->kind != NETDEV_KIND_SIT &&
392 netdev->kind != NETDEV_KIND_GRE &&
393 netdev->kind != NETDEV_KIND_VTI) {
394 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
395 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
399 network->tunnel = netdev;