networkd-network.c revision 9011ce771f149ba45e8ffdb2ae4f0950cdbc6b8b
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik/***
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik This file is part of systemd.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Copyright 2013 Tom Gundersen <teg@jklm.no>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik systemd is free software; you can redistribute it and/or modify it
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik under the terms of the GNU Lesser General Public License as published by
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik the Free Software Foundation; either version 2.1 of the License, or
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik (at your option) any later version.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik systemd is distributed in the hope that it will be useful, but
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik WITHOUT ANY WARRANTY; without even the implied warranty of
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Lesser General Public License for more details.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik You should have received a copy of the GNU Lesser General Public License
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik along with systemd; If not, see <http://www.gnu.org/licenses/>.
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik***/
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <ctype.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include <net/if.h>
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "conf-files.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "conf-parser.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "util.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "networkd.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "networkd-netdev.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "networkd-link.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik#include "network-internal.h"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikstatic int network_load_one(Manager *manager, const char *filename) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik _cleanup_network_free_ Network *network = NULL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik _cleanup_fclose_ FILE *file = NULL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik char *d;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Route *route;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Address *address;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(manager);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(filename);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik file = fopen(filename, "re");
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!file) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (errno == ENOENT)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return 0;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik else
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -errno;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (null_or_empty_fd(fileno(file))) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik log_debug("Skipping empty file: %s", filename);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return 0;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network = new0(Network, 1);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik network->manager = manager;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik LIST_HEAD_INIT(network->static_addresses);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik LIST_HEAD_INIT(network->static_routes);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik LIST_HEAD_INIT(network->static_fdb_entries);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->stacked_netdevs = hashmap_new(&string_hash_ops);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network->stacked_netdevs)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->addresses_by_section = hashmap_new(NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network->addresses_by_section)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->routes_by_section = hashmap_new(NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network->routes_by_section)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->fdb_entries_by_section = hashmap_new(NULL);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network->fdb_entries_by_section)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->filename = strdup(filename);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network->filename)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->name = strdup(basename(filename));
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network->name)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_oom();
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik d = strrchr(network->name, '.');
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!d)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return -EINVAL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(streq(d, ".network"));
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik *d = '\0';
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp = ADDRESS_FAMILY_NO;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_ntp = true;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_dns = true;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_hostname = true;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_routes = true;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_sendhost = true;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_route_metric = DHCP_ROUTE_METRIC;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->llmnr = LLMNR_SUPPORT_YES;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->link_local = ADDRESS_FAMILY_IPV6;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik r = config_parse(NULL, filename, file,
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Match\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Link\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Network\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Address\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Route\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "DHCP\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "DHCPv4\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Bridge\0"
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "BridgeFDB\0",
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik config_item_perf_lookup, network_network_gperf_lookup,
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik false, false, true, network);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (r < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik /* IPMasquerade=yes implies IPForward=yes */
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (network->ip_masquerade)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network->ip_forward |= ADDRESS_FAMILY_IPV4;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik LIST_PREPEND(networks, manager->networks, network);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (r < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik r = hashmap_put(manager->networks_by_name, network->name, network);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (r < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik LIST_FOREACH(routes, route, network->static_routes) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!route->family) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik log_warning("Route section without Gateway field configured in %s. "
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Ignoring", filename);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return 0;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik LIST_FOREACH(addresses, address, network->static_addresses) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!address->family) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik log_warning("Address section without Address field configured in %s. "
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik "Ignoring", filename);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return 0;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network = NULL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return 0;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik}
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikint network_load(Manager *manager) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Network *network;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik _cleanup_strv_free_ char **files = NULL;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik char **f;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik int r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(manager);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik while ((network = manager->networks))
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik network_free(network);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (r < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return log_error_errno(r, "Failed to enumerate network files: %m");
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik STRV_FOREACH_BACKWARDS(f, files) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik r = network_load_one(manager, *f);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (r < 0)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return r;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik }
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return 0;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik}
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvikvoid network_free(Network *network) {
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik NetDev *netdev;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Route *route;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Address *address;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik FdbEntry *fdb_entry;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik Iterator i;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik if (!network)
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik return;
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik free(network->filename);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik free(network->match_mac);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik strv_free(network->match_path);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik strv_free(network->match_driver);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik strv_free(network->match_type);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik strv_free(network->match_name);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik free(network->description);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik free(network->dhcp_vendor_class_identifier);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik free(network->mac);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik strv_free(network->ntp);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik strv_free(network->dns);
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen strv_free(network->domains);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik strv_free(network->bind_carrier);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik netdev_unref(network->bridge);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik netdev_unref(network->bond);
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik hashmap_remove(network->stacked_netdevs, netdev->ifname);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik netdev_unref(netdev);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik }
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik hashmap_free(network->stacked_netdevs);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik while ((route = network->static_routes))
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik route_free(route);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik while ((address = network->static_addresses))
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik address_free(address);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen while ((fdb_entry = network->static_fdb_entries))
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen fdb_entry_free(fdb_entry);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik hashmap_free(network->addresses_by_section);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik hashmap_free(network->routes_by_section);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik hashmap_free(network->fdb_entries_by_section);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (network->manager) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (network->manager->networks)
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen LIST_REMOVE(networks, network->manager->networks, network);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (network->manager->networks_by_name)
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik hashmap_remove(network->manager->networks_by_name, network->name);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik }
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik free(network->name);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik condition_free_list(network->match_host);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik condition_free_list(network->match_virt);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik condition_free_list(network->match_kernel);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik condition_free_list(network->match_arch);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik free(network);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik}
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvikint network_get_by_name(Manager *manager, const char *name, Network **ret) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik Network *network;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(manager);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(name);
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen assert(ret);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen network = hashmap_get(manager->networks_by_name, name);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik if (!network)
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik return -ENOENT;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik *ret = network;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik return 0;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik}
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvikint network_get(Manager *manager, struct udev_device *device,
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik const char *ifname, const struct ether_addr *address,
71e31fc573ba527f0d2be7929c2cb98037c860ecKnut Anders Hatlen Network **ret) {
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik Network *network;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik struct udev_device *parent;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik const char *path, *parent_driver, *driver, *devtype;
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(manager);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik assert(ret);
8d22687fbdc540bd0b4d05fd90d87fb6037f4b9fJorgen Austvik assert(device);
381a9b85cf2c73401fc1bff06c2e0d86389a5e88Jorgen Austvik
path = udev_device_get_property_value(device, "ID_PATH");
parent = udev_device_get_parent(device);
if (parent)
parent_driver = udev_device_get_driver(parent);
else
parent_driver = NULL;
driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
devtype = udev_device_get_devtype(device);
LIST_FOREACH(networks, network, manager->networks) {
if (net_match_config(network->match_mac, network->match_path,
network->match_driver, network->match_type,
network->match_name, network->match_host,
network->match_virt, network->match_kernel,
network->match_arch,
address, path, parent_driver, driver,
devtype, ifname)) {
if (network->match_name) {
const char *attr;
uint8_t name_assign_type = NET_NAME_UNKNOWN;
attr = udev_device_get_sysattr_value(device, "name_assign_type");
if (attr)
(void) safe_atou8(attr, &name_assign_type);
if (name_assign_type == NET_NAME_ENUM)
log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
IFNAMSIZ, ifname, network->filename);
else
log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
} else
log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
*ret = network;
return 0;
}
}
*ret = NULL;
return -ENOENT;
}
int network_apply(Manager *manager, Network *network, Link *link) {
int r;
link->network = network;
if (network->ipv4ll_route) {
Route *route;
r = route_new_static(network, 0, &route);
if (r < 0)
return r;
r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
if (r == 0)
return -EINVAL;
if (r < 0)
return -errno;
route->family = AF_INET;
route->dst_prefixlen = 16;
route->scope = RT_SCOPE_LINK;
route->metrics = IPV4LL_ROUTE_METRIC;
route->protocol = RTPROT_STATIC;
}
if (network->dns || network->ntp) {
r = link_save(link);
if (r < 0)
return r;
}
return 0;
}
int config_parse_netdev(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
_cleanup_free_ char *kind_string = NULL;
char *p;
NetDev *netdev;
NetDevKind kind;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
kind_string = strdup(lvalue);
if (!kind_string)
return log_oom();
/* the keys are CamelCase versions of the kind */
for (p = kind_string; *p; p++)
*p = tolower(*p);
kind = netdev_kind_from_string(kind_string);
if (kind == _NETDEV_KIND_INVALID) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Invalid NetDev kind: %s", lvalue);
return 0;
}
r = netdev_get(network->manager, rvalue, &netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"%s could not be found, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
if (netdev->kind != kind) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
switch (kind) {
case NETDEV_KIND_BRIDGE:
network->bridge = netdev;
break;
case NETDEV_KIND_BOND:
network->bond = netdev;
break;
case NETDEV_KIND_VLAN:
case NETDEV_KIND_MACVLAN:
case NETDEV_KIND_IPVLAN:
case NETDEV_KIND_VXLAN:
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Can not add VLAN '%s' to network: %m",
rvalue);
return 0;
}
break;
default:
assert_not_reached("Can not parse NetDev");
}
netdev_ref(netdev);
return 0;
}
int config_parse_domains(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
char ***domains = data;
char **domain;
int r;
r = config_parse_strv(unit, filename, line, section, section_line,
lvalue, ltype, rvalue, domains, userdata);
if (r < 0)
return r;
strv_uniq(*domains);
network->wildcard_domain = !!strv_find(*domains, "*");
STRV_FOREACH(domain, *domains) {
if (is_localhost(*domain))
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
else if (!hostname_is_valid(*domain)) {
if (!streq(*domain, "*"))
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "domain name is not valid, ignoring assignment: %s", *domain);
} else
continue;
strv_remove(*domains, *domain);
/* We removed one entry, make sure we don't skip the next one */
domain--;
}
return 0;
}
int config_parse_tunnel(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Network *network = userdata;
NetDev *netdev;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = netdev_get(network->manager, rvalue, &netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
return 0;
}
if (netdev->kind != NETDEV_KIND_IPIP &&
netdev->kind != NETDEV_KIND_SIT &&
netdev->kind != NETDEV_KIND_GRE &&
netdev->kind != NETDEV_KIND_GRETAP &&
netdev->kind != NETDEV_KIND_IP6GRE &&
netdev->kind != NETDEV_KIND_IP6GRETAP &&
netdev->kind != NETDEV_KIND_VTI &&
netdev->kind != NETDEV_KIND_VTI6 &&
netdev->kind != NETDEV_KIND_IP6TNL
) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"NetDev is not a tunnel, ignoring assignment: %s", rvalue);
return 0;
}
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
return 0;
}
netdev_ref(netdev);
return 0;
}
int config_parse_ipv4ll(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
AddressFamilyBoolean *link_local = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
/* Note that this is mostly like
* config_parse_address_family_boolean(), except that it
* applies only to IPv4 */
if (parse_boolean(rvalue))
*link_local |= ADDRESS_FAMILY_IPV4;
else
*link_local &= ~ADDRESS_FAMILY_IPV4;
return 0;
}
int config_parse_dhcp(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
AddressFamilyBoolean *dhcp = data, s;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
/* Note that this is mostly like
* config_parse_address_family_boolean(), except that it
* understands some old names for the enum values */
s = address_family_boolean_from_string(rvalue);
if (s < 0) {
/* Previously, we had a slightly different enum here,
* support its values for compatbility. */
if (streq(rvalue, "none"))
s = ADDRESS_FAMILY_NO;
else if (streq(rvalue, "v4"))
s = ADDRESS_FAMILY_IPV4;
else if (streq(rvalue, "v6"))
s = ADDRESS_FAMILY_IPV6;
else if (streq(rvalue, "both"))
s = ADDRESS_FAMILY_YES;
else {
log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
return 0;
}
}
*dhcp = s;
return 0;
}
static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
[DHCP_CLIENT_ID_MAC] = "mac",
[DHCP_CLIENT_ID_DUID] = "duid"
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
[LLMNR_SUPPORT_NO] = "no",
[LLMNR_SUPPORT_YES] = "yes",
[LLMNR_SUPPORT_RESOLVE] = "resolve",
};
DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport);
int config_parse_llmnr(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
LLMNRSupport *llmnr = data;
int k;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(llmnr);
/* Our enum shall be a superset of booleans, hence first try
* to parse as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
*llmnr = LLMNR_SUPPORT_YES;
else if (k == 0)
*llmnr = LLMNR_SUPPORT_NO;
else {
LLMNRSupport s;
s = llmnr_support_from_string(rvalue);
if (s < 0){
log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue);
return 0;
}
*llmnr = s;
}
return 0;
}
int config_parse_ipv6token(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
union in_addr_union buffer;
struct in6_addr *token = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(token);
r = in_addr_from_string(AF_INET6, rvalue, &buffer);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
return 0;
}
r = in_addr_is_null(AF_INET6, &buffer);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
return 0;
}
if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
return 0;
}
*token = buffer.in6;
return 0;
}