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->dns = set_new(NULL, NULL);
84 network->filename = strdup(filename);
85 if (!network->filename)
88 network->dhcp_dns = true;
89 network->dhcp_hostname = true;
90 network->dhcp_domainname = true;
92 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
93 (void*) network_network_gperf_lookup, false, false, network);
95 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
99 LIST_PREPEND(networks, manager->networks, network);
101 LIST_FOREACH(routes, route, network->static_routes) {
102 if (!route->family) {
103 log_warning("Route section without Gateway field configured in %s. "
104 "Ignoring", filename);
109 LIST_FOREACH(addresses, address, network->static_addresses) {
110 if (!address->family) {
111 log_warning("Address section without Address field configured in %s. "
112 "Ignoring", filename);
122 int network_load(Manager *manager) {
124 _cleanup_strv_free_ char **files = NULL;
130 while ((network = manager->networks))
131 network_free(network);
133 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
135 log_error("Failed to enumerate network files: %s", strerror(-r));
139 STRV_FOREACH_BACKWARDS(f, files) {
140 r = network_load_one(manager, *f);
148 void network_free(Network *network) {
157 free(network->filename);
159 free(network->match_mac);
160 free(network->match_path);
161 free(network->match_driver);
162 free(network->match_type);
163 free(network->match_name);
165 free(network->description);
167 SET_FOREACH(address, network->dns, i)
168 address_free(address);
170 set_free(network->dns);
172 netdev_unref(network->bridge);
174 netdev_unref(network->bond);
176 HASHMAP_FOREACH(netdev, network->vlans, i)
177 netdev_unref(netdev);
178 hashmap_free(network->vlans);
180 HASHMAP_FOREACH(netdev, network->macvlans, i)
181 netdev_unref(netdev);
182 hashmap_free(network->macvlans);
184 while ((route = network->static_routes))
187 while ((address = network->static_addresses))
188 address_free(address);
190 hashmap_free(network->addresses_by_section);
191 hashmap_free(network->routes_by_section);
193 if (network->manager && network->manager->networks)
194 LIST_REMOVE(networks, network->manager->networks, network);
196 condition_free_list(network->match_host);
197 condition_free_list(network->match_virt);
198 condition_free_list(network->match_kernel);
199 condition_free_list(network->match_arch);
204 int network_get(Manager *manager, struct udev_device *device,
205 const char *ifname, const struct ether_addr *address,
212 LIST_FOREACH(networks, network, manager->networks) {
213 if (net_match_config(network->match_mac, network->match_path,
214 network->match_driver, network->match_type,
215 network->match_name, network->match_host,
216 network->match_virt, network->match_kernel,
219 udev_device_get_property_value(device, "ID_PATH"),
220 udev_device_get_driver(udev_device_get_parent(device)),
221 udev_device_get_property_value(device, "ID_NET_DRIVER"),
222 udev_device_get_devtype(device),
224 log_debug("%*s: found matching network '%s'", IFNAMSIZ, ifname,
236 int network_apply(Manager *manager, Network *network, Link *link) {
239 link->network = network;
242 r = manager_update_resolv_conf(manager);
250 int config_parse_netdev(const char *unit,
251 const char *filename,
254 unsigned section_line,
260 Network *network = userdata;
261 _cleanup_free_ char *kind_string = NULL;
272 kind_string = strdup(lvalue);
276 /* the keys are CamelCase versions of the kind */
277 for (p = kind_string; *p; p++)
280 kind = netdev_kind_from_string(kind_string);
281 if (kind == _NETDEV_KIND_INVALID) {
282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
283 "Invalid NetDev kind: %s", lvalue);
287 r = netdev_get(network->manager, rvalue, &netdev);
289 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
290 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
294 if (netdev->kind != kind) {
295 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
296 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
301 case NETDEV_KIND_BRIDGE:
302 network->bridge = netdev;
305 case NETDEV_KIND_BOND:
306 network->bond = netdev;
309 case NETDEV_KIND_VLAN:
310 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
312 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
313 "Can not add VLAN to network: %s", rvalue);
318 case NETDEV_KIND_MACVLAN:
319 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
321 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
322 "Can not add MACVLAN to network: %s", rvalue);
328 assert_not_reached("Can not parse NetDev");
336 int config_parse_tunnel(const char *unit,
337 const char *filename,
340 unsigned section_line,
346 Network *network = userdata;
355 r = netdev_get(network->manager, rvalue, &netdev);
357 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
358 "Tunnel is invalid, ignoring assignment: %s", rvalue);
362 if (netdev->kind != NETDEV_KIND_IPIP &&
363 netdev->kind != NETDEV_KIND_SIT &&
364 netdev->kind != NETDEV_KIND_GRE) {
365 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
366 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
370 network->tunnel = netdev;