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/>.
25 #include "conf-files.h"
26 #include "conf-parser.h"
29 #include "networkd-netdev.h"
30 #include "networkd-link.h"
31 #include "network-internal.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;
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);
65 LIST_HEAD_INIT(network->static_fdb_entries);
67 network->stacked_netdevs = hashmap_new(&string_hash_ops);
68 if (!network->stacked_netdevs)
71 network->addresses_by_section = hashmap_new(NULL);
72 if (!network->addresses_by_section)
75 network->routes_by_section = hashmap_new(NULL);
76 if (!network->routes_by_section)
79 network->fdb_entries_by_section = hashmap_new(NULL);
80 if (!network->fdb_entries_by_section)
83 network->filename = strdup(filename);
84 if (!network->filename)
87 network->name = strdup(basename(filename));
91 d = strrchr(network->name, '.');
95 assert(streq(d, ".network"));
99 network->dhcp = ADDRESS_FAMILY_NO;
100 network->dhcp_ntp = true;
101 network->dhcp_dns = true;
102 network->dhcp_hostname = true;
103 network->dhcp_routes = true;
104 network->dhcp_sendhost = true;
105 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
106 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
108 network->llmnr = LLMNR_SUPPORT_YES;
110 network->link_local = ADDRESS_FAMILY_IPV6;
112 r = config_parse(NULL, filename, file,
122 config_item_perf_lookup, network_network_gperf_lookup,
123 false, false, true, network);
127 /* IPMasquerade=yes implies IPForward=yes */
128 if (network->ip_masquerade)
129 network->ip_forward |= ADDRESS_FAMILY_IPV4;
131 LIST_PREPEND(networks, manager->networks, network);
133 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
137 r = hashmap_put(manager->networks_by_name, network->name, network);
141 LIST_FOREACH(routes, route, network->static_routes) {
142 if (!route->family) {
143 log_warning("Route section without Gateway field configured in %s. "
144 "Ignoring", filename);
149 LIST_FOREACH(addresses, address, network->static_addresses) {
150 if (!address->family) {
151 log_warning("Address section without Address field configured in %s. "
152 "Ignoring", filename);
162 int network_load(Manager *manager) {
164 _cleanup_strv_free_ char **files = NULL;
170 while ((network = manager->networks))
171 network_free(network);
173 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
175 return log_error_errno(r, "Failed to enumerate network files: %m");
177 STRV_FOREACH_BACKWARDS(f, files) {
178 r = network_load_one(manager, *f);
186 void network_free(Network *network) {
196 free(network->filename);
198 free(network->match_mac);
199 strv_free(network->match_path);
200 strv_free(network->match_driver);
201 strv_free(network->match_type);
202 strv_free(network->match_name);
204 free(network->description);
205 free(network->dhcp_vendor_class_identifier);
209 strv_free(network->ntp);
210 strv_free(network->dns);
211 strv_free(network->domains);
212 strv_free(network->bind_carrier);
214 netdev_unref(network->bridge);
216 netdev_unref(network->bond);
218 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
219 hashmap_remove(network->stacked_netdevs, netdev->ifname);
220 netdev_unref(netdev);
222 hashmap_free(network->stacked_netdevs);
224 while ((route = network->static_routes))
227 while ((address = network->static_addresses))
228 address_free(address);
230 while ((fdb_entry = network->static_fdb_entries))
231 fdb_entry_free(fdb_entry);
233 hashmap_free(network->addresses_by_section);
234 hashmap_free(network->routes_by_section);
235 hashmap_free(network->fdb_entries_by_section);
237 if (network->manager) {
238 if (network->manager->networks)
239 LIST_REMOVE(networks, network->manager->networks, network);
241 if (network->manager->networks_by_name)
242 hashmap_remove(network->manager->networks_by_name, network->name);
247 condition_free_list(network->match_host);
248 condition_free_list(network->match_virt);
249 condition_free_list(network->match_kernel);
250 condition_free_list(network->match_arch);
255 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
262 network = hashmap_get(manager->networks_by_name, name);
271 int network_get(Manager *manager, struct udev_device *device,
272 const char *ifname, const struct ether_addr *address,
275 struct udev_device *parent;
276 const char *path, *parent_driver, *driver, *devtype;
282 path = udev_device_get_property_value(device, "ID_PATH");
284 parent = udev_device_get_parent(device);
286 parent_driver = udev_device_get_driver(parent);
288 parent_driver = NULL;
290 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
292 devtype = udev_device_get_devtype(device);
294 LIST_FOREACH(networks, network, manager->networks) {
295 if (net_match_config(network->match_mac, network->match_path,
296 network->match_driver, network->match_type,
297 network->match_name, network->match_host,
298 network->match_virt, network->match_kernel,
300 address, path, parent_driver, driver,
302 if (network->match_name) {
304 uint8_t name_assign_type = NET_NAME_UNKNOWN;
306 attr = udev_device_get_sysattr_value(device, "name_assign_type");
308 (void) safe_atou8(attr, &name_assign_type);
310 if (name_assign_type == NET_NAME_ENUM)
311 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
312 IFNAMSIZ, ifname, network->filename);
314 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
316 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
328 int network_apply(Manager *manager, Network *network, Link *link) {
331 link->network = network;
333 if (network->ipv4ll_route) {
336 r = route_new_static(network, 0, &route);
340 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
346 route->family = AF_INET;
347 route->dst_prefixlen = 16;
348 route->scope = RT_SCOPE_LINK;
349 route->metrics = IPV4LL_ROUTE_METRIC;
350 route->protocol = RTPROT_STATIC;
353 if (network->dns || network->ntp) {
362 int config_parse_netdev(const char *unit,
363 const char *filename,
366 unsigned section_line,
372 Network *network = userdata;
373 _cleanup_free_ char *kind_string = NULL;
384 kind_string = strdup(lvalue);
388 /* the keys are CamelCase versions of the kind */
389 for (p = kind_string; *p; p++)
392 kind = netdev_kind_from_string(kind_string);
393 if (kind == _NETDEV_KIND_INVALID) {
394 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
395 "Invalid NetDev kind: %s", lvalue);
399 r = netdev_get(network->manager, rvalue, &netdev);
401 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
402 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
406 if (netdev->kind != kind) {
407 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
408 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
413 case NETDEV_KIND_BRIDGE:
414 network->bridge = netdev;
417 case NETDEV_KIND_BOND:
418 network->bond = netdev;
421 case NETDEV_KIND_VLAN:
422 case NETDEV_KIND_MACVLAN:
423 case NETDEV_KIND_IPVLAN:
424 case NETDEV_KIND_VXLAN:
425 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
427 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
428 "Can not add VLAN '%s' to network: %s",
429 rvalue, strerror(-r));
435 assert_not_reached("Can not parse NetDev");
443 int config_parse_domains(const char *unit,
444 const char *filename,
447 unsigned section_line,
453 Network *network = userdata;
454 char ***domains = data;
458 r = config_parse_strv(unit, filename, line, section, section_line,
459 lvalue, ltype, rvalue, domains, userdata);
464 network->wildcard_domain = !!strv_find(*domains, "*");
466 STRV_FOREACH(domain, *domains) {
467 if (is_localhost(*domain))
468 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
469 else if (!hostname_is_valid(*domain)) {
470 if (!streq(*domain, "*"))
471 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
475 strv_remove(*domains, *domain);
477 /* We removed one entry, make sure we don't skip the next one */
484 int config_parse_tunnel(const char *unit,
485 const char *filename,
488 unsigned section_line,
494 Network *network = userdata;
503 r = netdev_get(network->manager, rvalue, &netdev);
505 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
506 "Tunnel is invalid, ignoring assignment: %s", rvalue);
510 if (netdev->kind != NETDEV_KIND_IPIP &&
511 netdev->kind != NETDEV_KIND_SIT &&
512 netdev->kind != NETDEV_KIND_GRE &&
513 netdev->kind != NETDEV_KIND_GRETAP &&
514 netdev->kind != NETDEV_KIND_IP6GRE &&
515 netdev->kind != NETDEV_KIND_IP6GRETAP &&
516 netdev->kind != NETDEV_KIND_VTI &&
517 netdev->kind != NETDEV_KIND_IP6TNL
519 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
520 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
524 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
526 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
527 "Can not add VLAN '%s' to network: %s",
528 rvalue, strerror(-r));
537 int config_parse_ipv4ll(
539 const char *filename,
542 unsigned section_line,
549 AddressFamilyBoolean *link_local = data;
556 /* Note that this is mostly like
557 * config_parse_address_family_boolean(), except that it
558 * applies only to IPv4 */
560 if (parse_boolean(rvalue))
561 *link_local |= ADDRESS_FAMILY_IPV4;
563 *link_local &= ~ADDRESS_FAMILY_IPV4;
568 int config_parse_dhcp(
570 const char *filename,
573 unsigned section_line,
580 AddressFamilyBoolean *dhcp = data, s;
587 /* Note that this is mostly like
588 * config_parse_address_family_boolean(), except that it
589 * understands some old names for the enum values */
591 s = address_family_boolean_from_string(rvalue);
594 /* Previously, we had a slightly different enum here,
595 * support its values for compatbility. */
597 if (streq(rvalue, "none"))
598 s = ADDRESS_FAMILY_NO;
599 else if (streq(rvalue, "v4"))
600 s = ADDRESS_FAMILY_IPV4;
601 else if (streq(rvalue, "v6"))
602 s = ADDRESS_FAMILY_IPV6;
603 else if (streq(rvalue, "both"))
604 s = ADDRESS_FAMILY_YES;
606 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
615 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
616 [DHCP_CLIENT_ID_MAC] = "mac",
617 [DHCP_CLIENT_ID_DUID] = "duid"
620 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
621 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
623 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
624 [LLMNR_SUPPORT_NO] = "no",
625 [LLMNR_SUPPORT_YES] = "yes",
626 [LLMNR_SUPPORT_RESOLVE] = "resolve",
629 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
631 int config_parse_llmnr(
633 const char *filename,
636 unsigned section_line,
643 LLMNRSupport *llmnr = data;
651 /* Our enum shall be a superset of booleans, hence first try
652 * to parse as boolean, and then as enum */
654 k = parse_boolean(rvalue);
656 *llmnr = LLMNR_SUPPORT_YES;
658 *llmnr = LLMNR_SUPPORT_NO;
662 s = llmnr_support_from_string(rvalue);
664 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
674 int config_parse_ipv6token(
676 const char *filename,
679 unsigned section_line,
686 union in_addr_union buffer;
687 struct in6_addr *token = data;
695 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
697 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
701 r = in_addr_is_null(AF_INET6, &buffer);
703 log_syntax(unit, LOG_ERR, filename, line, -r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
707 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
708 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);