link-config.c revision 3f85ef0f05ffc51e19f86fb83a1c51e8e3cd6817
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic const char* const link_dirs[] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define _cleanup_link_config_ctx_free_ _cleanup_(link_config_ctx_freep)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint link_config_ctx_new(link_config_ctx **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_link_config_ctx_free_ link_config_ctx *ctx = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void link_configs_free(link_config_ctx *ctx) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid link_config_ctx_free(link_config_ctx *ctx) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int load_link(link_config_ctx *ctx, const char *filename) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Skipping empty file: %s", filename);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Match\0Link\0Ethernet\0",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering config_item_perf_lookup, link_config_gperf_lookup,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering false, false, true, link);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Parsed configuration file %s", filename);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool enable_name_policy(void) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning("Failed to read /proc/cmdline, ignoring: %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering FOREACH_WORD_QUOTED(word, l, line, state)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint link_config_load(link_config_ctx *ctx) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* update timestamp */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("failed to enumerate link files: %s", strerror(-r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringbool link_config_should_reload(link_config_ctx *ctx) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint link_config_get(link_config_ctx *ctx, struct udev_device *device,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char* attr_value = udev_device_get_sysattr_value(device, "address");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (net_match_config(link->match_mac, link->match_path, link->match_driver,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering link->match_type, NULL, link->match_host,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering link->match_virt, link->match_kernel, link->match_arch,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering attr_value ? ether_aton(attr_value) : NULL,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering udev_device_get_property_value(device, "ID_PATH"),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering udev_device_get_driver(udev_device_get_parent(device)),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering udev_device_get_property_value(device, "ID_NET_DRIVER"),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Config file %s applies to device %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool mac_is_random(struct udev_device *device) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* if we can't get the assign type, assume it is not random */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = udev_device_get_sysattr_value(device, "addr_assign_type");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool should_rename(struct udev_device *device, bool respect_predictable) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* if we can't get the assgin type, assume we should rename */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = udev_device_get_sysattr_value(device, "name_assign_type");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* these were already named by userspace, do not touch again */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* the kernel claims to have given a predictable name */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* fall through */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* the name is known to be bad, or of an unknown type */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int get_mac(struct udev_device *device, bool want_random,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering random_bytes(mac->ether_addr_octet, ETH_ALEN);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = net_get_unique_predictable_data(device, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering memcpy(mac->ether_addr_octet, result, ETH_ALEN);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* see eth_random_addr in the kernel */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint link_config_apply(link_config_ctx *ctx, link_config *config,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct udev_device *device, const char **name) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering old_name = udev_device_get_sysname(device);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering duplex_to_string(config->duplex), strerror(-r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning("Could not set WakeOnLan of %s to %s: %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering old_name, wol_to_string(config->wol), strerror(-r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ifindex = udev_device_get_ifindex(device);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (ctx->enable_name_policy && config->name_policy) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (should_rename(device, respect_predictable)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* if not set by policy, fall back manually set name */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = get_mac(device, false, &generated_mac);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = get_mac(device, true, &generated_mac);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning("Could not set Alias, MACAddress or MTU on %s: %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic const char* const mac_policy_table[_MACPOLICY_MAX] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Failed to parse MAC address policy");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic const char* const name_policy_table[_NAMEPOLICY_MAX] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Failed to parse interface name policy");