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);
170 while ((address = network->ntp)) {
171 LIST_REMOVE(addresses, network->ntp, address);
172 address_free(address);
175 while ((address = network->dns)) {
176 LIST_REMOVE(addresses, network->dns, address);
177 address_free(address);
180 netdev_unref(network->bridge);
182 netdev_unref(network->bond);
184 netdev_unref(network->tunnel);
186 HASHMAP_FOREACH(netdev, network->vlans, i)
187 netdev_unref(netdev);
188 hashmap_free(network->vlans);
190 HASHMAP_FOREACH(netdev, network->macvlans, i)
191 netdev_unref(netdev);
192 hashmap_free(network->macvlans);
194 HASHMAP_FOREACH(netdev, network->vxlans, i)
195 netdev_unref(netdev);
196 hashmap_free(network->vxlans);
198 while ((route = network->static_routes))
201 while ((address = network->static_addresses))
202 address_free(address);
204 hashmap_free(network->addresses_by_section);
205 hashmap_free(network->routes_by_section);
207 if (network->manager && network->manager->networks)
208 LIST_REMOVE(networks, network->manager->networks, network);
210 condition_free_list(network->match_host);
211 condition_free_list(network->match_virt);
212 condition_free_list(network->match_kernel);
213 condition_free_list(network->match_arch);
218 int network_get(Manager *manager, struct udev_device *device,
219 const char *ifname, const struct ether_addr *address,
226 LIST_FOREACH(networks, network, manager->networks) {
227 if (net_match_config(network->match_mac, network->match_path,
228 network->match_driver, network->match_type,
229 network->match_name, network->match_host,
230 network->match_virt, network->match_kernel,
233 udev_device_get_property_value(device, "ID_PATH"),
234 udev_device_get_driver(udev_device_get_parent(device)),
235 udev_device_get_property_value(device, "ID_NET_DRIVER"),
236 udev_device_get_devtype(device),
238 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
250 int network_apply(Manager *manager, Network *network, Link *link) {
253 link->network = network;
255 if (network->dns || network->ntp) {
264 int config_parse_netdev(const char *unit,
265 const char *filename,
268 unsigned section_line,
274 Network *network = userdata;
275 _cleanup_free_ char *kind_string = NULL;
286 kind_string = strdup(lvalue);
290 /* the keys are CamelCase versions of the kind */
291 for (p = kind_string; *p; p++)
294 kind = netdev_kind_from_string(kind_string);
295 if (kind == _NETDEV_KIND_INVALID) {
296 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
297 "Invalid NetDev kind: %s", lvalue);
301 r = netdev_get(network->manager, rvalue, &netdev);
303 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
304 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
308 if (netdev->kind != kind) {
309 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
310 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
315 case NETDEV_KIND_BRIDGE:
316 network->bridge = netdev;
319 case NETDEV_KIND_BOND:
320 network->bond = netdev;
323 case NETDEV_KIND_VLAN:
324 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
326 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327 "Can not add VLAN to network: %s", rvalue);
332 case NETDEV_KIND_MACVLAN:
333 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
335 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
336 "Can not add MACVLAN to network: %s", rvalue);
341 case NETDEV_KIND_VXLAN:
342 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
344 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
345 "Can not add VXLAN to network: %s", rvalue);
351 assert_not_reached("Can not parse NetDev");
359 int config_parse_tunnel(const char *unit,
360 const char *filename,
363 unsigned section_line,
369 Network *network = userdata;
378 r = netdev_get(network->manager, rvalue, &netdev);
380 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
381 "Tunnel is invalid, ignoring assignment: %s", rvalue);
385 if (netdev->kind != NETDEV_KIND_IPIP &&
386 netdev->kind != NETDEV_KIND_SIT &&
387 netdev->kind != NETDEV_KIND_GRE &&
388 netdev->kind != NETDEV_KIND_VTI) {
389 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
390 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
394 network->tunnel = netdev;