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