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_path(filename)) {
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(uint64_hash_func, uint64_compare_func);
70 if (!network->macvlans)
73 network->vxlans = hashmap_new(uint64_hash_func, uint64_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, network);
101 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
105 LIST_PREPEND(networks, manager->networks, network);
107 LIST_FOREACH(routes, route, network->static_routes) {
108 if (!route->family) {
109 log_warning("Route section without Gateway field configured in %s. "
110 "Ignoring", filename);
115 LIST_FOREACH(addresses, address, network->static_addresses) {
116 if (!address->family) {
117 log_warning("Address section without Address field configured in %s. "
118 "Ignoring", filename);
128 int network_load(Manager *manager) {
130 _cleanup_strv_free_ char **files = NULL;
136 while ((network = manager->networks))
137 network_free(network);
139 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
141 log_error("Failed to enumerate network files: %s", strerror(-r));
145 STRV_FOREACH_BACKWARDS(f, files) {
146 r = network_load_one(manager, *f);
154 void network_free(Network *network) {
163 free(network->filename);
165 free(network->match_mac);
166 free(network->match_path);
167 free(network->match_driver);
168 free(network->match_type);
169 free(network->match_name);
171 free(network->description);
172 free(network->dhcp_vendor_class_identifier);
174 while ((address = network->ntp)) {
175 LIST_REMOVE(addresses, network->ntp, address);
176 address_free(address);
179 while ((address = network->dns)) {
180 LIST_REMOVE(addresses, network->dns, address);
181 address_free(address);
184 netdev_unref(network->bridge);
186 netdev_unref(network->bond);
188 netdev_unref(network->tunnel);
190 HASHMAP_FOREACH(netdev, network->vlans, i)
191 netdev_unref(netdev);
192 hashmap_free(network->vlans);
194 HASHMAP_FOREACH(netdev, network->macvlans, i)
195 netdev_unref(netdev);
196 hashmap_free(network->macvlans);
198 HASHMAP_FOREACH(netdev, network->vxlans, i)
199 netdev_unref(netdev);
200 hashmap_free(network->vxlans);
202 while ((route = network->static_routes))
205 while ((address = network->static_addresses))
206 address_free(address);
208 hashmap_free(network->addresses_by_section);
209 hashmap_free(network->routes_by_section);
211 if (network->manager && network->manager->networks)
212 LIST_REMOVE(networks, network->manager->networks, network);
214 condition_free_list(network->match_host);
215 condition_free_list(network->match_virt);
216 condition_free_list(network->match_kernel);
217 condition_free_list(network->match_arch);
222 int network_get(Manager *manager, struct udev_device *device,
223 const char *ifname, const struct ether_addr *address,
230 LIST_FOREACH(networks, network, manager->networks) {
231 if (net_match_config(network->match_mac, network->match_path,
232 network->match_driver, network->match_type,
233 network->match_name, network->match_host,
234 network->match_virt, network->match_kernel,
237 udev_device_get_property_value(device, "ID_PATH"),
238 udev_device_get_driver(udev_device_get_parent(device)),
239 udev_device_get_property_value(device, "ID_NET_DRIVER"),
240 udev_device_get_devtype(device),
242 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
254 int network_apply(Manager *manager, Network *network, Link *link) {
257 link->network = network;
259 if (network->dns || network->ntp) {
268 int config_parse_netdev(const char *unit,
269 const char *filename,
272 unsigned section_line,
278 Network *network = userdata;
279 _cleanup_free_ char *kind_string = NULL;
290 kind_string = strdup(lvalue);
294 /* the keys are CamelCase versions of the kind */
295 for (p = kind_string; *p; p++)
298 kind = netdev_kind_from_string(kind_string);
299 if (kind == _NETDEV_KIND_INVALID) {
300 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
301 "Invalid NetDev kind: %s", lvalue);
305 r = netdev_get(network->manager, rvalue, &netdev);
307 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
308 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
312 if (netdev->kind != kind) {
313 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
314 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
319 case NETDEV_KIND_BRIDGE:
320 network->bridge = netdev;
323 case NETDEV_KIND_BOND:
324 network->bond = netdev;
327 case NETDEV_KIND_VLAN:
328 r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
330 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
331 "Can not add VLAN to network: %s", rvalue);
336 case NETDEV_KIND_MACVLAN:
337 r = hashmap_put(network->macvlans, netdev->ifname, netdev);
339 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
340 "Can not add MACVLAN to network: %s", rvalue);
345 case NETDEV_KIND_VXLAN:
346 r = hashmap_put(network->vxlans, netdev->ifname, netdev);
348 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
349 "Can not add VXLAN to network: %s", rvalue);
355 assert_not_reached("Can not parse NetDev");
363 int config_parse_tunnel(const char *unit,
364 const char *filename,
367 unsigned section_line,
373 Network *network = userdata;
382 r = netdev_get(network->manager, rvalue, &netdev);
384 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
385 "Tunnel is invalid, ignoring assignment: %s", rvalue);
389 if (netdev->kind != NETDEV_KIND_IPIP &&
390 netdev->kind != NETDEV_KIND_SIT &&
391 netdev->kind != NETDEV_KIND_GRE &&
392 netdev->kind != NETDEV_KIND_VTI) {
393 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
394 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
398 network->tunnel = netdev;