networkd-network.c revision 1ac608c9ccb6b69a6bc8a458e10a05e0fc9a8301
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright 2013 Tom Gundersen <teg@jklm.no>
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer systemd is free software; you can redistribute it and/or modify it
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer under the terms of the GNU Lesser General Public License as published by
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer the Free Software Foundation; either version 2.1 of the License, or
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt (at your option) any later version.
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt systemd is distributed in the hope that it will be useful, but
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt WITHOUT ANY WARRANTY; without even the implied warranty of
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4be4833ece2856e0cacc09f8f8b2c02b320751faMartin Pitt Lesser General Public License for more details.
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier You should have received a copy of the GNU Lesser General Public License
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalierstatic int network_load_one(Manager *manager, const char *filename) {
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier _cleanup_network_free_ Network *network = NULL;
61fea35e14d84144e6e2122f5cd247f9c7e6245eEvgeny Vereshchagin log_debug("Skipping empty file: %s", filename);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier network->stacked_netdevs = hashmap_new(&string_hash_ops);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier network->addresses_by_section = hashmap_new(NULL);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier network->routes_by_section = hashmap_new(NULL);
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier network->fdb_entries_by_section = hashmap_new(NULL);
8a8332f77e61d41f3bb28b8f929ed41e0ffaf721Zbigniew Jędrzejewski-Szmek network->name = strdup(basename(filename));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier network->dhcp_route_metric = DHCP_ROUTE_METRIC;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier "BridgeFDB\0",
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier config_item_perf_lookup, network_network_gperf_lookup,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier false, false, true, network);
2375607039517c88df51ef16ddbb624ec1c10654Kay Sievers /* IPMasquerade=yes implies IPForward=yes */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier LIST_PREPEND(networks, manager->networks, network);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = hashmap_put(manager->networks_by_name, network->name, network);
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek LIST_FOREACH(routes, route, network->static_routes) {
1b1eae69ce52ef6c89a1200e8d3758549b291991Daniel Mack log_warning("Route section without Gateway field configured in %s. "
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier LIST_FOREACH(addresses, address, network->static_addresses) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Address section without Address field configured in %s. "
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return log_error_errno(r, "Failed to enumerate network files: %m");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier free(network->dhcp_vendor_class_identifier);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier hashmap_remove(network->stacked_netdevs, netdev->ifname);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier while ((address = network->static_addresses))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier while ((fdb_entry = network->static_fdb_entries))
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier hashmap_free(network->addresses_by_section);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier hashmap_free(network->fdb_entries_by_section);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier LIST_REMOVE(networks, network->manager->networks, network);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier hashmap_remove(network->manager->networks_by_name, network->name);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierint network_get_by_name(Manager *manager, const char *name, Network **ret) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier network = hashmap_get(manager->networks_by_name, name);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierint network_get(Manager *manager, struct udev_device *device,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier const char *ifname, const struct ether_addr *address,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier path = udev_device_get_property_value(device, "ID_PATH");
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin parent = udev_device_get_parent(device);
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin parent_driver = udev_device_get_driver(parent);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier LIST_FOREACH(networks, network, manager->networks) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (net_match_config(network->match_mac, network->match_path,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier uint8_t name_assign_type = NET_NAME_UNKNOWN;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier attr = udev_device_get_sysattr_value(device, "name_assign_type");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierint network_apply(Manager *manager, Network *network, Link *link) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* the keys are CamelCase versions of the kind */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier for (p = kind_string; *p; p++)
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier kind = netdev_kind_from_string(kind_string);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = netdev_get(network->manager, rvalue, &netdev);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer "Can not add VLAN '%s' to network: %m",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = config_parse_strv(unit, filename, line, section, section_line,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer network->wildcard_domain = !!strv_find(*domains, "*");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* We removed one entry, make sure we don't skip the next one */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = netdev_get(network->manager, rvalue, &netdev);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char* unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Note that this is mostly like
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * config_parse_address_family_boolean(), except that it
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * applies only to IPv4 */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char* unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Note that this is mostly like
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * config_parse_address_family_boolean(), except that it
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * understands some old names for the enum values */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = address_family_boolean_from_string(rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (s < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Previously, we had a slightly different enum here,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * support its values for compatbility. */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_STRING_TABLE_LOOKUP(resolve_support, ResolveSupport);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char* unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Our enum shall be a superset of booleans, hence first try
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * to parse as boolean, and then as enum */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else if (k == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s option, ignoring: %s", lvalue, rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char* unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = in_addr_from_string(AF_INET6, rvalue, &buffer);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint config_parse_address_family_boolean_with_kernel(
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char* unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = address_family_boolean_from_string(rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (s < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding option, ignoring: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char* unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* Our enum shall be a superset of booleans, hence first try
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * to parse as boolean, and then as enum */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else if (k == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer s = ipv6_privacy_extensions_from_string(rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (s < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer const char *unit,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue);