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_ntp = true;
85 network->dhcp_dns = true;
86 network->dhcp_hostname = true;
87 network->dhcp_domainname = true;
89 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
90 (void*) network_network_gperf_lookup, false, false, network);
92 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
96 LIST_PREPEND(networks, manager->networks, network);
98 LIST_FOREACH(routes, route, network->static_routes) {
100 log_warning("Route section without Gateway field configured in %s. "
101 "Ignoring", filename);
106 LIST_FOREACH(addresses, address, network->static_addresses) {
107 if (!address->family) {
108 log_warning("Address section without Address field configured in %s. "
109 "Ignoring", filename);
119 int network_load(Manager *manager) {
121 _cleanup_strv_free_ char **files = NULL;
127 while ((network = manager->networks))
128 network_free(network);
130 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
132 log_error("Failed to enumerate network files: %s", strerror(-r));
136 STRV_FOREACH_BACKWARDS(f, files) {
137 r = network_load_one(manager, *f);
145 void network_free(Network *network) {
154 free(network->filename);
156 free(network->match_mac);
157 free(network->match_path);
158 free(network->match_driver);
159 free(network->match_type);
160 free(network->match_name);
162 free(network->description);
164 while ((address = network->ntp)) {
165 LIST_REMOVE(addresses, network->ntp, address);
166 address_free(address);
169 while ((address = network->dns)) {
170 LIST_REMOVE(addresses, network->dns, address);
171 address_free(address);
174 netdev_unref(network->bridge);
176 netdev_unref(network->bond);
178 HASHMAP_FOREACH(netdev, network->vlans, i)
179 netdev_unref(netdev);
180 hashmap_free(network->vlans);
182 HASHMAP_FOREACH(netdev, network->macvlans, i)
183 netdev_unref(netdev);
184 hashmap_free(network->macvlans);
186 while ((route = network->static_routes))
189 while ((address = network->static_addresses))
190 address_free(address);
192 hashmap_free(network->addresses_by_section);
193 hashmap_free(network->routes_by_section);
195 if (network->manager && network->manager->networks)
196 LIST_REMOVE(networks, network->manager->networks, network);
198 condition_free_list(network->match_host);
199 condition_free_list(network->match_virt);
200 condition_free_list(network->match_kernel);
201 condition_free_list(network->match_arch);
206 int network_get(Manager *manager, struct udev_device *device,
207 const char *ifname, const struct ether_addr *address,
214 LIST_FOREACH(networks, network, manager->networks) {
215 if (net_match_config(network->match_mac, network->match_path,
216 network->match_driver, network->match_type,
217 network->match_name, network->match_host,
218 network->match_virt, network->match_kernel,
221 udev_device_get_property_value(device, "ID_PATH"),
222 udev_device_get_driver(udev_device_get_parent(device)),
223 udev_device_get_property_value(device, "ID_NET_DRIVER"),
224 udev_device_get_devtype(device),
226 log_debug("%*s: found matching network '%s'", IFNAMSIZ, ifname,
238 int network_apply(Manager *manager, Network *network, Link *link) {
241 link->network = network;
243 if (network->dns || network->ntp) {
252 int config_parse_netdev(const char *unit,
253 const char *filename,
256 unsigned section_line,
262 Network *network = userdata;
263 _cleanup_free_ char *kind_string = NULL;
274 kind_string = strdup(lvalue);
278 /* the keys are CamelCase versions of the kind */
279 for (p = kind_string; *p; p++)
282 kind = netdev_kind_from_string(kind_string);
283 if (kind == _NETDEV_KIND_INVALID) {
284 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
285 "Invalid NetDev kind: %s", lvalue);
289 r = netdev_get(network->manager, rvalue, &netdev);
291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
292 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
296 if (netdev->kind != kind) {
297 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
298 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
303 case NETDEV_KIND_BRIDGE:
304 network->bridge = netdev;
307 case NETDEV_KIND_BOND:
308 network->bond = netdev;
311 case NETDEV_KIND_VLAN:
312 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
314 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
315 "Can not add VLAN to network: %s", rvalue);
320 case NETDEV_KIND_MACVLAN:
321 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
323 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
324 "Can not add MACVLAN to network: %s", rvalue);
330 assert_not_reached("Can not parse NetDev");
338 int config_parse_tunnel(const char *unit,
339 const char *filename,
342 unsigned section_line,
348 Network *network = userdata;
357 r = netdev_get(network->manager, rvalue, &netdev);
359 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
360 "Tunnel is invalid, ignoring assignment: %s", rvalue);
364 if (netdev->kind != NETDEV_KIND_IPIP &&
365 netdev->kind != NETDEV_KIND_SIT &&
366 netdev->kind != NETDEV_KIND_GRE &&
367 netdev->kind != NETDEV_KIND_VTI) {
368 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
369 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
373 network->tunnel = netdev;