diff options
Diffstat (limited to 'src/udev/net/link-config.c')
-rw-r--r-- | src/udev/net/link-config.c | 519 |
1 files changed, 0 insertions, 519 deletions
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c deleted file mode 100644 index c66504102f..0000000000 --- a/src/udev/net/link-config.c +++ /dev/null @@ -1,519 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <netinet/ether.h> - -#include "sd-netlink.h" - -#include "alloc-util.h" -#include "conf-files.h" -#include "conf-parser.h" -#include "ethtool-util.h" -#include "fd-util.h" -#include "libudev-private.h" -#include "link-config.h" -#include "log.h" -#include "missing.h" -#include "netlink-util.h" -#include "network-internal.h" -#include "parse-util.h" -#include "path-util.h" -#include "proc-cmdline.h" -#include "random-util.h" -#include "stat-util.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "util.h" - -struct link_config_ctx { - LIST_HEAD(link_config, links); - - int ethtool_fd; - - bool enable_name_policy; - - sd_netlink *rtnl; - - usec_t link_dirs_ts_usec; -}; - -static const char* const link_dirs[] = { - "/etc/systemd/network", - "/run/systemd/network", - "/usr/lib/systemd/network", -#ifdef HAVE_SPLIT_USR - "/lib/systemd/network", -#endif - NULL}; - -static void link_config_free(link_config *link) { - if (!link) - return; - - free(link->filename); - - free(link->match_mac); - strv_free(link->match_path); - strv_free(link->match_driver); - strv_free(link->match_type); - free(link->match_name); - free(link->match_host); - free(link->match_virt); - free(link->match_kernel); - free(link->match_arch); - - free(link->description); - free(link->mac); - free(link->name_policy); - free(link->name); - free(link->alias); - - free(link); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free); - -static void link_configs_free(link_config_ctx *ctx) { - link_config *link, *link_next; - - if (!ctx) - return; - - LIST_FOREACH_SAFE(links, link, link_next, ctx->links) - link_config_free(link); -} - -void link_config_ctx_free(link_config_ctx *ctx) { - if (!ctx) - return; - - safe_close(ctx->ethtool_fd); - - sd_netlink_unref(ctx->rtnl); - - link_configs_free(ctx); - - free(ctx); - - return; -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free); - -int link_config_ctx_new(link_config_ctx **ret) { - _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL; - - if (!ret) - return -EINVAL; - - ctx = new0(link_config_ctx, 1); - if (!ctx) - return -ENOMEM; - - LIST_HEAD_INIT(ctx->links); - - ctx->ethtool_fd = -1; - - ctx->enable_name_policy = true; - - *ret = ctx; - ctx = NULL; - - return 0; -} - -static int load_link(link_config_ctx *ctx, const char *filename) { - _cleanup_(link_config_freep) link_config *link = NULL; - _cleanup_fclose_ FILE *file = NULL; - int r; - - assert(ctx); - assert(filename); - - file = fopen(filename, "re"); - if (!file) { - if (errno == ENOENT) - return 0; - else - return -errno; - } - - if (null_or_empty_fd(fileno(file))) { - log_debug("Skipping empty file: %s", filename); - return 0; - } - - link = new0(link_config, 1); - if (!link) - return log_oom(); - - link->mac_policy = _MACPOLICY_INVALID; - link->wol = _WOL_INVALID; - link->duplex = _DUP_INVALID; - - r = config_parse(NULL, filename, file, - "Match\0Link\0Ethernet\0", - config_item_perf_lookup, link_config_gperf_lookup, - false, false, true, link); - if (r < 0) - return r; - else - log_debug("Parsed configuration file %s", filename); - - if (link->mtu > UINT_MAX || link->speed > UINT_MAX) - return -ERANGE; - - link->filename = strdup(filename); - - LIST_PREPEND(links, ctx->links, link); - link = NULL; - - return 0; -} - -static bool enable_name_policy(void) { - _cleanup_free_ char *line = NULL; - const char *word, *state; - int r; - size_t l; - - r = proc_cmdline(&line); - if (r < 0) { - log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m"); - return true; - } - - FOREACH_WORD_QUOTED(word, l, line, state) - if (strneq(word, "net.ifnames=0", l)) - return false; - - return true; -} - -int link_config_load(link_config_ctx *ctx) { - int r; - _cleanup_strv_free_ char **files; - char **f; - - link_configs_free(ctx); - - if (!enable_name_policy()) { - ctx->enable_name_policy = false; - log_info("Network interface NamePolicy= disabled on kernel command line, ignoring."); - } - - /* update timestamp */ - paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true); - - r = conf_files_list_strv(&files, ".link", NULL, link_dirs); - if (r < 0) - return log_error_errno(r, "failed to enumerate link files: %m"); - - STRV_FOREACH_BACKWARDS(f, files) { - r = load_link(ctx, *f); - if (r < 0) - return r; - } - - return 0; -} - -bool link_config_should_reload(link_config_ctx *ctx) { - return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false); -} - -int link_config_get(link_config_ctx *ctx, struct udev_device *device, - link_config **ret) { - link_config *link; - - assert(ctx); - assert(device); - assert(ret); - - LIST_FOREACH(links, link, ctx->links) { - const char* attr_value; - - attr_value = udev_device_get_sysattr_value(device, "address"); - - if (net_match_config(link->match_mac, link->match_path, link->match_driver, - link->match_type, link->match_name, link->match_host, - link->match_virt, link->match_kernel, link->match_arch, - attr_value ? ether_aton(attr_value) : NULL, - udev_device_get_property_value(device, "ID_PATH"), - udev_device_get_driver(udev_device_get_parent(device)), - udev_device_get_property_value(device, "ID_NET_DRIVER"), - udev_device_get_devtype(device), - udev_device_get_sysname(device))) { - if (link->match_name) { - unsigned char name_assign_type = NET_NAME_UNKNOWN; - - attr_value = udev_device_get_sysattr_value(device, "name_assign_type"); - if (attr_value) - (void) safe_atou8(attr_value, &name_assign_type); - - if (name_assign_type == NET_NAME_ENUM) { - log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'", - link->filename, udev_device_get_sysname(device)); - *ret = link; - - return 0; - } else if (name_assign_type == NET_NAME_RENAMED) { - log_warning("Config file %s matches device based on renamed interface name '%s', ignoring", - link->filename, udev_device_get_sysname(device)); - - continue; - } - } - - log_debug("Config file %s applies to device %s", - link->filename, udev_device_get_sysname(device)); - - *ret = link; - - return 0; - } - } - - *ret = NULL; - - return -ENOENT; -} - -static bool mac_is_random(struct udev_device *device) { - const char *s; - unsigned type; - int r; - - /* if we can't get the assign type, assume it is not random */ - s = udev_device_get_sysattr_value(device, "addr_assign_type"); - if (!s) - return false; - - r = safe_atou(s, &type); - if (r < 0) - return false; - - return type == NET_ADDR_RANDOM; -} - -static bool should_rename(struct udev_device *device, bool respect_predictable) { - const char *s; - unsigned type; - int r; - - /* if we can't get the assgin type, assume we should rename */ - s = udev_device_get_sysattr_value(device, "name_assign_type"); - if (!s) - return true; - - r = safe_atou(s, &type); - if (r < 0) - return true; - - 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 { - uint64_t result; - - 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 %zu 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) { - log_warning_errno(r, "Could not generate persistent MAC address for %s: %m", old_name); - 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) { - log_warning_errno(r, "Could not generate random MAC address for %s: %m", old_name); - break; - } else if (r < 0) - return r; - mac = &generated_mac; - } - break; - case MACPOLICY_NONE: - 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 = NULL; - 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", - [MACPOLICY_NONE] = "none" -}; - -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"); |