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 "networkd-netdev.h"
27 #include "network-internal.h"
28 #include "path-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
33 static int network_load_one(Manager *manager, const char *filename) {
34 _cleanup_network_free_ Network *network = NULL;
35 _cleanup_fclose_ FILE *file = NULL;
43 file = fopen(filename, "re");
51 if (null_or_empty_fd(fileno(file))) {
52 log_debug("Skipping empty file: %s", filename);
56 network = new0(Network, 1);
60 network->manager = manager;
62 LIST_HEAD_INIT(network->static_addresses);
63 LIST_HEAD_INIT(network->static_routes);
65 network->vlans = hashmap_new(string_hash_func, string_compare_func);
69 network->macvlans = hashmap_new(string_hash_func, string_compare_func);
70 if (!network->macvlans)
73 network->vxlans = hashmap_new(string_hash_func, string_compare_func);
77 network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
78 if (!network->addresses_by_section)
81 network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
82 if (!network->routes_by_section)
85 network->filename = strdup(filename);
86 if (!network->filename)
89 network->dhcp_ntp = true;
90 network->dhcp_dns = true;
91 network->dhcp_hostname = true;
92 network->dhcp_domainname = true;
93 network->dhcp_routes = true;
94 network->dhcp_sendhost = true;
96 r = config_parse(NULL, filename, file,
97 "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
98 config_item_perf_lookup, network_network_gperf_lookup,
99 false, false, true, network);
103 LIST_PREPEND(networks, manager->networks, network);
105 LIST_FOREACH(routes, route, network->static_routes) {
106 if (!route->family) {
107 log_warning("Route section without Gateway field configured in %s. "
108 "Ignoring", filename);
113 LIST_FOREACH(addresses, address, network->static_addresses) {
114 if (!address->family) {
115 log_warning("Address section without Address field configured in %s. "
116 "Ignoring", filename);
126 int network_load(Manager *manager) {
128 _cleanup_strv_free_ char **files = NULL;
134 while ((network = manager->networks))
135 network_free(network);
137 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
139 log_error("Failed to enumerate network files: %s", strerror(-r));
143 STRV_FOREACH_BACKWARDS(f, files) {
144 r = network_load_one(manager, *f);
152 void network_free(Network *network) {
161 free(network->filename);
163 free(network->match_mac);
164 free(network->match_path);
165 free(network->match_driver);
166 free(network->match_type);
167 free(network->match_name);
169 free(network->description);
170 free(network->dhcp_vendor_class_identifier);
172 strv_free(network->ntp);
173 strv_free(network->dns);
175 netdev_unref(network->bridge);
177 netdev_unref(network->bond);
179 netdev_unref(network->tunnel);
181 HASHMAP_FOREACH(netdev, network->vlans, i)
182 netdev_unref(netdev);
183 hashmap_free(network->vlans);
185 HASHMAP_FOREACH(netdev, network->macvlans, i)
186 netdev_unref(netdev);
187 hashmap_free(network->macvlans);
189 HASHMAP_FOREACH(netdev, network->vxlans, i)
190 netdev_unref(netdev);
191 hashmap_free(network->vxlans);
193 while ((route = network->static_routes))
196 while ((address = network->static_addresses))
197 address_free(address);
199 hashmap_free(network->addresses_by_section);
200 hashmap_free(network->routes_by_section);
202 if (network->manager && network->manager->networks)
203 LIST_REMOVE(networks, network->manager->networks, network);
205 condition_free_list(network->match_host);
206 condition_free_list(network->match_virt);
207 condition_free_list(network->match_kernel);
208 condition_free_list(network->match_arch);
213 int network_get(Manager *manager, struct udev_device *device,
214 const char *ifname, const struct ether_addr *address,
221 LIST_FOREACH(networks, network, manager->networks) {
222 if (net_match_config(network->match_mac, network->match_path,
223 network->match_driver, network->match_type,
224 network->match_name, network->match_host,
225 network->match_virt, network->match_kernel,
228 udev_device_get_property_value(device, "ID_PATH"),
229 udev_device_get_driver(udev_device_get_parent(device)),
230 udev_device_get_property_value(device, "ID_NET_DRIVER"),
231 udev_device_get_devtype(device),
233 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
245 int network_apply(Manager *manager, Network *network, Link *link) {
248 link->network = network;
250 if (network->dns || network->ntp) {
259 int config_parse_netdev(const char *unit,
260 const char *filename,
263 unsigned section_line,
269 Network *network = userdata;
270 _cleanup_free_ char *kind_string = NULL;
281 kind_string = strdup(lvalue);
285 /* the keys are CamelCase versions of the kind */
286 for (p = kind_string; *p; p++)
289 kind = netdev_kind_from_string(kind_string);
290 if (kind == _NETDEV_KIND_INVALID) {
291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
292 "Invalid NetDev kind: %s", lvalue);
296 r = netdev_get(network->manager, rvalue, &netdev);
298 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
299 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
303 if (netdev->kind != kind) {
304 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
305 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
310 case NETDEV_KIND_BRIDGE:
311 network->bridge = netdev;
314 case NETDEV_KIND_BOND:
315 network->bond = netdev;
318 case NETDEV_KIND_VLAN:
319 r = hashmap_put(network->vlans, netdev->ifname, netdev);
321 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
322 "Can not add VLAN '%s' to network: %s",
323 rvalue, strerror(-r));
328 case NETDEV_KIND_MACVLAN:
329 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
331 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
332 "Can not add MACVLAN '%s' to network: %s",
333 rvalue, strerror(-r));
338 case NETDEV_KIND_VXLAN:
339 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
341 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
342 "Can not add VXLAN '%s' to network: %s",
343 rvalue, strerror(-r));
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;