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