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,
279 LIST_FOREACH(networks, network, manager->networks) {
280 if (net_match_config(network->match_mac, network->match_path,
281 network->match_driver, network->match_type,
282 network->match_name, network->match_host,
283 network->match_virt, network->match_kernel,
286 udev_device_get_property_value(device, "ID_PATH"),
287 udev_device_get_driver(udev_device_get_parent(device)),
288 udev_device_get_property_value(device, "ID_NET_DRIVER"),
289 udev_device_get_devtype(device),
291 if (network->match_name) {
293 uint8_t name_assign_type = NET_NAME_UNKNOWN;
295 attr = udev_device_get_sysattr_value(device, "name_assign_type");
297 (void) safe_atou8(attr, &name_assign_type);
299 if (name_assign_type == NET_NAME_ENUM)
300 log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
301 IFNAMSIZ, ifname, network->filename);
303 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
305 log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
317 int network_apply(Manager *manager, Network *network, Link *link) {
320 link->network = network;
322 if (network->ipv4ll_route) {
325 r = route_new_static(network, 0, &route);
329 r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
335 route->family = AF_INET;
336 route->dst_prefixlen = 16;
337 route->scope = RT_SCOPE_LINK;
338 route->metrics = IPV4LL_ROUTE_METRIC;
339 route->protocol = RTPROT_STATIC;
342 if (network->dns || network->ntp) {
351 int config_parse_netdev(const char *unit,
352 const char *filename,
355 unsigned section_line,
361 Network *network = userdata;
362 _cleanup_free_ char *kind_string = NULL;
373 kind_string = strdup(lvalue);
377 /* the keys are CamelCase versions of the kind */
378 for (p = kind_string; *p; p++)
381 kind = netdev_kind_from_string(kind_string);
382 if (kind == _NETDEV_KIND_INVALID) {
383 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
384 "Invalid NetDev kind: %s", lvalue);
388 r = netdev_get(network->manager, rvalue, &netdev);
390 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
391 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
395 if (netdev->kind != kind) {
396 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
397 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
402 case NETDEV_KIND_BRIDGE:
403 network->bridge = netdev;
406 case NETDEV_KIND_BOND:
407 network->bond = netdev;
410 case NETDEV_KIND_VLAN:
411 case NETDEV_KIND_MACVLAN:
412 case NETDEV_KIND_IPVLAN:
413 case NETDEV_KIND_VXLAN:
414 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
416 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
417 "Can not add VLAN '%s' to network: %s",
418 rvalue, strerror(-r));
424 assert_not_reached("Can not parse NetDev");
432 int config_parse_domains(const char *unit,
433 const char *filename,
436 unsigned section_line,
442 Network *network = userdata;
443 char ***domains = data;
447 r = config_parse_strv(unit, filename, line, section, section_line,
448 lvalue, ltype, rvalue, domains, userdata);
453 network->wildcard_domain = !!strv_find(*domains, "*");
455 STRV_FOREACH(domain, *domains) {
456 if (is_localhost(*domain))
457 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
458 else if (!hostname_is_valid(*domain)) {
459 if (!streq(*domain, "*"))
460 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
464 strv_remove(*domains, *domain);
466 /* We removed one entry, make sure we don't skip the next one */
473 int config_parse_tunnel(const char *unit,
474 const char *filename,
477 unsigned section_line,
483 Network *network = userdata;
492 r = netdev_get(network->manager, rvalue, &netdev);
494 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
495 "Tunnel is invalid, ignoring assignment: %s", rvalue);
499 if (netdev->kind != NETDEV_KIND_IPIP &&
500 netdev->kind != NETDEV_KIND_SIT &&
501 netdev->kind != NETDEV_KIND_GRE &&
502 netdev->kind != NETDEV_KIND_GRETAP &&
503 netdev->kind != NETDEV_KIND_IP6GRE &&
504 netdev->kind != NETDEV_KIND_IP6GRETAP &&
505 netdev->kind != NETDEV_KIND_VTI &&
506 netdev->kind != NETDEV_KIND_IP6TNL
508 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
509 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
513 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
515 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
516 "Can not add VLAN '%s' to network: %s",
517 rvalue, strerror(-r));
526 int config_parse_ipv4ll(
528 const char *filename,
531 unsigned section_line,
538 AddressFamilyBoolean *link_local = data;
545 /* Note that this is mostly like
546 * config_parse_address_family_boolean(), except that it
547 * applies only to IPv4 */
549 if (parse_boolean(rvalue))
550 *link_local |= ADDRESS_FAMILY_IPV4;
552 *link_local &= ~ADDRESS_FAMILY_IPV4;
557 int config_parse_dhcp(
559 const char *filename,
562 unsigned section_line,
569 AddressFamilyBoolean *dhcp = data, s;
576 /* Note that this is mostly like
577 * config_parse_address_family_boolean(), except that it
578 * understands some old names for the enum values */
580 s = address_family_boolean_from_string(rvalue);
583 /* Previously, we had a slightly different enum here,
584 * support its values for compatbility. */
586 if (streq(rvalue, "none"))
587 s = ADDRESS_FAMILY_NO;
588 else if (streq(rvalue, "v4"))
589 s = ADDRESS_FAMILY_IPV4;
590 else if (streq(rvalue, "v6"))
591 s = ADDRESS_FAMILY_IPV6;
592 else if (streq(rvalue, "both"))
593 s = ADDRESS_FAMILY_YES;
595 log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
604 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
605 [DHCP_CLIENT_ID_MAC] = "mac",
606 [DHCP_CLIENT_ID_DUID] = "duid"
609 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
610 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
612 static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
613 [LLMNR_SUPPORT_NO] = "no",
614 [LLMNR_SUPPORT_YES] = "yes",
615 [LLMNR_SUPPORT_RESOLVE] = "resolve",
618 DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
620 int config_parse_llmnr(
622 const char *filename,
625 unsigned section_line,
632 LLMNRSupport *llmnr = data;
640 /* Our enum shall be a superset of booleans, hence first try
641 * to parse as boolean, and then as enum */
643 k = parse_boolean(rvalue);
645 *llmnr = LLMNR_SUPPORT_YES;
647 *llmnr = LLMNR_SUPPORT_NO;
651 s = llmnr_support_from_string(rvalue);
653 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
663 int config_parse_ipv6token(
665 const char *filename,
668 unsigned section_line,
675 union in_addr_union buffer;
676 struct in6_addr *token = data;
684 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
686 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
690 r = in_addr_is_null(AF_INET6, &buffer);
692 log_syntax(unit, LOG_ERR, filename, line, -r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
696 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
697 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);