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