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;
94 r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup,
95 (void*) network_network_gperf_lookup, false, false, network);
97 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
101 LIST_PREPEND(networks, manager->networks, network);
103 LIST_FOREACH(routes, route, network->static_routes) {
104 if (!route->family) {
105 log_warning("Route section without Gateway field configured in %s. "
106 "Ignoring", filename);
111 LIST_FOREACH(addresses, address, network->static_addresses) {
112 if (!address->family) {
113 log_warning("Address section without Address field configured in %s. "
114 "Ignoring", filename);
124 int network_load(Manager *manager) {
126 _cleanup_strv_free_ char **files = NULL;
132 while ((network = manager->networks))
133 network_free(network);
135 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
137 log_error("Failed to enumerate network files: %s", strerror(-r));
141 STRV_FOREACH_BACKWARDS(f, files) {
142 r = network_load_one(manager, *f);
150 void network_free(Network *network) {
159 free(network->filename);
161 free(network->match_mac);
162 free(network->match_path);
163 free(network->match_driver);
164 free(network->match_type);
165 free(network->match_name);
167 free(network->description);
169 while ((address = network->ntp)) {
170 LIST_REMOVE(addresses, network->ntp, address);
171 address_free(address);
174 while ((address = network->dns)) {
175 LIST_REMOVE(addresses, network->dns, address);
176 address_free(address);
179 netdev_unref(network->bridge);
181 netdev_unref(network->bond);
183 netdev_unref(network->tunnel);
185 HASHMAP_FOREACH(netdev, network->vlans, i)
186 netdev_unref(netdev);
187 hashmap_free(network->vlans);
189 HASHMAP_FOREACH(netdev, network->macvlans, i)
190 netdev_unref(netdev);
191 hashmap_free(network->macvlans);
193 HASHMAP_FOREACH(netdev, network->vxlans, i)
194 netdev_unref(netdev);
195 hashmap_free(network->vxlans);
197 while ((route = network->static_routes))
200 while ((address = network->static_addresses))
201 address_free(address);
203 hashmap_free(network->addresses_by_section);
204 hashmap_free(network->routes_by_section);
206 if (network->manager && network->manager->networks)
207 LIST_REMOVE(networks, network->manager->networks, network);
209 condition_free_list(network->match_host);
210 condition_free_list(network->match_virt);
211 condition_free_list(network->match_kernel);
212 condition_free_list(network->match_arch);
217 int network_get(Manager *manager, struct udev_device *device,
218 const char *ifname, const struct ether_addr *address,
225 LIST_FOREACH(networks, network, manager->networks) {
226 if (net_match_config(network->match_mac, network->match_path,
227 network->match_driver, network->match_type,
228 network->match_name, network->match_host,
229 network->match_virt, network->match_kernel,
232 udev_device_get_property_value(device, "ID_PATH"),
233 udev_device_get_driver(udev_device_get_parent(device)),
234 udev_device_get_property_value(device, "ID_NET_DRIVER"),
235 udev_device_get_devtype(device),
237 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
249 int network_apply(Manager *manager, Network *network, Link *link) {
252 link->network = network;
254 if (network->dns || network->ntp) {
263 int config_parse_netdev(const char *unit,
264 const char *filename,
267 unsigned section_line,
273 Network *network = userdata;
274 _cleanup_free_ char *kind_string = NULL;
285 kind_string = strdup(lvalue);
289 /* the keys are CamelCase versions of the kind */
290 for (p = kind_string; *p; p++)
293 kind = netdev_kind_from_string(kind_string);
294 if (kind == _NETDEV_KIND_INVALID) {
295 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
296 "Invalid NetDev kind: %s", lvalue);
300 r = netdev_get(network->manager, rvalue, &netdev);
302 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
303 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
307 if (netdev->kind != kind) {
308 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
309 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
314 case NETDEV_KIND_BRIDGE:
315 network->bridge = netdev;
318 case NETDEV_KIND_BOND:
319 network->bond = netdev;
322 case NETDEV_KIND_VLAN:
323 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
325 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
326 "Can not add VLAN to network: %s", rvalue);
331 case NETDEV_KIND_MACVLAN:
332 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
335 "Can not add MACVLAN to network: %s", rvalue);
340 case NETDEV_KIND_VXLAN:
341 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
343 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
344 "Can not add VXLAN to network: %s", rvalue);
350 assert_not_reached("Can not parse NetDev");
358 int config_parse_tunnel(const char *unit,
359 const char *filename,
362 unsigned section_line,
368 Network *network = userdata;
377 r = netdev_get(network->manager, rvalue, &netdev);
379 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
380 "Tunnel is invalid, ignoring assignment: %s", rvalue);
384 if (netdev->kind != NETDEV_KIND_IPIP &&
385 netdev->kind != NETDEV_KIND_SIT &&
386 netdev->kind != NETDEV_KIND_GRE &&
387 netdev->kind != NETDEV_KIND_VTI) {
388 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
389 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
393 network->tunnel = netdev;