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