link-config.c revision 187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer systemd is free software; you can redistribute it and/or modify it
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer under the terms of the GNU Lesser General Public License as published by
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer the Free Software Foundation; either version 2.1 of the License, or
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt (at your option) any later version.
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt systemd is distributed in the hope that it will be useful, but
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt WITHOUT ANY WARRANTY; without even the implied warranty of
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1c36b4a73b876258fbe01fbe9bc9b750b7dcc9ceEvgeny Vereshchagin Lesser General Public License for more details.
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier You should have received a copy of the GNU Lesser General Public License
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny ChevalierDEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
61fea35e14d84144e6e2122f5cd247f9c7e6245eEvgeny Vereshchagin#define _cleanup_link_config_ctx_free_ _cleanup_(link_config_ctx_freep)
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalierint link_config_ctx_new(link_config_ctx **ret) {
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier _cleanup_link_config_ctx_free_ link_config_ctx *ctx = NULL;
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier ctx->link_dirs = strv_new("/etc/systemd/network",
c6a77179a4097df355f0f04b8f3260c76b5e515cRonny Chevalier log_error("failed to build link config directory array");
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
dbf43a42b8bb66d53c7cbab05f104c28097f811eDaniel Mack log_error("failed to canonicalize link config directories\n");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic int link_config_ctx_connect(link_config_ctx *ctx) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic void link_configs_free(link_config_ctx *ctx) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
a2fbff31c9c319da51528f85ae97d019f1e61a86Evgeny Vereshchaginvoid link_config_ctx_free(link_config_ctx *ctx) {
cb2f9d3f296bc80b55f09880d61dfdf47fc98212Evgeny Vereshchaginstatic int load_link(link_config_ctx *ctx, const char *filename) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
739d81ddd005fae2bb82edce5b8a6173c7c48b34Zbigniew Jędrzejewski-Szmek (void*) link_config_gperf_lookup, false, false, link);
1b1eae69ce52ef6c89a1200e8d3758549b291991Daniel Mack log_warning("Could not parse config file %s: %s", filename, strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Parsed configuration file %s", filename);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic bool enable_name_policy(void) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return false;
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin /* update timestamp */
c7eda0133b6bf13a182337cbe8a61bf2faf9b32eEvgeny Vereshchagin paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, true);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_error("failed to enumerate link files: %s", strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierbool link_config_should_reload(link_config_ctx *ctx) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, false);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierint link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier if (net_match_config(link->match_mac, link->match_path,
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier udev_device_get_sysattr_value(device, "address"),
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier udev_device_get_property_value(device, "ID_PATH"),
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_debug("Config file %s applies to device %s",
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic bool mac_is_random(struct udev_device *device) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier const char *s;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier s = udev_device_get_sysattr_value(device, "addr_assign_type");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return false; /* if we don't know, assume it is not random */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier return false;
4be4833ece2856e0cacc09f8f8b2c02b320751faMartin Pitt /* check for NET_ADDR_RANDOM */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierstatic bool mac_is_permanent(struct udev_device *device) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier const char *s;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier s = udev_device_get_sysattr_value(device, "addr_assign_type");
cffae62bcb6912fbaf1b7b282d9d170c9d308897Martin Pitt return true; /* if we don't know, assume it is permanent */
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt /* check for NET_ADDR_PERM */
3486cb6cfa3d32a95c0daf02c7510fdf372507bfMartin Pitt return type == 0;
e63b61be5350dbe92ea12e1eeb96dde251ed9292Evgeny Vereshchaginstatic int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier unsigned int seed;
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* fetch some persistent data unique (on this machine) to this device */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
417491f122b346a31cf8dc406c4f9195a5900cecEvgeny Vereshchagin name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* fetch some persistent data unique to this machine */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* combine the data */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier seed_str = strappenda(name, sd_id128_to_string(machine, machineid_buf));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* hash to get seed */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier for (i = 0; i < ETH_ALEN; i++) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier /* see eth_random_addr in the kernel */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalierint link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device, const char **name) {
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = ethtool_set_speed(ctx->ethtool_fd, old_name, config->speed, config->duplex);
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier log_warning("Could not set speed or duplex of %s to %u Mbytes (%s): %s",
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier old_name, config->speed, duplex_to_string(config->duplex), strerror(-r));
889a90422dd47284dffa32b9234a6e58991b000cRonny Chevalier r = ethtool_set_wol(ctx->ethtool_fd, old_name, config->wol);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_warning("Could not set WakeOnLan of %s to %s: %s",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer old_name, wol_to_string(config->wol), strerror(-r));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (ctx->enable_name_policy && config->name_policy) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *name = new_name; /* a name was set by a policy */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *name = config->name; /* a name was set manually in the config */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = rtnl_set_link_properties(ctx->rtnl, ifindex, config->alias, mac, config->mtu);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_warning("Could not set Alias, MACAddress or MTU on %s: %s", old_name, strerror(-r));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const char* const mac_policy_table[] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy, "Failed to parse MAC address policy");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const char* const name_policy_table[] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy, _NAMEPOLICY_INVALID, "Failed to parse interface name policy");