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->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
73 if (!network->addresses_by_section)
76 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
77 if (!network->routes_by_section)
80 network->filename = strdup(filename);
81 if (!network->filename)
84 network->dhcp_dns = true;
85 network->dhcp_hostname = true;
86 network->dhcp_domainname = true;
88 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
89 (void*) network_network_gperf_lookup, false, false, network);
91 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
95 LIST_PREPEND(networks, manager->networks, network);
97 LIST_FOREACH(routes, route, network->static_routes) {
99 log_warning("Route section without Gateway field configured in %s. "
100 "Ignoring", filename);
105 LIST_FOREACH(addresses, address, network->static_addresses) {
106 if (!address->family) {
107 log_warning("Address section without Address field configured in %s. "
108 "Ignoring", filename);
118 int network_load(Manager *manager) {
120 _cleanup_strv_free_ char **files = NULL;
126 while ((network = manager->networks))
127 network_free(network);
129 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
131 log_error("Failed to enumerate network files: %s", strerror(-r));
135 STRV_FOREACH_BACKWARDS(f, files) {
136 r = network_load_one(manager, *f);
144 void network_free(Network *network) {
153 free(network->filename);
155 free(network->match_mac);
156 free(network->match_path);
157 free(network->match_driver);
158 free(network->match_type);
159 free(network->match_name);
161 free(network->description);
163 while ((address = network->dns)) {
164 LIST_REMOVE(addresses, network->dns, address);
165 address_free(address);
168 netdev_unref(network->bridge);
170 netdev_unref(network->bond);
172 HASHMAP_FOREACH(netdev, network->vlans, i)
173 netdev_unref(netdev);
174 hashmap_free(network->vlans);
176 HASHMAP_FOREACH(netdev, network->macvlans, i)
177 netdev_unref(netdev);
178 hashmap_free(network->macvlans);
180 while ((route = network->static_routes))
183 while ((address = network->static_addresses))
184 address_free(address);
186 hashmap_free(network->addresses_by_section);
187 hashmap_free(network->routes_by_section);
189 if (network->manager && network->manager->networks)
190 LIST_REMOVE(networks, network->manager->networks, network);
192 condition_free_list(network->match_host);
193 condition_free_list(network->match_virt);
194 condition_free_list(network->match_kernel);
195 condition_free_list(network->match_arch);
200 int network_get(Manager *manager, struct udev_device *device,
201 const char *ifname, const struct ether_addr *address,
208 LIST_FOREACH(networks, network, manager->networks) {
209 if (net_match_config(network->match_mac, network->match_path,
210 network->match_driver, network->match_type,
211 network->match_name, network->match_host,
212 network->match_virt, network->match_kernel,
215 udev_device_get_property_value(device, "ID_PATH"),
216 udev_device_get_driver(udev_device_get_parent(device)),
217 udev_device_get_property_value(device, "ID_NET_DRIVER"),
218 udev_device_get_devtype(device),
220 log_debug("%*s: found matching network '%s'", IFNAMSIZ, ifname,
232 int network_apply(Manager *manager, Network *network, Link *link) {
235 link->network = network;
238 r = manager_update_resolv_conf(manager);
246 int config_parse_netdev(const char *unit,
247 const char *filename,
250 unsigned section_line,
256 Network *network = userdata;
257 _cleanup_free_ char *kind_string = NULL;
268 kind_string = strdup(lvalue);
272 /* the keys are CamelCase versions of the kind */
273 for (p = kind_string; *p; p++)
276 kind = netdev_kind_from_string(kind_string);
277 if (kind == _NETDEV_KIND_INVALID) {
278 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
279 "Invalid NetDev kind: %s", lvalue);
283 r = netdev_get(network->manager, rvalue, &netdev);
285 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
286 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
290 if (netdev->kind != kind) {
291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
292 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
297 case NETDEV_KIND_BRIDGE:
298 network->bridge = netdev;
301 case NETDEV_KIND_BOND:
302 network->bond = netdev;
305 case NETDEV_KIND_VLAN:
306 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
308 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
309 "Can not add VLAN to network: %s", rvalue);
314 case NETDEV_KIND_MACVLAN:
315 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
317 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
318 "Can not add MACVLAN to network: %s", rvalue);
324 assert_not_reached("Can not parse NetDev");
332 int config_parse_tunnel(const char *unit,
333 const char *filename,
336 unsigned section_line,
342 Network *network = userdata;
351 r = netdev_get(network->manager, rvalue, &netdev);
353 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
354 "Tunnel is invalid, ignoring assignment: %s", rvalue);
358 if (netdev->kind != NETDEV_KIND_IPIP &&
359 netdev->kind != NETDEV_KIND_SIT &&
360 netdev->kind != NETDEV_KIND_GRE) {
361 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
362 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
366 network->tunnel = netdev;