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 netdev_unref(network->tunnel);
184 HASHMAP_FOREACH(netdev, network->vlans, i)
185 netdev_unref(netdev);
186 hashmap_free(network->vlans);
188 HASHMAP_FOREACH(netdev, network->macvlans, i)
189 netdev_unref(netdev);
190 hashmap_free(network->macvlans);
192 HASHMAP_FOREACH(netdev, network->vxlans, i)
193 netdev_unref(netdev);
194 hashmap_free(network->vxlans);
196 while ((route = network->static_routes))
199 while ((address = network->static_addresses))
200 address_free(address);
202 hashmap_free(network->addresses_by_section);
203 hashmap_free(network->routes_by_section);
205 if (network->manager && network->manager->networks)
206 LIST_REMOVE(networks, network->manager->networks, network);
208 condition_free_list(network->match_host);
209 condition_free_list(network->match_virt);
210 condition_free_list(network->match_kernel);
211 condition_free_list(network->match_arch);
216 int network_get(Manager *manager, struct udev_device *device,
217 const char *ifname, const struct ether_addr *address,
224 LIST_FOREACH(networks, network, manager->networks) {
225 if (net_match_config(network->match_mac, network->match_path,
226 network->match_driver, network->match_type,
227 network->match_name, network->match_host,
228 network->match_virt, network->match_kernel,
231 udev_device_get_property_value(device, "ID_PATH"),
232 udev_device_get_driver(udev_device_get_parent(device)),
233 udev_device_get_property_value(device, "ID_NET_DRIVER"),
234 udev_device_get_devtype(device),
236 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
248 int network_apply(Manager *manager, Network *network, Link *link) {
251 link->network = network;
253 if (network->dns || network->ntp) {
262 int config_parse_netdev(const char *unit,
263 const char *filename,
266 unsigned section_line,
272 Network *network = userdata;
273 _cleanup_free_ char *kind_string = NULL;
284 kind_string = strdup(lvalue);
288 /* the keys are CamelCase versions of the kind */
289 for (p = kind_string; *p; p++)
292 kind = netdev_kind_from_string(kind_string);
293 if (kind == _NETDEV_KIND_INVALID) {
294 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
295 "Invalid NetDev kind: %s", lvalue);
299 r = netdev_get(network->manager, rvalue, &netdev);
301 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
302 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
306 if (netdev->kind != kind) {
307 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
308 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
313 case NETDEV_KIND_BRIDGE:
314 network->bridge = netdev;
317 case NETDEV_KIND_BOND:
318 network->bond = netdev;
321 case NETDEV_KIND_VLAN:
322 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
324 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
325 "Can not add VLAN to network: %s", rvalue);
330 case NETDEV_KIND_MACVLAN:
331 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
333 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
334 "Can not add MACVLAN to network: %s", rvalue);
339 case NETDEV_KIND_VXLAN:
340 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
342 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
343 "Can not add VXLAN to network: %s", rvalue);
349 assert_not_reached("Can not parse NetDev");
357 int config_parse_tunnel(const char *unit,
358 const char *filename,
361 unsigned section_line,
367 Network *network = userdata;
376 r = netdev_get(network->manager, rvalue, &netdev);
378 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
379 "Tunnel is invalid, ignoring assignment: %s", rvalue);
383 if (netdev->kind != NETDEV_KIND_IPIP &&
384 netdev->kind != NETDEV_KIND_SIT &&
385 netdev->kind != NETDEV_KIND_GRE &&
386 netdev->kind != NETDEV_KIND_VTI) {
387 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
388 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
392 network->tunnel = netdev;