From 418c02c3f1f55db0564ba989dd71d31da98387f1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Nov 2021 09:06:05 +0900 Subject: [PATCH 1/3] udev/net: rename variables --- src/udev/net/link-config.c | 150 ++++++++++++++++++------------------- src/udev/net/link-config.h | 2 +- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index fb108b7551..ab9ffdc216 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -36,44 +36,44 @@ #include "utf8.h" struct LinkConfigContext { - LIST_HEAD(LinkConfig, links); + LIST_HEAD(LinkConfig, configs); int ethtool_fd; bool enable_name_policy; usec_t network_dirs_ts_usec; }; -static LinkConfig* link_config_free(LinkConfig *link) { - if (!link) +static LinkConfig* link_config_free(LinkConfig *config) { + if (!config) return NULL; - free(link->filename); + free(config->filename); - net_match_clear(&link->match); - condition_free_list(link->conditions); + net_match_clear(&config->match); + condition_free_list(config->conditions); - free(link->description); - free(link->mac); - free(link->name_policy); - free(link->name); - strv_free(link->alternative_names); - free(link->alternative_names_policy); - free(link->alias); - free(link->wol_password_file); - erase_and_free(link->wol_password); + free(config->description); + free(config->mac); + free(config->name_policy); + free(config->name); + strv_free(config->alternative_names); + free(config->alternative_names_policy); + free(config->alias); + free(config->wol_password_file); + erase_and_free(config->wol_password); - return mfree(link); + return mfree(config); } DEFINE_TRIVIAL_CLEANUP_FUNC(LinkConfig*, link_config_free); static void link_configs_free(LinkConfigContext *ctx) { - LinkConfig *link, *link_next; + LinkConfig *config, *config_next; if (!ctx) return; - LIST_FOREACH_SAFE(links, link, link_next, ctx->links) - link_config_free(link); + LIST_FOREACH_SAFE(configs, config, config_next, ctx->configs) + link_config_free(config); } LinkConfigContext *link_config_ctx_free(LinkConfigContext *ctx) { @@ -105,11 +105,11 @@ int link_config_ctx_new(LinkConfigContext **ret) { return 0; } -static int link_parse_wol_password(LinkConfig *link, const char *str) { +static int link_parse_wol_password(LinkConfig *config, const char *str) { _cleanup_(erase_and_freep) uint8_t *p = NULL; int r; - assert(link); + assert(config); assert(str); assert_cc(sizeof(struct ether_addr) == SOPASS_MAX); @@ -123,48 +123,48 @@ static int link_parse_wol_password(LinkConfig *link, const char *str) { if (r < 0) return r; - erase_and_free(link->wol_password); - link->wol_password = TAKE_PTR(p); + erase_and_free(config->wol_password); + config->wol_password = TAKE_PTR(p); return 0; } -static int link_read_wol_password_from_file(LinkConfig *link) { +static int link_read_wol_password_from_file(LinkConfig *config) { _cleanup_(erase_and_freep) char *password = NULL; int r; - assert(link); + assert(config); - if (!link->wol_password_file) + if (!config->wol_password_file) return 0; r = read_full_file_full( - AT_FDCWD, link->wol_password_file, UINT64_MAX, SIZE_MAX, + AT_FDCWD, config->wol_password_file, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_SECURE | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET, NULL, &password, NULL); if (r < 0) return r; - return link_parse_wol_password(link, password); + return link_parse_wol_password(config, password); } -static int link_read_wol_password_from_cred(LinkConfig *link) { +static int link_read_wol_password_from_cred(LinkConfig *config) { _cleanup_free_ char *base = NULL, *cred_name = NULL; _cleanup_(erase_and_freep) char *password = NULL; int r; - assert(link); - assert(link->filename); + assert(config); + assert(config->filename); - if (link->wol == UINT32_MAX) + if (config->wol == UINT32_MAX) return 0; /* WakeOnLan= is not specified. */ - if (!FLAGS_SET(link->wol, WAKE_MAGICSECURE)) + if (!FLAGS_SET(config->wol, WAKE_MAGICSECURE)) return 0; /* secureon is not specified in WakeOnLan=. */ - if (link->wol_password) + if (config->wol_password) return 0; /* WakeOnLanPassword= is specified. */ - if (link->wol_password_file) + if (config->wol_password_file) return 0; /* a file name is specified in WakeOnLanPassword=, but failed to read it. */ - r = path_extract_filename(link->filename, &base); + r = path_extract_filename(config->filename, &base); if (r < 0) return r; @@ -178,37 +178,37 @@ static int link_read_wol_password_from_cred(LinkConfig *link) { if (r < 0) return r; - return link_parse_wol_password(link, password); + return link_parse_wol_password(config, password); } -static int link_adjust_wol_options(LinkConfig *link) { +static int link_adjust_wol_options(LinkConfig *config) { int r; - assert(link); + assert(config); - r = link_read_wol_password_from_file(link); + r = link_read_wol_password_from_file(config); if (r == -ENOMEM) return log_oom(); if (r < 0) - log_warning_errno(r, "Failed to read WakeOnLan password from %s, ignoring: %m", link->wol_password_file); + log_warning_errno(r, "Failed to read WakeOnLan password from %s, ignoring: %m", config->wol_password_file); - r = link_read_wol_password_from_cred(link); + r = link_read_wol_password_from_cred(config); if (r == -ENOMEM) return log_oom(); if (r < 0) log_warning_errno(r, "Failed to read WakeOnLan password from credential, ignoring: %m"); - if (link->wol != UINT32_MAX && link->wol_password) + if (config->wol != UINT32_MAX && config->wol_password) /* Enable WAKE_MAGICSECURE flag when WakeOnLanPassword=. Note that when * WakeOnLanPassword= is set without WakeOnLan=, then ethtool_set_wol() enables * WAKE_MAGICSECURE flag and other flags are not changed. */ - link->wol |= WAKE_MAGICSECURE; + config->wol |= WAKE_MAGICSECURE; return 0; } int link_load_one(LinkConfigContext *ctx, const char *filename) { - _cleanup_(link_config_freep) LinkConfig *link = NULL; + _cleanup_(link_config_freep) LinkConfig *config = NULL; _cleanup_free_ char *name = NULL; const char *dropin_dirname; size_t i; @@ -231,11 +231,11 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { if (!name) return -ENOMEM; - link = new(LinkConfig, 1); - if (!link) + config = new(LinkConfig, 1); + if (!config) return -ENOMEM; - *link = (LinkConfig) { + *config = (LinkConfig) { .filename = TAKE_PTR(name), .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID, .wol = UINT32_MAX, /* UINT32_MAX means do not change WOL setting. */ @@ -250,8 +250,8 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { .coalesce.use_adaptive_tx_coalesce = -1, }; - for (i = 0; i < ELEMENTSOF(link->features); i++) - link->features[i] = -1; + for (i = 0; i < ELEMENTSOF(config->features); i++) + config->features[i] = -1; dropin_dirname = strjoina(basename(filename), ".d"); r = config_parse_many( @@ -260,36 +260,36 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { dropin_dirname, "Match\0Link\0", config_item_perf_lookup, link_config_gperf_lookup, - CONFIG_PARSE_WARN, link, NULL); + CONFIG_PARSE_WARN, config, NULL); if (r < 0) return r; - if (net_match_is_empty(&link->match) && !link->conditions) { + if (net_match_is_empty(&config->match) && !config->conditions) { log_warning("%s: No valid settings found in the [Match] section, ignoring file. " "To match all interfaces, add OriginalName=* in the [Match] section.", filename); return 0; } - if (!condition_test_list(link->conditions, environ, NULL, NULL, NULL)) { + if (!condition_test_list(config->conditions, environ, NULL, NULL, NULL)) { log_debug("%s: Conditions do not match the system environment, skipping.", filename); return 0; } - if (IN_SET(link->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM) && link->mac) { + if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM) && config->mac) { log_warning("%s: MACAddress= in [Link] section will be ignored when MACAddressPolicy= " "is set to \"persistent\" or \"random\".", filename); - link->mac = mfree(link->mac); + config->mac = mfree(config->mac); } - r = link_adjust_wol_options(link); + r = link_adjust_wol_options(config); if (r < 0) return r; log_debug("Parsed configuration file %s", filename); - LIST_PREPEND(links, ctx->links, TAKE_PTR(link)); + LIST_PREPEND(configs, ctx->configs, TAKE_PTR(config)); return 0; } @@ -299,7 +299,7 @@ static bool enable_name_policy(void) { return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b; } -static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) { +static int device_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) { const char *s; int r; @@ -351,7 +351,7 @@ int link_config_get(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device unsigned name_assign_type = NET_NAME_UNKNOWN; struct hw_addr_data hw_addr, permanent_hw_addr; unsigned short iftype; - LinkConfig *link; + LinkConfig *config; const char *name; unsigned flags; int ifindex, r; @@ -383,23 +383,23 @@ int link_config_get(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device log_device_debug_errno(device, r, "Failed to get permanent hardware address, ignoring: %m"); } - (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type); + (void) device_unsigned_attribute(device, "name_assign_type", &name_assign_type); - LIST_FOREACH(links, link, ctx->links) { - r = net_match_config(&link->match, device, &hw_addr, &permanent_hw_addr, + LIST_FOREACH(configs, config, ctx->configs) { + r = net_match_config(&config->match, device, &hw_addr, &permanent_hw_addr, NULL, iftype, NULL, NULL, 0, NULL, NULL); if (r < 0) return r; if (r == 0) continue; - if (link->match.ifname && !strv_contains(link->match.ifname, "*") && name_assign_type == NET_NAME_ENUM) + if (config->match.ifname && !strv_contains(config->match.ifname, "*") && name_assign_type == NET_NAME_ENUM) log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.", - link->filename); + config->filename); else - log_device_debug(device, "Config file %s is applied", link->filename); + log_device_debug(device, "Config file %s is applied", config->filename); - *ret = link; + *ret = config; return 0; } @@ -481,7 +481,7 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT)); - r = link_unsigned_attribute(device, "addr_assign_type", &addr_type); + r = device_unsigned_attribute(device, "addr_assign_type", &addr_type); if (r < 0) return r; switch (addr_type) { @@ -574,7 +574,7 @@ static int link_config_generate_new_name(const LinkConfigContext *ctx, const Lin assert(device); assert(ret_name); - (void) link_unsigned_attribute(device, "name_assign_type", &name_type); + (void) device_unsigned_attribute(device, "name_assign_type", &name_type); if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED) && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) { @@ -907,7 +907,7 @@ int config_parse_wol_password( void *data, void *userdata) { - LinkConfig *link = userdata; + LinkConfig *config = userdata; int r; assert(filename); @@ -916,19 +916,19 @@ int config_parse_wol_password( assert(userdata); if (isempty(rvalue)) { - link->wol_password = erase_and_free(link->wol_password); - link->wol_password_file = mfree(link->wol_password_file); + config->wol_password = erase_and_free(config->wol_password); + config->wol_password_file = mfree(config->wol_password_file); return 0; } if (path_is_absolute(rvalue) && path_is_safe(rvalue)) { - link->wol_password = erase_and_free(link->wol_password); - return free_and_strdup_warn(&link->wol_password_file, rvalue); + config->wol_password = erase_and_free(config->wol_password); + return free_and_strdup_warn(&config->wol_password_file, rvalue); } warn_file_is_world_accessible(filename, NULL, unit, line); - r = link_parse_wol_password(link, rvalue); + r = link_parse_wol_password(config, rvalue); if (r == -ENOMEM) return log_oom(); if (r < 0) { @@ -937,7 +937,7 @@ int config_parse_wol_password( return 0; } - link->wol_password_file = mfree(link->wol_password_file); + config->wol_password_file = mfree(config->wol_password_file); return 0; } diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index cf5eccf093..47619d923f 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -69,7 +69,7 @@ struct LinkConfig { int autoneg_flow_control; netdev_coalesce_param coalesce; - LIST_FIELDS(LinkConfig, links); + LIST_FIELDS(LinkConfig, configs); }; int link_config_ctx_new(LinkConfigContext **ret); From 613701a4e88b3fbf9d0f7901fea62ed0016d8862 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Nov 2021 10:13:56 +0900 Subject: [PATCH 2/3] udev/net: introduce "struct Link" to store link attributes --- src/shared/net-condition.c | 13 +- src/udev/net/link-config.c | 368 +++++++++++++------------ src/udev/net/link-config.h | 27 +- src/udev/udev-builtin-net_setup_link.c | 31 +-- 4 files changed, 230 insertions(+), 209 deletions(-) diff --git a/src/shared/net-condition.c b/src/shared/net-condition.c index fbd7bd0784..006676d973 100644 --- a/src/shared/net-condition.c +++ b/src/shared/net-condition.c @@ -134,21 +134,14 @@ int net_match_config( _cleanup_free_ char *iftype_str = NULL; const char *path = NULL; - int r; assert(match); - r = net_get_type_string(device, iftype, &iftype_str); - if (r == -ENOMEM) - return r; + if (net_get_type_string(device, iftype, &iftype_str) == -ENOMEM) + return -ENOMEM; - if (device) { + if (device) (void) sd_device_get_property_value(device, "ID_PATH", &path); - if (!driver) - (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver); - if (!ifname) - (void) sd_device_get_sysname(device, &ifname); - } if (match->hw_addr && (!hw_addr || !set_contains(match->hw_addr, hw_addr))) return false; diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index ab9ffdc216..940b5cdfea 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -18,7 +18,7 @@ #include "fd-util.h" #include "fileio.h" #include "link-config.h" -#include "log.h" +#include "log-link.h" #include "memory-util.h" #include "net-condition.h" #include "netif-naming-scheme.h" @@ -347,99 +347,146 @@ bool link_config_should_reload(LinkConfigContext *ctx) { return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false); } -int link_config_get(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, LinkConfig **ret) { - unsigned name_assign_type = NET_NAME_UNKNOWN; - struct hw_addr_data hw_addr, permanent_hw_addr; - unsigned short iftype; - LinkConfig *config; - const char *name; - unsigned flags; - int ifindex, r; +Link *link_free(Link *link) { + if (!link) + return NULL; + + sd_device_unref(link->device); + free(link->driver); + return mfree(link); +} + +int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link **ret) { + _cleanup_(link_freep) Link *link = NULL; + int r; assert(ctx); assert(rtnl); assert(device); assert(ret); - r = sd_device_get_sysname(device, &name); + link = new(Link, 1); + if (!link) + return -ENOMEM; + + *link = (Link) { + .device = sd_device_ref(device), + }; + + r = sd_device_get_sysname(device, &link->ifname); if (r < 0) return r; - r = sd_device_get_ifindex(device, &ifindex); + r = sd_device_get_ifindex(device, &link->ifindex); if (r < 0) return r; - r = rtnl_get_link_info(rtnl, ifindex, &iftype, &flags, &hw_addr, &permanent_hw_addr); + r = sd_device_get_action(device, &link->action); if (r < 0) return r; - /* Do not configure loopback interfaces by .link files. */ - if (flags & IFF_LOOPBACK) - return -ENOENT; + r = device_unsigned_attribute(device, "name_assign_type", &link->name_assign_type); + if (r < 0) + log_link_debug_errno(link, r, "Failed to get \"name_assign_type\" attribute, ignoring: %m"); - if (hw_addr.length > 0 && permanent_hw_addr.length == 0) { - r = ethtool_get_permanent_hw_addr(&ctx->ethtool_fd, name, &permanent_hw_addr); + r = device_unsigned_attribute(device, "addr_assign_type", &link->addr_assign_type); + if (r < 0) + log_link_debug_errno(link, r, "Failed to get \"addr_assign_type\" attribute, ignoring: %m"); + + r = rtnl_get_link_info(rtnl, link->ifindex, &link->iftype, &link->flags, &link->hw_addr, &link->permanent_hw_addr); + if (r < 0) + return r; + + if (link->hw_addr.length > 0 && link->permanent_hw_addr.length == 0) { + r = ethtool_get_permanent_hw_addr(&ctx->ethtool_fd, link->ifname, &link->permanent_hw_addr); if (r < 0) - log_device_debug_errno(device, r, "Failed to get permanent hardware address, ignoring: %m"); + log_link_debug_errno(link, r, "Failed to get permanent hardware address, ignoring: %m"); } - (void) device_unsigned_attribute(device, "name_assign_type", &name_assign_type); + r = ethtool_get_driver(&ctx->ethtool_fd, link->ifname, &link->driver); + if (r < 0) + log_link_debug_errno(link, r, "Failed to get driver, ignoring: %m"); + + *ret = TAKE_PTR(link); + return 0; +} + +int link_get_config(LinkConfigContext *ctx, Link *link) { + LinkConfig *config; + int r; + + assert(ctx); + assert(link); + + /* Do not configure loopback interfaces by .link files. */ + if (link->flags & IFF_LOOPBACK) + return -ENOENT; LIST_FOREACH(configs, config, ctx->configs) { - r = net_match_config(&config->match, device, &hw_addr, &permanent_hw_addr, - NULL, iftype, NULL, NULL, 0, NULL, NULL); + r = net_match_config( + &config->match, + link->device, + &link->hw_addr, + &link->permanent_hw_addr, + link->driver, + link->iftype, + link->ifname, + /* alternative_names = */ NULL, + /* wlan_iftype = */ 0, + /* ssid = */ NULL, + /* bssid = */ NULL); if (r < 0) return r; if (r == 0) continue; - if (config->match.ifname && !strv_contains(config->match.ifname, "*") && name_assign_type == NET_NAME_ENUM) - log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.", - config->filename); + if (config->match.ifname && !strv_contains(config->match.ifname, "*") && link->name_assign_type == NET_NAME_ENUM) + log_link_warning(link, "Config file %s is applied to device based on potentially unpredictable interface name.", + config->filename); else - log_device_debug(device, "Config file %s is applied", config->filename); + log_link_debug(link, "Config file %s is applied", config->filename); - *ret = config; + link->config = config; return 0; } return -ENOENT; } -static int link_config_apply_ethtool_settings(int *ethtool_fd, const LinkConfig *config, sd_device *device) { +static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) { + LinkConfig *config; const char *name; int r; + assert(link); + assert(link->config); assert(ethtool_fd); - assert(config); - assert(device); - r = sd_device_get_sysname(device, &name); - if (r < 0) - return log_device_error_errno(device, r, "Failed to get sysname: %m"); + config = link->config; + name = link->ifname; r = ethtool_set_glinksettings(ethtool_fd, name, config->autonegotiation, config->advertise, config->speed, config->duplex, config->port); if (r < 0) { if (config->autonegotiation >= 0) - log_device_warning_errno(device, r, "Could not %s auto negotiation, ignoring: %m", - enable_disable(config->autonegotiation)); + log_link_warning_errno(link, r, "Could not %s auto negotiation, ignoring: %m", + enable_disable(config->autonegotiation)); if (!eqzero(config->advertise)) - log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); + log_link_warning_errno(link, r, "Could not set advertise mode, ignoring: %m"); if (config->speed > 0) - log_device_warning_errno(device, r, "Could not set speed to %"PRIu64"Mbps, ignoring: %m", - DIV_ROUND_UP(config->speed, 1000000)); + log_link_warning_errno(link, r, "Could not set speed to %"PRIu64"Mbps, ignoring: %m", + DIV_ROUND_UP(config->speed, 1000000)); if (config->duplex >= 0) - log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", - duplex_to_string(config->duplex)); + log_link_warning_errno(link, r, "Could not set duplex to %s, ignoring: %m", + duplex_to_string(config->duplex)); if (config->port >= 0) - log_device_warning_errno(device, r, "Could not set port to '%s', ignoring: %m", - port_to_string(config->port)); + log_link_warning_errno(link, r, "Could not set port to '%s', ignoring: %m", + port_to_string(config->port)); } r = ethtool_set_wol(ethtool_fd, name, config->wol, config->wol_password); @@ -447,83 +494,82 @@ static int link_config_apply_ethtool_settings(int *ethtool_fd, const LinkConfig _cleanup_free_ char *str = NULL; (void) wol_options_to_string_alloc(config->wol, &str); - log_device_warning_errno(device, r, "Could not set WakeOnLan%s%s, ignoring: %m", - isempty(str) ? "" : " to ", strempty(str)); + log_link_warning_errno(link, r, "Could not set WakeOnLan%s%s, ignoring: %m", + isempty(str) ? "" : " to ", strempty(str)); } r = ethtool_set_features(ethtool_fd, name, config->features); if (r < 0) - log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m"); + log_link_warning_errno(link, r, "Could not set offload features, ignoring: %m"); r = ethtool_set_channels(ethtool_fd, name, &config->channels); if (r < 0) - log_device_warning_errno(device, r, "Could not set channels, ignoring: %m"); + log_link_warning_errno(link, r, "Could not set channels, ignoring: %m"); r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring); if (r < 0) - log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m"); + log_link_warning_errno(link, r, "Could not set ring buffer, ignoring: %m"); r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control); if (r < 0) - log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m"); + log_link_warning_errno(link, r, "Could not set flow control, ignoring: %m"); r = ethtool_set_nic_coalesce_settings(ethtool_fd, name, &config->coalesce); if (r < 0) - log_device_warning_errno(device, r, "Could not set coalesce settings, ignoring: %m"); + log_link_warning_errno(link, r, "Could not set coalesce settings, ignoring: %m"); return 0; } -static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) { - unsigned addr_type; - bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM; +static int link_generate_new_mac(Link *link, struct ether_addr *mac) { int r; - assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT)); + assert(link); + assert(link->config); + assert(IN_SET(link->config->mac_address_policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT)); + assert(link->device); + assert(mac); - r = device_unsigned_attribute(device, "addr_assign_type", &addr_type); - if (r < 0) - return r; - switch (addr_type) { + switch (link->addr_assign_type) { case NET_ADDR_SET: - log_device_debug(device, "MAC on the device already set by userspace"); + log_link_debug(link, "MAC on the device already set by userspace"); return 0; case NET_ADDR_STOLEN: - log_device_debug(device, "MAC on the device already set based on another device"); + log_link_debug(link, "MAC on the device already set based on another device"); return 0; case NET_ADDR_RANDOM: case NET_ADDR_PERM: break; default: - log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type); + log_link_warning(link, "Unknown addr_assign_type %u, ignoring", link->addr_assign_type); return 0; } - if (want_random == (addr_type == NET_ADDR_RANDOM)) { - log_device_debug(device, "MAC on the device already matches policy *%s*", - mac_address_policy_to_string(policy)); + if ((link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM) == (link->addr_assign_type == NET_ADDR_RANDOM)) { + log_link_debug(link, "MAC on the device already matches policy *%s*", + mac_address_policy_to_string(link->config->mac_address_policy)); return 0; } - if (want_random) { - log_device_debug(device, "Using random bytes to generate MAC"); + if (link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM) { + log_link_debug(link, "Using random bytes to generate MAC"); /* We require genuine randomness here, since we want to make sure we won't collide with other * systems booting up at the very same time. We do allow RDRAND however, since this is not * cryptographic key material. */ r = genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND); if (r < 0) - return log_device_error_errno(device, r, "Failed to acquire random data to generate MAC: %m"); + return log_link_warning_errno(link, r, "Failed to acquire random data to generate MAC: %m"); } else { uint64_t result; - r = net_get_unique_predictable_data(device, + r = net_get_unique_predictable_data(link->device, naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS), &result); if (r < 0) - return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m"); + return log_link_warning_errno(link, r, "Could not generate persistent MAC: %m"); - log_device_debug(device, "Using generated persistent MAC address"); + log_link_debug(link, "Using generated persistent MAC address"); assert_cc(ETH_ALEN <= sizeof(result)); memcpy(mac->ether_addr_octet, &result, ETH_ALEN); } @@ -534,74 +580,78 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr return 1; } -static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const LinkConfig *config, sd_device *device) { +static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { struct ether_addr generated_mac, *mac = NULL; - int ifindex, r; + LinkConfig *config; + int r; + assert(link); + assert(link->config); assert(rtnl); - assert(config); - assert(device); - r = sd_device_get_ifindex(device, &ifindex); - if (r < 0) - return log_device_error_errno(device, r, "Could not find ifindex: %m"); + config = link->config; if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) { - if (get_mac(device, config->mac_address_policy, &generated_mac) > 0) + if (link_generate_new_mac(link, &generated_mac) > 0) mac = &generated_mac; } else mac = config->mac; - r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, + r = rtnl_set_link_properties(rtnl, link->ifindex, config->alias, mac, config->txqueues, config->rxqueues, config->txqueuelen, config->mtu, config->gso_max_size, config->gso_max_segments); if (r < 0) - log_device_warning_errno(device, r, - "Could not set Alias=, MACAddress=, " - "TransmitQueues=, ReceiveQueues=, TransmitQueueLength=, MTU=, " - "GenericSegmentOffloadMaxBytes= or GenericSegmentOffloadMaxSegments=, " - "ignoring: %m"); + log_link_warning_errno(link, r, + "Could not set Alias=, MACAddress=/MACAddressPolicy=, " + "TransmitQueues=, ReceiveQueues=, TransmitQueueLength=, MTUBytes=, " + "GenericSegmentOffloadMaxBytes= or GenericSegmentOffloadMaxSegments=, " + "ignoring: %m"); return 0; } -static int link_config_generate_new_name(const LinkConfigContext *ctx, const LinkConfig *config, sd_device *device, const char **ret_name) { - unsigned name_type = NET_NAME_UNKNOWN; - int r; +static int link_generate_new_name(Link *link, bool enable_name_policy) { + LinkConfig *config; + sd_device *device; - assert(ctx); - assert(config); - assert(device); - assert(ret_name); + assert(link); + assert(link->config); + assert(link->device); - (void) device_unsigned_attribute(device, "name_assign_type", &name_type); + config = link->config; + device = link->device; - if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED) - && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) { - log_device_debug(device, "Device already has a name given by userspace, not renaming."); + if (link->action == SD_DEVICE_MOVE) { + log_link_debug(link, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", + device_action_to_string(link->action)); goto no_rename; } - if (ctx->enable_name_policy && config->name_policy) - for (NamePolicy *p = config->name_policy; *p != _NAMEPOLICY_INVALID; p++) { - const char *new_name = NULL; - NamePolicy policy = *p; + if (IN_SET(link->name_assign_type, NET_NAME_USER, NET_NAME_RENAMED) && + !naming_scheme_has(NAMING_ALLOW_RERENAMES)) { + log_link_debug(link, "Device already has a name given by userspace, not renaming."); + goto no_rename; + } - switch (policy) { + if (enable_name_policy && config->name_policy) + for (NamePolicy *policy = config->name_policy; *policy != _NAMEPOLICY_INVALID; policy++) { + const char *new_name = NULL; + + switch (*policy) { case NAMEPOLICY_KERNEL: - if (name_type != NET_NAME_PREDICTABLE) + if (link->name_assign_type != NET_NAME_PREDICTABLE) continue; /* The kernel claims to have given a predictable name, keep it. */ - log_device_debug(device, "Policy *%s*: keeping predictable kernel name", - name_policy_to_string(policy)); + log_link_debug(link, "Policy *%s*: keeping predictable kernel name", + name_policy_to_string(*policy)); goto no_rename; case NAMEPOLICY_KEEP: - if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)) + if (!IN_SET(link->name_assign_type, NET_NAME_USER, NET_NAME_RENAMED)) continue; - log_device_debug(device, "Policy *%s*: keeping existing userspace name", - name_policy_to_string(policy)); + log_link_debug(link, "Policy *%s*: keeping existing userspace name", + name_policy_to_string(*policy)); goto no_rename; case NAMEPOLICY_DATABASE: (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name); @@ -622,43 +672,37 @@ static int link_config_generate_new_name(const LinkConfigContext *ctx, const Lin assert_not_reached(); } if (ifname_valid(new_name)) { - log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); - *ret_name = new_name; + log_link_debug(link, "Policy *%s* yields \"%s\".", name_policy_to_string(*policy), new_name); + link->new_name = new_name; return 0; } } - if (config->name) { - log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name); - *ret_name = config->name; + if (link->config->name) { + log_link_debug(link, "Policies didn't yield a name, using specified Name=%s.", link->config->name); + link->new_name = link->config->name; return 0; } - log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming."); + log_link_debug(link, "Policies didn't yield a name and Name= is not given, not renaming."); no_rename: - r = sd_device_get_sysname(device, ret_name); - if (r < 0) - return log_device_error_errno(device, r, "Failed to get sysname: %m"); - + link->new_name = link->ifname; return 0; } -static int link_config_apply_alternative_names(sd_netlink **rtnl, const LinkConfig *config, sd_device *device, const char *new_name) { +static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) { _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL; - const char *current_name; - int ifindex, r; + LinkConfig *config; + sd_device *device; + int r; + assert(link); + assert(link->config); + assert(link->device); assert(rtnl); - assert(config); - assert(device); - r = sd_device_get_sysname(device, ¤t_name); - if (r < 0) - return log_device_error_errno(device, r, "Failed to get sysname: %m"); - - r = sd_device_get_ifindex(device, &ifindex); - if (r < 0) - return log_device_error_errno(device, r, "Could not find ifindex: %m"); + config = link->config; + device = link->device; if (config->alternative_names) { altnames = strv_copy(config->alternative_names); @@ -696,13 +740,13 @@ static int link_config_apply_alternative_names(sd_netlink **rtnl, const LinkConf } } - if (new_name) - strv_remove(altnames, new_name); - strv_remove(altnames, current_name); + if (link->new_name) + strv_remove(altnames, link->new_name); + strv_remove(altnames, link->ifname); - r = rtnl_get_link_alternative_names(rtnl, ifindex, ¤t_altnames); + r = rtnl_get_link_alternative_names(rtnl, link->ifindex, ¤t_altnames); if (r < 0) - log_device_debug_errno(device, r, "Failed to get alternative names, ignoring: %m"); + log_link_debug_errno(link, r, "Failed to get alternative names, ignoring: %m"); char **p; STRV_FOREACH(p, current_altnames) @@ -710,81 +754,45 @@ static int link_config_apply_alternative_names(sd_netlink **rtnl, const LinkConf strv_uniq(altnames); strv_sort(altnames); - r = rtnl_set_link_alternative_names(rtnl, ifindex, altnames); + r = rtnl_set_link_alternative_names(rtnl, link->ifindex, altnames); if (r < 0) - log_device_full_errno(device, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r, - "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m"); + log_link_full_errno(link, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r, + "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m"); return 0; } -int link_config_apply(LinkConfigContext *ctx, const LinkConfig *config, sd_netlink **rtnl, sd_device *device, const char **ret_name) { - const char *new_name; - sd_device_action_t a; +int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { int r; assert(ctx); - assert(config); assert(rtnl); - assert(device); - assert(ret_name); + assert(link); - r = sd_device_get_action(device, &a); - if (r < 0) - return log_device_error_errno(device, r, "Failed to get ACTION= property: %m"); - - if (!IN_SET(a, SD_DEVICE_ADD, SD_DEVICE_BIND, SD_DEVICE_MOVE)) { - log_device_debug(device, "Skipping to apply .link settings on '%s' uevent.", device_action_to_string(a)); - - r = sd_device_get_sysname(device, ret_name); - if (r < 0) - return log_device_error_errno(device, r, "Failed to get sysname: %m"); + if (!IN_SET(link->action, SD_DEVICE_ADD, SD_DEVICE_BIND, SD_DEVICE_MOVE)) { + log_link_debug(link, "Skipping to apply .link settings on '%s' uevent.", + device_action_to_string(link->action)); + link->new_name = link->ifname; return 0; } - r = link_config_apply_ethtool_settings(&ctx->ethtool_fd, config, device); + r = link_apply_ethtool_settings(link, &ctx->ethtool_fd); if (r < 0) return r; - r = link_config_apply_rtnl_settings(rtnl, config, device); + r = link_apply_rtnl_settings(link, rtnl); if (r < 0) return r; - if (a == SD_DEVICE_MOVE) { - log_device_debug(device, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", device_action_to_string(a)); - - r = sd_device_get_sysname(device, &new_name); - if (r < 0) - return log_device_error_errno(device, r, "Failed to get sysname: %m"); - } else { - r = link_config_generate_new_name(ctx, config, device, &new_name); - if (r < 0) - return r; - } - - r = link_config_apply_alternative_names(rtnl, config, device, new_name); + r = link_generate_new_name(link, ctx->enable_name_policy); if (r < 0) return r; - *ret_name = new_name; - return 0; -} - -int link_get_driver(LinkConfigContext *ctx, sd_device *device, char **ret) { - const char *name; - char *driver = NULL; - int r; - - r = sd_device_get_sysname(device, &name); + r = link_apply_alternative_names(link, rtnl); if (r < 0) return r; - r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver); - if (r < 0) - return r; - - *ret = driver; return 0; } diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 47619d923f..ad2a32790d 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -33,6 +33,24 @@ typedef enum NamePolicy { _NAMEPOLICY_INVALID = -EINVAL, } NamePolicy; +typedef struct Link { + int ifindex; + const char *ifname; + const char *new_name; + + LinkConfig *config; + sd_device *device; + sd_device_action_t action; + + char *driver; + uint16_t iftype; + uint32_t flags; + struct hw_addr_data hw_addr; + struct hw_addr_data permanent_hw_addr; + unsigned name_assign_type; + unsigned addr_assign_type; +} Link; + struct LinkConfig { char *filename; @@ -80,9 +98,12 @@ int link_load_one(LinkConfigContext *ctx, const char *filename); int link_config_load(LinkConfigContext *ctx); bool link_config_should_reload(LinkConfigContext *ctx); -int link_config_get(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, LinkConfig **ret); -int link_config_apply(LinkConfigContext *ctx, const LinkConfig *config, sd_netlink **rtnl, sd_device *device, const char **ret_name); -int link_get_driver(LinkConfigContext *ctx, sd_device *device, char **ret); +int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link **ret); +Link *link_free(Link *link); +DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free); + +int link_get_config(LinkConfigContext *ctx, Link *link); +int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link); const char *name_policy_to_string(NamePolicy p) _const_; NamePolicy name_policy_from_string(const char *p) _pure_; diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index 4c7a5b23fd..d4095c7684 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -11,25 +11,25 @@ static LinkConfigContext *ctx = NULL; static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, char **argv, bool test) { - _cleanup_free_ char *driver = NULL; - const char *name = NULL; - LinkConfig *link; + _cleanup_(link_freep) Link *link = NULL; int r; if (argc > 1) return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments."); - r = link_get_driver(ctx, dev, &driver); + r = link_new(ctx, rtnl, dev, &link); + if (r == -ENODEV) { + log_device_debug_errno(dev, r, "Link vanished while getting information, ignoring."); + return 0; + } if (r < 0) - log_device_full_errno(dev, ERRNO_IS_NOT_SUPPORTED(r) || r == -ENODEV ? LOG_DEBUG : LOG_WARNING, - r, "Failed to query device driver: %m"); - else - udev_builtin_add_property(dev, test, "ID_NET_DRIVER", driver); + return log_device_warning_errno(dev, r, "Failed to get link information: %m"); - r = link_config_get(ctx, rtnl, dev, &link); + if (link->driver) + udev_builtin_add_property(dev, test, "ID_NET_DRIVER", link->driver); + + r = link_get_config(ctx, link); if (r < 0) { - if (r == -ENODEV) - return log_device_debug_errno(dev, r, "Link vanished while searching for configuration for it."); if (r == -ENOENT) { log_device_debug_errno(dev, r, "No matching link configuration found, ignoring device."); return 0; @@ -38,16 +38,15 @@ static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, c return log_device_error_errno(dev, r, "Failed to get link config: %m"); } - r = link_config_apply(ctx, link, rtnl, dev, &name); + r = link_apply_config(ctx, rtnl, link); if (r == -ENODEV) log_device_debug_errno(dev, r, "Link vanished while applying configuration, ignoring."); else if (r < 0) log_device_warning_errno(dev, r, "Could not apply link configuration, ignoring: %m"); - udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->filename); - - if (name) - udev_builtin_add_property(dev, test, "ID_NET_NAME", name); + udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->config->filename); + if (link->new_name) + udev_builtin_add_property(dev, test, "ID_NET_NAME", link->new_name); return 0; } From 9e2b7763d361f1533966bd85329c1bbd2d914240 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 6 Nov 2021 10:58:31 +0900 Subject: [PATCH 3/3] udev/net: make MACAddress= takes hardware address for infiniband --- src/libsystemd/sd-netlink/netlink-util.c | 16 ++- src/libsystemd/sd-netlink/netlink-util.h | 2 +- src/udev/net/link-config-gperf.gperf | 2 +- src/udev/net/link-config.c | 141 +++++++++++++++++------ src/udev/net/link-config.h | 2 +- 5 files changed, 119 insertions(+), 44 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index c477bdd326..8b4ed44790 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -64,7 +64,7 @@ int rtnl_set_link_properties( sd_netlink **rtnl, int ifindex, const char *alias, - const struct ether_addr *mac, + const struct hw_addr_data *hw_addr, uint32_t txqueues, uint32_t rxqueues, uint32_t txqueuelen, @@ -77,8 +77,14 @@ int rtnl_set_link_properties( assert(rtnl); assert(ifindex > 0); - if (!alias && !mac && txqueues == 0 && rxqueues == 0 && txqueuelen == UINT32_MAX && mtu == 0 && - gso_max_size == 0 && gso_max_segments == 0) + if (!alias && + (!hw_addr || hw_addr->length == 0) && + txqueues == 0 && + rxqueues == 0 && + txqueuelen == UINT32_MAX && + mtu == 0 && + gso_max_size == 0 && + gso_max_segments == 0) return 0; if (!*rtnl) { @@ -97,8 +103,8 @@ int rtnl_set_link_properties( return r; } - if (mac) { - r = sd_netlink_message_append_ether_addr(message, IFLA_ADDRESS, mac); + if (hw_addr && hw_addr->length > 0) { + r = netlink_message_append_hw_addr(message, IFLA_ADDRESS, hw_addr); if (r < 0) return r; } diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 837a606649..9024c00830 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -76,7 +76,7 @@ int rtnl_set_link_properties( sd_netlink **rtnl, int ifindex, const char *alias, - const struct ether_addr *mac, + const struct hw_addr_data *hw_addr, uint32_t txqueues, uint32_t rxqueues, uint32_t txqueuelen, diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 5e570f00fb..ac7825b00f 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -35,7 +35,7 @@ Match.KernelVersion, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(LinkConfig, conditions) Link.Description, config_parse_string, 0, offsetof(LinkConfig, description) Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(LinkConfig, mac_address_policy) -Link.MACAddress, config_parse_ether_addr, 0, offsetof(LinkConfig, mac) +Link.MACAddress, config_parse_hw_addr, 0, offsetof(LinkConfig, hw_addr) Link.NamePolicy, config_parse_name_policy, 0, offsetof(LinkConfig, name_policy) Link.Name, config_parse_ifname, 0, offsetof(LinkConfig, name) Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(LinkConfig, alternative_names) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 940b5cdfea..c248024ca4 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -8,6 +8,7 @@ #include "sd-netlink.h" #include "alloc-util.h" +#include "arphrd-util.h" #include "conf-files.h" #include "conf-parser.h" #include "creds-util.h" @@ -52,7 +53,6 @@ static LinkConfig* link_config_free(LinkConfig *config) { condition_free_list(config->conditions); free(config->description); - free(config->mac); free(config->name_policy); free(config->name); strv_free(config->alternative_names); @@ -237,7 +237,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { *config = (LinkConfig) { .filename = TAKE_PTR(name), - .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID, + .mac_address_policy = MAC_ADDRESS_POLICY_NONE, .wol = UINT32_MAX, /* UINT32_MAX means do not change WOL setting. */ .duplex = _DUP_INVALID, .port = _NET_DEV_PORT_INVALID, @@ -276,12 +276,11 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { return 0; } - if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM) && config->mac) { + if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM) && + config->hw_addr.length > 0) log_warning("%s: MACAddress= in [Link] section will be ignored when MACAddressPolicy= " "is set to \"persistent\" or \"random\".", filename); - config->mac = mfree(config->mac); - } r = link_adjust_wol_options(config); if (r < 0) @@ -521,67 +520,141 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) { return 0; } -static int link_generate_new_mac(Link *link, struct ether_addr *mac) { +static bool hw_addr_is_valid(Link *link, const struct hw_addr_data *hw_addr) { + assert(link); + assert(hw_addr); + + switch (link->iftype) { + case ARPHRD_ETHER: + /* Refuse all zero and all 0xFF. */ + assert(hw_addr->length == ETH_ALEN); + return !ether_addr_is_null(&hw_addr->ether) && !ether_addr_is_broadcast(&hw_addr->ether); + + case ARPHRD_INFINIBAND: + /* The last 8 bytes cannot be zero*/ + assert(hw_addr->length == INFINIBAND_ALEN); + return !memeqzero(hw_addr->bytes + INFINIBAND_ALEN - 8, 8); + + default: + assert_not_reached(); + } +} + +static int link_generate_new_hw_addr(Link *link, struct hw_addr_data *ret) { + struct hw_addr_data hw_addr = HW_ADDR_NULL; + bool warn_invalid = false; + uint8_t *p; + size_t len; int r; assert(link); assert(link->config); - assert(IN_SET(link->config->mac_address_policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT)); assert(link->device); - assert(mac); + assert(ret); + + if (link->hw_addr.length == 0) + goto finalize; + + if (link->config->mac_address_policy == MAC_ADDRESS_POLICY_NONE) { + log_link_debug(link, "Using static MAC address."); + hw_addr = link->config->hw_addr; + warn_invalid = true; + goto finalize; + } + + if (!IN_SET(link->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND)) + goto finalize; switch (link->addr_assign_type) { case NET_ADDR_SET: - log_link_debug(link, "MAC on the device already set by userspace"); - return 0; + log_link_debug(link, "MAC address on the device already set by userspace."); + goto finalize; case NET_ADDR_STOLEN: - log_link_debug(link, "MAC on the device already set based on another device"); - return 0; + log_link_debug(link, "MAC address on the device already set based on another device."); + goto finalize; case NET_ADDR_RANDOM: case NET_ADDR_PERM: break; default: log_link_warning(link, "Unknown addr_assign_type %u, ignoring", link->addr_assign_type); - return 0; + goto finalize; } if ((link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM) == (link->addr_assign_type == NET_ADDR_RANDOM)) { - log_link_debug(link, "MAC on the device already matches policy *%s*", + log_link_debug(link, "MAC address on the device already matches policy \"%s\".", mac_address_policy_to_string(link->config->mac_address_policy)); - return 0; + goto finalize; } - if (link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM) { - log_link_debug(link, "Using random bytes to generate MAC"); + hw_addr = (struct hw_addr_data) { + .length = arphrd_to_hw_addr_len(link->iftype), + }; + switch (link->iftype) { + case ARPHRD_ETHER: + p = hw_addr.bytes; + len = hw_addr.length; + break; + case ARPHRD_INFINIBAND: + p = hw_addr.bytes + INFINIBAND_ALEN - 8; + len = 8; + break; + default: + assert_not_reached(); + } + + if (link->config->mac_address_policy == MAC_ADDRESS_POLICY_RANDOM) /* We require genuine randomness here, since we want to make sure we won't collide with other * systems booting up at the very same time. We do allow RDRAND however, since this is not * cryptographic key material. */ - r = genuine_random_bytes(mac->ether_addr_octet, ETH_ALEN, RANDOM_ALLOW_RDRAND); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to acquire random data to generate MAC: %m"); - } else { + for (;;) { + r = genuine_random_bytes(p, len, RANDOM_ALLOW_RDRAND); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to acquire random data to generate MAC address: %m"); + + if (hw_addr_is_valid(link, &hw_addr)) + break; + } + + else { uint64_t result; r = net_get_unique_predictable_data(link->device, naming_scheme_has(NAMING_STABLE_VIRTUAL_MACS), &result); if (r < 0) - return log_link_warning_errno(link, r, "Could not generate persistent MAC: %m"); + return log_link_warning_errno(link, r, "Could not generate persistent MAC address: %m"); - log_link_debug(link, "Using generated persistent MAC address"); - assert_cc(ETH_ALEN <= sizeof(result)); - memcpy(mac->ether_addr_octet, &result, ETH_ALEN); + assert(len <= sizeof(result)); + memcpy(p, &result, len); + if (!hw_addr_is_valid(link, &hw_addr)) + return log_link_warning_errno(link, SYNTHETIC_ERRNO(EINVAL), + "Could not generate valid persistent MAC address: %m"); } - /* see eth_random_addr in the kernel */ - mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */ - mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */ - return 1; +finalize: + + r = net_verify_hardware_address(link->ifname, warn_invalid, link->iftype, &link->hw_addr, &hw_addr); + if (r < 0) + return r; + + if (hw_addr_equal(&link->hw_addr, &hw_addr)) { + *ret = HW_ADDR_NULL; + return 0; + } + + if (hw_addr.length > 0) + log_link_debug(link, "Applying %s MAC address: %s", + link->config->mac_address_policy == MAC_ADDRESS_POLICY_NONE ? "static" : + mac_address_policy_to_string(link->config->mac_address_policy), + HW_ADDR_TO_STR(&hw_addr)); + + *ret = hw_addr; + return 0; } static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { - struct ether_addr generated_mac, *mac = NULL; + struct hw_addr_data hw_addr = {}; LinkConfig *config; int r; @@ -591,13 +664,9 @@ static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { config = link->config; - if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) { - if (link_generate_new_mac(link, &generated_mac) > 0) - mac = &generated_mac; - } else - mac = config->mac; + (void) link_generate_new_hw_addr(link, &hw_addr); - r = rtnl_set_link_properties(rtnl, link->ifindex, config->alias, mac, + r = rtnl_set_link_properties(rtnl, link->ifindex, config->alias, &hw_addr, config->txqueues, config->rxqueues, config->txqueuelen, config->mtu, config->gso_max_size, config->gso_max_segments); if (r < 0) diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index ad2a32790d..092a6fa808 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -58,7 +58,7 @@ struct LinkConfig { LIST_HEAD(Condition, conditions); char *description; - struct ether_addr *mac; + struct hw_addr_data hw_addr; MACAddressPolicy mac_address_policy; NamePolicy *name_policy; NamePolicy *alternative_names_policy;