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 "networkd-link.h"
28 #include "network-internal.h"
29 #include "path-util.h"
30 #include "conf-files.h"
31 #include "conf-parser.h"
34 static int network_load_one(Manager *manager, const char *filename) {
35 _cleanup_network_free_ Network *network = NULL;
36 _cleanup_fclose_ FILE *file = NULL;
44 file = fopen(filename, "re");
52 if (null_or_empty_fd(fileno(file))) {
53 log_debug("Skipping empty file: %s", filename);
57 network = new0(Network, 1);
61 network->manager = manager;
63 LIST_HEAD_INIT(network->static_addresses);
64 LIST_HEAD_INIT(network->static_routes);
66 network->stacked_netdevs = hashmap_new(&string_hash_ops);
67 if (!network->stacked_netdevs)
70 network->addresses_by_section = hashmap_new(NULL);
71 if (!network->addresses_by_section)
74 network->routes_by_section = hashmap_new(NULL);
75 if (!network->routes_by_section)
78 network->filename = strdup(filename);
79 if (!network->filename)
82 network->dhcp = DHCP_SUPPORT_NONE;
83 network->dhcp_ntp = true;
84 network->dhcp_dns = true;
85 network->dhcp_hostname = true;
86 network->dhcp_routes = true;
87 network->dhcp_sendhost = true;
88 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
90 network->llmnr = LLMNR_SUPPORT_YES;
92 r = config_parse(NULL, filename, file,
101 config_item_perf_lookup, network_network_gperf_lookup,
102 false, false, true, network);
106 LIST_PREPEND(networks, manager->networks, network);
108 LIST_FOREACH(routes, route, network->static_routes) {
109 if (!route->family) {
110 log_warning("Route section without Gateway field configured in %s. "
111 "Ignoring", filename);
116 LIST_FOREACH(addresses, address, network->static_addresses) {
117 if (!address->family) {
118 log_warning("Address section without Address field configured in %s. "
119 "Ignoring", filename);
129 int network_load(Manager *manager) {
131 _cleanup_strv_free_ char **files = NULL;
137 while ((network = manager->networks))
138 network_free(network);
140 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
142 return log_error_errno(r, "Failed to enumerate network files: %m");
144 STRV_FOREACH_BACKWARDS(f, files) {
145 r = network_load_one(manager, *f);
153 void network_free(Network *network) {
162 free(network->filename);
164 free(network->match_mac);
165 free(network->match_path);
166 free(network->match_driver);
167 free(network->match_type);
168 free(network->match_name);
170 free(network->description);
171 free(network->dhcp_vendor_class_identifier);
175 strv_free(network->ntp);
176 strv_free(network->dns);
177 strv_free(network->domains);
179 netdev_unref(network->bridge);
181 netdev_unref(network->bond);
183 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
184 hashmap_remove(network->stacked_netdevs, netdev->ifname);
185 netdev_unref(netdev);
187 hashmap_free(network->stacked_netdevs);
189 while ((route = network->static_routes))
192 while ((address = network->static_addresses))
193 address_free(address);
195 hashmap_free(network->addresses_by_section);
196 hashmap_free(network->routes_by_section);
198 if (network->manager && network->manager->networks)
199 LIST_REMOVE(networks, network->manager->networks, network);
201 condition_free_list(network->match_host);
202 condition_free_list(network->match_virt);
203 condition_free_list(network->match_kernel);
204 condition_free_list(network->match_arch);
209 int network_get(Manager *manager, struct udev_device *device,
210 const char *ifname, const struct ether_addr *address,
217 LIST_FOREACH(networks, network, manager->networks) {
218 if (net_match_config(network->match_mac, network->match_path,
219 network->match_driver, network->match_type,
220 network->match_name, network->match_host,
221 network->match_virt, network->match_kernel,
224 udev_device_get_property_value(device, "ID_PATH"),
225 udev_device_get_driver(udev_device_get_parent(device)),
226 udev_device_get_property_value(device, "ID_NET_DRIVER"),
227 udev_device_get_devtype(device),
229 if (network->match_name) {
231 uint8_t name_assign_type = NET_NAME_UNKNOWN;
233 attr = udev_device_get_sysattr_value(device, "name_assign_type");
235 (void)safe_atou8(attr, &name_assign_type);
237 if (name_assign_type == NET_NAME_ENUM)
238 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
239 IFNAMSIZ, ifname, network->filename);
241 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
243 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
255 int network_apply(Manager *manager, Network *network, Link *link) {
258 link->network = network;
260 if (network->ipv4ll_route) {
263 r = route_new_static(network, 0, &route);
267 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
273 route->family = AF_INET;
274 route->dst_prefixlen = 16;
275 route->scope = RT_SCOPE_LINK;
276 route->metrics = IPV4LL_ROUTE_METRIC;
277 route->protocol = RTPROT_STATIC;
280 if (network->dns || network->ntp) {
289 int config_parse_netdev(const char *unit,
290 const char *filename,
293 unsigned section_line,
299 Network *network = userdata;
300 _cleanup_free_ char *kind_string = NULL;
311 kind_string = strdup(lvalue);
315 /* the keys are CamelCase versions of the kind */
316 for (p = kind_string; *p; p++)
319 kind = netdev_kind_from_string(kind_string);
320 if (kind == _NETDEV_KIND_INVALID) {
321 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
322 "Invalid NetDev kind: %s", lvalue);
326 r = netdev_get(network->manager, rvalue, &netdev);
328 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
329 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
333 if (netdev->kind != kind) {
334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
335 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
340 case NETDEV_KIND_BRIDGE:
341 network->bridge = netdev;
344 case NETDEV_KIND_BOND:
345 network->bond = netdev;
348 case NETDEV_KIND_VLAN:
349 case NETDEV_KIND_MACVLAN:
350 case NETDEV_KIND_VXLAN:
351 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
353 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
354 "Can not add VLAN '%s' to network: %s",
355 rvalue, strerror(-r));
361 assert_not_reached("Can not parse NetDev");
369 int config_parse_domains(const char *unit,
370 const char *filename,
373 unsigned section_line,
379 Network *network = userdata;
380 char ***domains = data;
384 r = config_parse_strv(unit, filename, line, section, section_line,
385 lvalue, ltype, rvalue, domains, userdata);
390 network->wildcard_domain = !!strv_find(*domains, "*");
392 STRV_FOREACH(domain, *domains) {
393 if (is_localhost(*domain))
394 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
395 else if (!hostname_is_valid(*domain)) {
396 if (!streq(*domain, "*"))
397 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
401 strv_remove(*domains, *domain);
403 /* We removed one entry, make sure we don't skip the next one */
410 int config_parse_tunnel(const char *unit,
411 const char *filename,
414 unsigned section_line,
420 Network *network = userdata;
429 r = netdev_get(network->manager, rvalue, &netdev);
431 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
432 "Tunnel is invalid, ignoring assignment: %s", rvalue);
436 if (netdev->kind != NETDEV_KIND_IPIP &&
437 netdev->kind != NETDEV_KIND_SIT &&
438 netdev->kind != NETDEV_KIND_GRE &&
439 netdev->kind != NETDEV_KIND_VTI) {
440 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
441 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
445 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
447 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
448 "Can not add VLAN '%s' to network: %s",
449 rvalue, strerror(-r));
458 static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
459 [DHCP_SUPPORT_NONE] = "none",
460 [DHCP_SUPPORT_BOTH] = "both",
461 [DHCP_SUPPORT_V4] = "v4",
462 [DHCP_SUPPORT_V6] = "v6",
465 DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
467 int config_parse_dhcp(
469 const char *filename,
472 unsigned section_line,
479 DHCPSupport *dhcp = data;
487 /* Our enum shall be a superset of booleans, hence first try
488 * to parse as boolean, and then as enum */
490 k = parse_boolean(rvalue);
492 *dhcp = DHCP_SUPPORT_BOTH;
494 *dhcp = DHCP_SUPPORT_NONE;
498 s = dhcp_support_from_string(rvalue);
500 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
510 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
511 [LLMNR_SUPPORT_NO] = "no",
512 [LLMNR_SUPPORT_YES] = "yes",
513 [LLMNR_SUPPORT_RESOLVE] = "resolve",
516 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
518 int config_parse_llmnr(
520 const char *filename,
523 unsigned section_line,
530 LLMNRSupport *llmnr = data;
538 /* Our enum shall be a superset of booleans, hence first try
539 * to parse as boolean, and then as enum */
541 k = parse_boolean(rvalue);
543 *llmnr = LLMNR_SUPPORT_YES;
545 *llmnr = LLMNR_SUPPORT_NO;
549 s = llmnr_support_from_string(rvalue);
551 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);