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;
92 network->dhcp_routes = true;
93 network->dhcp_sendhost = true;
95 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0", config_item_perf_lookup,
96 (void*) network_network_gperf_lookup, false, false, network);
98 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
102 LIST_PREPEND(networks, manager->networks, network);
104 LIST_FOREACH(routes, route, network->static_routes) {
105 if (!route->family) {
106 log_warning("Route section without Gateway field configured in %s. "
107 "Ignoring", filename);
112 LIST_FOREACH(addresses, address, network->static_addresses) {
113 if (!address->family) {
114 log_warning("Address section without Address field configured in %s. "
115 "Ignoring", filename);
125 int network_load(Manager *manager) {
127 _cleanup_strv_free_ char **files = NULL;
133 while ((network = manager->networks))
134 network_free(network);
136 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
138 log_error("Failed to enumerate network files: %s", strerror(-r));
142 STRV_FOREACH_BACKWARDS(f, files) {
143 r = network_load_one(manager, *f);
151 void network_free(Network *network) {
160 free(network->filename);
162 free(network->match_mac);
163 free(network->match_path);
164 free(network->match_driver);
165 free(network->match_type);
166 free(network->match_name);
168 free(network->description);
169 free(network->dhcp_vendor_class_identifier);
171 while ((address = network->ntp)) {
172 LIST_REMOVE(addresses, network->ntp, address);
173 address_free(address);
176 while ((address = network->dns)) {
177 LIST_REMOVE(addresses, network->dns, address);
178 address_free(address);
181 netdev_unref(network->bridge);
183 netdev_unref(network->bond);
185 netdev_unref(network->tunnel);
187 HASHMAP_FOREACH(netdev, network->vlans, i)
188 netdev_unref(netdev);
189 hashmap_free(network->vlans);
191 HASHMAP_FOREACH(netdev, network->macvlans, i)
192 netdev_unref(netdev);
193 hashmap_free(network->macvlans);
195 HASHMAP_FOREACH(netdev, network->vxlans, i)
196 netdev_unref(netdev);
197 hashmap_free(network->vxlans);
199 while ((route = network->static_routes))
202 while ((address = network->static_addresses))
203 address_free(address);
205 hashmap_free(network->addresses_by_section);
206 hashmap_free(network->routes_by_section);
208 if (network->manager && network->manager->networks)
209 LIST_REMOVE(networks, network->manager->networks, network);
211 condition_free_list(network->match_host);
212 condition_free_list(network->match_virt);
213 condition_free_list(network->match_kernel);
214 condition_free_list(network->match_arch);
219 int network_get(Manager *manager, struct udev_device *device,
220 const char *ifname, const struct ether_addr *address,
227 LIST_FOREACH(networks, network, manager->networks) {
228 if (net_match_config(network->match_mac, network->match_path,
229 network->match_driver, network->match_type,
230 network->match_name, network->match_host,
231 network->match_virt, network->match_kernel,
234 udev_device_get_property_value(device, "ID_PATH"),
235 udev_device_get_driver(udev_device_get_parent(device)),
236 udev_device_get_property_value(device, "ID_NET_DRIVER"),
237 udev_device_get_devtype(device),
239 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
251 int network_apply(Manager *manager, Network *network, Link *link) {
254 link->network = network;
256 if (network->dns || network->ntp) {
265 int config_parse_netdev(const char *unit,
266 const char *filename,
269 unsigned section_line,
275 Network *network = userdata;
276 _cleanup_free_ char *kind_string = NULL;
287 kind_string = strdup(lvalue);
291 /* the keys are CamelCase versions of the kind */
292 for (p = kind_string; *p; p++)
295 kind = netdev_kind_from_string(kind_string);
296 if (kind == _NETDEV_KIND_INVALID) {
297 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
298 "Invalid NetDev kind: %s", lvalue);
302 r = netdev_get(network->manager, rvalue, &netdev);
304 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
305 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
309 if (netdev->kind != kind) {
310 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
311 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
316 case NETDEV_KIND_BRIDGE:
317 network->bridge = netdev;
320 case NETDEV_KIND_BOND:
321 network->bond = netdev;
324 case NETDEV_KIND_VLAN:
325 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
327 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
328 "Can not add VLAN to network: %s", rvalue);
333 case NETDEV_KIND_MACVLAN:
334 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
336 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
337 "Can not add MACVLAN to network: %s", rvalue);
342 case NETDEV_KIND_VXLAN:
343 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
345 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
346 "Can not add VXLAN to network: %s", rvalue);
352 assert_not_reached("Can not parse NetDev");
360 int config_parse_tunnel(const char *unit,
361 const char *filename,
364 unsigned section_line,
370 Network *network = userdata;
379 r = netdev_get(network->manager, rvalue, &netdev);
381 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
382 "Tunnel is invalid, ignoring assignment: %s", rvalue);
386 if (netdev->kind != NETDEV_KIND_IPIP &&
387 netdev->kind != NETDEV_KIND_SIT &&
388 netdev->kind != NETDEV_KIND_GRE &&
389 netdev->kind != NETDEV_KIND_VTI) {
390 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
391 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
395 network->tunnel = netdev;