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 "network-internal.h"
27 #include "path-util.h"
28 #include "conf-files.h"
29 #include "conf-parser.h"
32 static int network_load_one(Manager *manager, const char *filename) {
33 _cleanup_network_free_ Network *network = NULL;
34 _cleanup_fclose_ FILE *file = NULL;
42 file = fopen(filename, "re");
50 if (null_or_empty_path(filename)) {
51 log_debug("skipping empty file: %s", filename);
55 network = new0(Network, 1);
59 network->manager = manager;
61 LIST_HEAD_INIT(network->static_addresses);
62 LIST_HEAD_INIT(network->static_routes);
64 network->vlans = hashmap_new(string_hash_func, string_compare_func);
68 network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
69 if (!network->macvlans)
72 network->vxlans = hashmap_new(uint64_hash_func, uint64_compare_func);
76 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
77 if (!network->addresses_by_section)
80 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
81 if (!network->routes_by_section)
84 network->filename = strdup(filename);
85 if (!network->filename)
88 network->dhcp_ntp = true;
89 network->dhcp_dns = true;
90 network->dhcp_hostname = true;
91 network->dhcp_domainname = true;
93 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
94 (void*) network_network_gperf_lookup, false, false, network);
96 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
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);
168 while ((address = network->ntp)) {
169 LIST_REMOVE(addresses, network->ntp, address);
170 address_free(address);
173 while ((address = network->dns)) {
174 LIST_REMOVE(addresses, network->dns, address);
175 address_free(address);
178 netdev_unref(network->bridge);
180 netdev_unref(network->bond);
182 HASHMAP_FOREACH(netdev, network->vlans, i)
183 netdev_unref(netdev);
184 hashmap_free(network->vlans);
186 HASHMAP_FOREACH(netdev, network->macvlans, i)
187 netdev_unref(netdev);
188 hashmap_free(network->macvlans);
190 HASHMAP_FOREACH(netdev, network->vxlans, i)
191 netdev_unref(netdev);
192 hashmap_free(network->vxlans);
194 while ((route = network->static_routes))
197 while ((address = network->static_addresses))
198 address_free(address);
200 hashmap_free(network->addresses_by_section);
201 hashmap_free(network->routes_by_section);
203 if (network->manager && network->manager->networks)
204 LIST_REMOVE(networks, network->manager->networks, network);
206 condition_free_list(network->match_host);
207 condition_free_list(network->match_virt);
208 condition_free_list(network->match_kernel);
209 condition_free_list(network->match_arch);
214 int network_get(Manager *manager, struct udev_device *device,
215 const char *ifname, const struct ether_addr *address,
222 LIST_FOREACH(networks, network, manager->networks) {
223 if (net_match_config(network->match_mac, network->match_path,
224 network->match_driver, network->match_type,
225 network->match_name, network->match_host,
226 network->match_virt, network->match_kernel,
229 udev_device_get_property_value(device, "ID_PATH"),
230 udev_device_get_driver(udev_device_get_parent(device)),
231 udev_device_get_property_value(device, "ID_NET_DRIVER"),
232 udev_device_get_devtype(device),
234 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
246 int network_apply(Manager *manager, Network *network, Link *link) {
249 link->network = network;
251 if (network->dns || network->ntp) {
260 int config_parse_netdev(const char *unit,
261 const char *filename,
264 unsigned section_line,
270 Network *network = userdata;
271 _cleanup_free_ char *kind_string = NULL;
282 kind_string = strdup(lvalue);
286 /* the keys are CamelCase versions of the kind */
287 for (p = kind_string; *p; p++)
290 kind = netdev_kind_from_string(kind_string);
291 if (kind == _NETDEV_KIND_INVALID) {
292 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
293 "Invalid NetDev kind: %s", lvalue);
297 r = netdev_get(network->manager, rvalue, &netdev);
299 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
300 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
304 if (netdev->kind != kind) {
305 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
306 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
311 case NETDEV_KIND_BRIDGE:
312 network->bridge = netdev;
315 case NETDEV_KIND_BOND:
316 network->bond = netdev;
319 case NETDEV_KIND_VLAN:
320 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
322 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
323 "Can not add VLAN to network: %s", rvalue);
328 case NETDEV_KIND_MACVLAN:
329 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
331 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
332 "Can not add MACVLAN to network: %s", rvalue);
337 case NETDEV_KIND_VXLAN:
338 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
340 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
341 "Can not add VXLAN to network: %s", rvalue);
347 assert_not_reached("Can not parse NetDev");
355 int config_parse_tunnel(const char *unit,
356 const char *filename,
359 unsigned section_line,
365 Network *network = userdata;
374 r = netdev_get(network->manager, rvalue, &netdev);
376 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
377 "Tunnel is invalid, ignoring assignment: %s", rvalue);
381 if (netdev->kind != NETDEV_KIND_IPIP &&
382 netdev->kind != NETDEV_KIND_SIT &&
383 netdev->kind != NETDEV_KIND_GRE &&
384 netdev->kind != NETDEV_KIND_VTI) {
385 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
386 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
390 network->tunnel = netdev;