link-config.c revision 97f2d76d4f4dfab8b0629c09926a05a1e5621125
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering This file is part of systemd.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is free software; you can redistribute it and/or modify it
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering under the terms of the GNU Lesser General Public License as published by
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (at your option) any later version.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is distributed in the hope that it will be useful, but
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Lesser General Public License for more details.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering You should have received a copy of the GNU Lesser General Public License
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint link_config_ctx_new(link_config_ctx **ret) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering ctx->link_dirs = strv_new("/etc/systemd/network",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_error("failed to build link config directory array");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_error("failed to canonicalize link config directories\n");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic void link_configs_free(link_config_ctx *ctx) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid link_config_ctx_free(link_config_ctx *ctx) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int load_link(link_config_ctx *ctx, const char *filename) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (void*) link_config_gperf_lookup, false, false, link);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Colud not parse config file %s: %s", filename, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_info("Parsed configuration file %s", filename);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint link_config_load(link_config_ctx *ctx) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* update timestamp */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_error("failed to enumerate link files: %s", strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringbool link_config_should_reload(link_config_ctx *ctx) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return paths_check_timestamp(ctx->link_dirs, &ctx->link_dirs_ts_usec, false);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic bool match_config(link_config *match, struct udev_device *device) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering property = udev_device_get_sysattr_value(device, "address");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!property || memcmp(match->match_mac, ether_aton(property), ETH_ALEN)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("Device MAC address (%s) did not match MACAddress=%s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering property = udev_device_get_property_value(device, "ID_PATH");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!streq_ptr(match->match_path, property)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("Device's persistent path (%s) did not match Path=%s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering property = udev_device_get_driver(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!streq_ptr(match->match_driver, property)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("Device driver (%s) did not match Driver=%s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering property = udev_device_get_devtype(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!streq_ptr(match->match_type, property)) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug("Device type (%s) did not match Type=%s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_info("Config file %s does not apply to device %s", link->filename, udev_device_get_sysname(device));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_info("Config file %s applies to device %s", link->filename, udev_device_get_sysname(device));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int rtnl_set_properties(sd_rtnl *rtnl, int ifindex, const char *name, const struct ether_addr *mac, unsigned int mtu) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *message;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_rtnl_message_link_new(RTM_NEWLINK, ifindex, 0, 0, &message);
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek r = sd_rtnl_message_append(message, IFLA_IFNAME, name);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_rtnl_message_append(message, IFLA_ADDRESS, mac);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_rtnl_message_append(message, IFLA_MTU, &mtu);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_rtnl_send_with_reply_and_block(rtnl, message, 5 * USEC_PER_SEC, NULL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic bool enable_name_policy(void) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = read_one_line_file("/proc/cmdline", &line);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return true; /* something is very wrong, let's not make it worse */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic bool mac_is_random(struct udev_device *device) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering const char *s;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering s = udev_device_get_sysattr_value(device, "addr_assign_type");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* check for NET_ADDR_RANDOM */
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmekstatic bool mac_is_permanent(struct udev_device *device) {
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek s = udev_device_get_sysattr_value(device, "addr_assign_type");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* check for NET_ADDR_PERM */
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poetteringstatic int get_mac(struct udev_device *device, bool want_random, struct ether_addr *mac) {
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek /* fetch some persistent data unique (on this machine) to this device */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* fetch some persistent data unique to this machine */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* combine the data */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering seed_str = strappenda(name, sd_id128_to_string(machine, machineid_buf));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* hash to get seed */
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek seed = string_hash_func(seed_str);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering for(i = 0; i < ETH_ALEN; i++) {
943aad8ca57a6b5c49c4ea60f9e8c13bf9b20e6cZbigniew Jędrzejewski-Szmek mac->ether_addr_octet[i] = random();
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* see eth_random_addr in the kernel */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = udev_device_set_sysattr_value(device, "ifalias",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Could not set description of %s to '%s': %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering name, config->description, strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = ethtool_set_speed(ctx->ethtool_fd, name, config->speed, config->duplex);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Could not set speed or duplex of %s to %u Mbytes (%s): %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering name, config->speed, duplex_to_string(config->duplex), strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = ethtool_set_wol(ctx->ethtool_fd, name, config->wol);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Could not set WakeOnLan of %s to %s: %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering name, wol_to_string(config->wol), strerror(-r));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering ifindex = udev_device_get_ifindex(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (config->name_policy && enable_name_policy()) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering for (policy = config->name_policy; !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = get_mac(device, false, &generated_mac);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = get_mac(device, true, &generated_mac);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = rtnl_set_properties(ctx->rtnl, ifindex, new_name, mac, config->mtu);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_warning("Could not set Name, MACAddress or MTU on %s: %s", name, strerror(-r));