link-config.c revision 9a4b012e43f23516373bf398dd9a458439d19939
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers/***
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers This file is part of systemd.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers systemd is free software; you can redistribute it and/or modify it
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers under the terms of the GNU Lesser General Public License as published by
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers the Free Software Foundation; either version 2.1 of the License, or
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers (at your option) any later version.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers systemd is distributed in the hope that it will be useful, but
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers Lesser General Public License for more details.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers You should have received a copy of the GNU Lesser General Public License
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers***/
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include <netinet/ether.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include <linux/netdevice.h>
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "sd-id128.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "missing.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "link-config.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "ethtool-util.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "libudev-private.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "sd-rtnl.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "util.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "log.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "strv.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "path-util.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "conf-parser.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "conf-files.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "fileio.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "hashmap.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "rtnl-util.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "network-internal.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#include "siphash24.h"
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstruct link_config_ctx {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers LIST_HEAD(link_config, links);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int ethtool_fd;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers bool enable_name_policy;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers sd_rtnl *rtnl;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers usec_t link_dirs_ts_usec;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers};
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic const char* const link_dirs[] = {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers "/etc/systemd/network",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers "/run/systemd/network",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers "/usr/lib/systemd/network",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#ifdef HAVE_SPLIT_USR
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers "/lib/systemd/network",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers#endif
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers NULL};
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic void link_config_free(link_config *link) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!link)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->filename);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_mac);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_path);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_driver);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_type);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_name);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_host);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_virt);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_kernel);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->match_arch);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->description);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->mac);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->name_policy);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->name);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link->alias);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(link);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay SieversDEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic void link_configs_free(link_config_ctx *ctx) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link_config *link, *link_next;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!ctx)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link_config_free(link);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversvoid link_config_ctx_free(link_config_ctx *ctx) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!ctx)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers safe_close(ctx->ethtool_fd);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers sd_rtnl_unref(ctx->rtnl);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link_configs_free(ctx);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers free(ctx);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay SieversDEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversint link_config_ctx_new(link_config_ctx **ret) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!ret)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -EINVAL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers ctx = new0(link_config_ctx, 1);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!ctx)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -ENOMEM;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers LIST_HEAD_INIT(ctx->links);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers ctx->ethtool_fd = -1;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers ctx->enable_name_policy = true;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers *ret = ctx;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers ctx = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic int load_link(link_config_ctx *ctx, const char *filename) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers _cleanup_(link_config_freep) link_config *link = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers _cleanup_fclose_ FILE *file = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(ctx);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers assert(filename);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers file = fopen(filename, "re");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!file) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (errno == ENOENT)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers else
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -errno;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (null_or_empty_fd(fileno(file))) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_debug("Skipping empty file: %s", filename);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link = new0(link_config, 1);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!link)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return log_oom();
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->mac_policy = _MACPOLICY_INVALID;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->wol = _WOL_INVALID;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->duplex = _DUP_INVALID;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = config_parse(NULL, filename, file,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers "Match\0Link\0Ethernet\0",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers config_item_perf_lookup, link_config_gperf_lookup,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers false, false, true, link);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers else
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_debug("Parsed configuration file %s", filename);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->filename = strdup(filename);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers LIST_PREPEND(links, ctx->links, link);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic bool enable_name_policy(void) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers _cleanup_free_ char *line = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers const char *word, *state;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers size_t l;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = proc_cmdline(&line);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return true;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers FOREACH_WORD_QUOTED(word, l, line, state)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (strneq(word, "net.ifnames=0", l))
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return false;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return true;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversint link_config_load(link_config_ctx *ctx) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers _cleanup_strv_free_ char **files;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers char **f;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link_configs_free(ctx);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!enable_name_policy()) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers ctx->enable_name_policy = false;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers /* update timestamp */
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return log_error_errno(r, "failed to enumerate link files: %m");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers STRV_FOREACH_BACKWARDS(f, files) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = load_link(ctx, *f);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversbool link_config_should_reload(link_config_ctx *ctx) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversint link_config_get(link_config_ctx *ctx, struct udev_device *device,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link_config **ret) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link_config *link;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers LIST_FOREACH(links, link, ctx->links) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers const char* attr_value;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers attr_value = udev_device_get_sysattr_value(device, "address");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (net_match_config(link->match_mac, link->match_path, link->match_driver,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->match_type, link->match_name, link->match_host,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->match_virt, link->match_kernel, link->match_arch,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers attr_value ? ether_aton(attr_value) : NULL,
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers udev_device_get_property_value(device, "ID_PATH"),
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers udev_device_get_driver(udev_device_get_parent(device)),
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers udev_device_get_property_value(device, "ID_NET_DRIVER"),
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers udev_device_get_devtype(device),
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers udev_device_get_sysname(device))) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (link->match_name) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers unsigned char name_assign_type = NET_NAME_UNKNOWN;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers attr_value = udev_device_get_sysattr_value(device, "name_assign_type");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (attr_value)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers (void)safe_atou8(attr_value, &name_assign_type);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (name_assign_type == NET_NAME_ENUM) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->filename, udev_device_get_sysname(device));
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers *ret = link;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers } else if (name_assign_type == NET_NAME_RENAMED) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->filename, udev_device_get_sysname(device));
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers continue;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers log_debug("Config file %s applies to device %s",
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers link->filename, udev_device_get_sysname(device));
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers *ret = link;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return 0;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers }
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers *ret = NULL;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return -ENOENT;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic bool mac_is_random(struct udev_device *device) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers const char *s;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers unsigned type;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers /* if we can't get the assign type, assume it is not random */
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s = udev_device_get_sysattr_value(device, "addr_assign_type");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!s)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return false;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = safe_atou(s, &type);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return false;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return type == NET_ADDR_RANDOM;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers}
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sieversstatic bool should_rename(struct udev_device *device, bool respect_predictable) {
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers const char *s;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers unsigned type;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers int r;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers /* if we can't get the assgin type, assume we should rename */
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers s = udev_device_get_sysattr_value(device, "name_assign_type");
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (!s)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return true;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers r = safe_atou(s, &type);
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers if (r < 0)
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers return true;
2f8d336478536af789d654599f9523d02e0ca693Kay Sievers
switch (type) {
case NET_NAME_USER:
case NET_NAME_RENAMED:
/* these were already named by userspace, do not touch again */
return false;
case NET_NAME_PREDICTABLE:
/* the kernel claims to have given a predictable name */
if (respect_predictable)
return false;
/* fall through */
case NET_NAME_ENUM:
default:
/* the name is known to be bad, or of an unknown type */
return true;
}
}
static int get_mac(struct udev_device *device, bool want_random,
struct ether_addr *mac) {
int r;
if (want_random)
random_bytes(mac->ether_addr_octet, ETH_ALEN);
else {
uint8_t result[8];
r = net_get_unique_predictable_data(device, result);
if (r < 0)
return r;
assert_cc(ETH_ALEN <= sizeof(result));
memcpy(mac->ether_addr_octet, result, ETH_ALEN);
}
/* see eth_random_addr in the kernel */
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
return 0;
}
int link_config_apply(link_config_ctx *ctx, link_config *config,
struct udev_device *device, const char **name) {
const char *old_name;
const char *new_name = NULL;
struct ether_addr generated_mac;
struct ether_addr *mac = NULL;
bool respect_predictable = false;
int r, ifindex;
assert(ctx);
assert(config);
assert(device);
assert(name);
old_name = udev_device_get_sysname(device);
if (!old_name)
return -EINVAL;
r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
config->duplex);
if (r < 0)
log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
old_name, config->speed / 1024,
duplex_to_string(config->duplex));
r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
if (r < 0)
log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
old_name, wol_to_string(config->wol));
ifindex = udev_device_get_ifindex(device);
if (ifindex <= 0) {
log_warning("Could not find ifindex");
return -ENODEV;
}
if (ctx->enable_name_policy && config->name_policy) {
NamePolicy *policy;
for (policy = config->name_policy;
!new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
switch (*policy) {
case NAMEPOLICY_KERNEL:
respect_predictable = true;
break;
case NAMEPOLICY_DATABASE:
new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
break;
case NAMEPOLICY_ONBOARD:
new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
break;
case NAMEPOLICY_SLOT:
new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
break;
case NAMEPOLICY_PATH:
new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
break;
case NAMEPOLICY_MAC:
new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
break;
default:
break;
}
}
}
if (should_rename(device, respect_predictable)) {
/* if not set by policy, fall back manually set name */
if (!new_name)
new_name = config->name;
} else
new_name = NULL;
switch (config->mac_policy) {
case MACPOLICY_PERSISTENT:
if (mac_is_random(device)) {
r = get_mac(device, false, &generated_mac);
if (r == -ENOENT)
break;
else if (r < 0)
return r;
mac = &generated_mac;
}
break;
case MACPOLICY_RANDOM:
if (!mac_is_random(device)) {
r = get_mac(device, true, &generated_mac);
if (r == -ENOENT)
break;
else if (r < 0)
return r;
mac = &generated_mac;
}
break;
default:
mac = config->mac;
}
r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
config->mtu);
if (r < 0)
return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name);
*name = new_name;
return 0;
}
int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
const char *name;
char *driver;
int r;
name = udev_device_get_sysname(device);
if (!name)
return -EINVAL;
r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
if (r < 0)
return r;
*ret = driver;
return 0;
}
static const char* const mac_policy_table[_MACPOLICY_MAX] = {
[MACPOLICY_PERSISTENT] = "persistent",
[MACPOLICY_RANDOM] = "random"
};
DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
"Failed to parse MAC address policy");
static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
[NAMEPOLICY_KERNEL] = "kernel",
[NAMEPOLICY_DATABASE] = "database",
[NAMEPOLICY_ONBOARD] = "onboard",
[NAMEPOLICY_SLOT] = "slot",
[NAMEPOLICY_PATH] = "path",
[NAMEPOLICY_MAC] = "mac"
};
DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
_NAMEPOLICY_INVALID,
"Failed to parse interface name policy");