diff options
Diffstat (limited to 'src/udev/net')
-rw-r--r-- | src/udev/net/link-config-gperf.gperf | 4 | ||||
-rw-r--r-- | src/udev/net/link-config.c | 359 | ||||
-rw-r--r-- | src/udev/net/link-config.h | 14 |
3 files changed, 358 insertions, 19 deletions
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 240f16e..b77759d 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -38,6 +38,9 @@ Match.Credential, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(LinkConfig, conditions) Match.Firmware, config_parse_net_condition, CONDITION_FIRMWARE, offsetof(LinkConfig, conditions) Link.Description, config_parse_string, 0, offsetof(LinkConfig, description) +Link.Property, config_parse_udev_property, 0, offsetof(LinkConfig, properties) +Link.ImportProperty, config_parse_udev_property_name, 0, offsetof(LinkConfig, import_properties) +Link.UnsetProperty, config_parse_udev_property_name, 0, offsetof(LinkConfig, unset_properties) Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(LinkConfig, mac_address_policy) Link.MACAddress, config_parse_hw_addr, 0, offsetof(LinkConfig, hw_addr) Link.NamePolicy, config_parse_name_policy, 0, offsetof(LinkConfig, name_policy) @@ -105,6 +108,7 @@ Link.RxMaxCoalescedHighFrames, config_parse_coalesce_u32, Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high) Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high) Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval) +Link.ReceivePacketSteeringCPUMask, config_parse_rps_cpu_mask, 0, offsetof(LinkConfig, rps_cpu_mask) Link.MDI, config_parse_mdi, 0, offsetof(LinkConfig, mdi) Link.SR-IOVVirtualFunctions, config_parse_sr_iov_num_vfs, 0, offsetof(LinkConfig, sr_iov_num_vfs) SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 910ec27..647cdee 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -15,6 +15,8 @@ #include "creds-util.h" #include "device-private.h" #include "device-util.h" +#include "env-util.h" +#include "escape.h" #include "ethtool-util.h" #include "fd-util.h" #include "fileio.h" @@ -30,12 +32,20 @@ #include "path-util.h" #include "proc-cmdline.h" #include "random-util.h" +#include "specifier.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "udev-builtin.h" #include "utf8.h" +static const Specifier link_specifier_table[] = { + COMMON_SYSTEM_SPECIFIERS, + COMMON_TMP_SPECIFIERS, + {} +}; + struct LinkConfigContext { LIST_HEAD(LinkConfig, configs); int ethtool_fd; @@ -53,6 +63,9 @@ static LinkConfig* link_config_free(LinkConfig *config) { condition_free_list(config->conditions); free(config->description); + strv_free(config->properties); + strv_free(config->import_properties); + strv_free(config->unset_properties); free(config->name_policy); free(config->name); strv_free(config->alternative_names); @@ -60,6 +73,7 @@ static LinkConfig* link_config_free(LinkConfig *config) { free(config->alias); free(config->wol_password_file); erase_and_free(config->wol_password); + cpu_set_free(config->rps_cpu_mask); ordered_hashmap_free_with_destructor(config->sr_iov_by_section, sr_iov_free); @@ -363,18 +377,20 @@ Link *link_free(Link *link) { return NULL; sd_device_unref(link->device); + sd_device_unref(link->device_db_clone); free(link->kind); strv_free(link->altnames); return mfree(link); } -int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link **ret) { +int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, sd_device *device_db_clone, Link **ret) { _cleanup_(link_freep) Link *link = NULL; int r; assert(ctx); assert(rtnl); assert(device); + assert(device_db_clone); assert(ret); link = new(Link, 1); @@ -383,6 +399,7 @@ int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link *link = (Link) { .device = sd_device_ref(device), + .device_db_clone = sd_device_ref(device_db_clone), }; r = sd_device_get_sysname(device, &link->ifname); @@ -466,7 +483,7 @@ int link_get_config(LinkConfigContext *ctx, Link *link) { return -ENOENT; } -static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) { +static int link_apply_ethtool_settings(Link *link, int *ethtool_fd, EventMode mode) { LinkConfig *config; const char *name; int r; @@ -475,6 +492,11 @@ static int link_apply_ethtool_settings(Link *link, int *ethtool_fd) { assert(link->config); assert(ethtool_fd); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of ethtool settings."); + return 0; + } + config = link->config; name = link->ifname; @@ -667,7 +689,7 @@ finalize: return 0; } -static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { +static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl, EventMode mode) { struct hw_addr_data hw_addr = {}; LinkConfig *config; int r; @@ -676,6 +698,11 @@ static int link_apply_rtnl_settings(Link *link, sd_netlink **rtnl) { assert(link->config); assert(rtnl); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of rtnl settings."); + return 0; + } + config = link->config; (void) link_generate_new_hw_addr(link, &hw_addr); @@ -725,7 +752,7 @@ static int link_generate_new_name(Link *link) { device = link->device; if (link->action != SD_DEVICE_ADD) { - log_link_debug(link, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", + log_link_debug(link, "Not applying Name= and NamePolicy= on '%s' uevent.", device_action_to_string(link->action)); goto no_rename; } @@ -805,7 +832,7 @@ static int link_generate_alternative_names(Link *link) { assert(!link->altnames); if (link->action != SD_DEVICE_ADD) { - log_link_debug(link, "Skipping to apply AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.", + log_link_debug(link, "Not applying AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.", device_action_to_string(link->action)); return 0; } @@ -879,7 +906,7 @@ static int sr_iov_configure(Link *link, sd_netlink **rtnl, SRIOV *sr_iov) { return 0; } -static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { +static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl, EventMode mode) { SRIOV *sr_iov; uint32_t n; int r; @@ -888,6 +915,11 @@ static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { assert(link->config); assert(link->device); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of SR-IOV settings."); + return 0; + } + r = sr_iov_set_num_vfs(link->device, link->config->sr_iov_num_vfs, link->config->sr_iov_by_section); if (r < 0) log_link_warning_errno(link, r, "Failed to set the number of SR-IOV virtual functions, ignoring: %m"); @@ -921,26 +953,122 @@ static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { return 0; } -int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { +static int link_apply_rps_cpu_mask(Link *link, EventMode mode) { + _cleanup_free_ char *mask_str = NULL; + LinkConfig *config; int r; - assert(ctx); - assert(rtnl); assert(link); + config = ASSERT_PTR(link->config); - 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)); + if (mode != EVENT_UDEV_WORKER) { + log_link_debug(link, "Running in test mode, skipping application of RPS setting."); + return 0; + } - link->new_name = link->ifname; + /* Skip if the config is not specified. */ + if (!config->rps_cpu_mask) return 0; + + mask_str = cpu_set_to_mask_string(config->rps_cpu_mask); + if (!mask_str) + return log_oom(); + + log_link_debug(link, "Applying RPS CPU mask: %s", mask_str); + + /* Currently, this will set CPU mask to all rx queue of matched device. */ + FOREACH_DEVICE_SYSATTR(link->device, attr) { + const char *c; + + c = path_startswith(attr, "queues/"); + if (!c) + continue; + + c = startswith(c, "rx-"); + if (!c) + continue; + + c += strcspn(c, "/"); + + if (!path_equal(c, "/rps_cpus")) + continue; + + r = sd_device_set_sysattr_value(link->device, attr, mask_str); + if (r < 0) + log_link_warning_errno(link, r, "Failed to write %s sysfs attribute, ignoring: %m", attr); + } + + return 0; +} + +static int link_apply_udev_properties(Link *link, EventMode mode) { + LinkConfig *config; + sd_device *device; + + assert(link); + + config = ASSERT_PTR(link->config); + device = ASSERT_PTR(link->device); + + /* 1. apply ImportProperty=. */ + STRV_FOREACH(p, config->import_properties) + (void) udev_builtin_import_property(device, link->device_db_clone, mode, *p); + + /* 2. apply Property=. */ + STRV_FOREACH(p, config->properties) { + _cleanup_free_ char *key = NULL; + const char *eq; + + eq = strchr(*p, '='); + if (!eq) + continue; + + key = strndup(*p, eq - *p); + if (!key) + return log_oom(); + + (void) udev_builtin_add_property(device, mode, key, eq + 1); + } + + /* 3. apply UnsetProperty=. */ + STRV_FOREACH(p, config->unset_properties) + (void) udev_builtin_add_property(device, mode, *p, NULL); + + /* 4. set the default properties. */ + (void) udev_builtin_add_property(device, mode, "ID_NET_LINK_FILE", config->filename); + + _cleanup_free_ char *joined = NULL; + STRV_FOREACH(d, config->dropins) { + _cleanup_free_ char *escaped = NULL; + + escaped = xescape(*d, ":"); + if (!escaped) + return log_oom(); + + if (!strextend_with_separator(&joined, ":", escaped)) + return log_oom(); } - r = link_apply_ethtool_settings(link, &ctx->ethtool_fd); + (void) udev_builtin_add_property(device, mode, "ID_NET_LINK_FILE_DROPINS", joined); + + if (link->new_name) + (void) udev_builtin_add_property(device, mode, "ID_NET_NAME", link->new_name); + + return 0; +} + +int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link, EventMode mode) { + int r; + + assert(ctx); + assert(rtnl); + assert(link); + + r = link_apply_ethtool_settings(link, &ctx->ethtool_fd, mode); if (r < 0) return r; - r = link_apply_rtnl_settings(link, rtnl); + r = link_apply_rtnl_settings(link, rtnl, mode); if (r < 0) return r; @@ -952,11 +1080,151 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { if (r < 0) return r; - r = link_apply_sr_iov_config(link, rtnl); + r = link_apply_sr_iov_config(link, rtnl, mode); if (r < 0) return r; - return 0; + r = link_apply_rps_cpu_mask(link, mode); + if (r < 0) + return r; + + return link_apply_udev_properties(link, mode); +} + +int config_parse_udev_property( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char ***properties = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *properties = strv_free(*properties); + return 0; + } + + for (const char *p = rvalue;; ) { + _cleanup_free_ char *word = NULL, *resolved = NULL, *key = NULL; + const char *eq; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring assignment: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + r = specifier_printf(word, SIZE_MAX, link_specifier_table, NULL, NULL, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve specifiers in %s, ignoring assignment: %m", word); + continue; + } + + /* The restriction for udev property is not clear. Let's apply the one for environment variable here. */ + if (!env_assignment_is_valid(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property, ignoring assignment: %s", word); + continue; + } + + assert_se(eq = strchr(resolved, '=')); + key = strndup(resolved, eq - resolved); + if (!key) + return log_oom(); + + if (!device_property_can_set(key)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property name '%s', ignoring assignment: %s", key, resolved); + continue; + } + + r = strv_env_replace_consume(properties, TAKE_PTR(resolved)); + if (r < 0) + return log_error_errno(r, "Failed to update properties: %m"); + } +} + +int config_parse_udev_property_name( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char ***properties = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *properties = strv_free(*properties); + return 0; + } + + for (const char *p = rvalue;; ) { + _cleanup_free_ char *word = NULL, *resolved = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring assignment: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + r = specifier_printf(word, SIZE_MAX, link_specifier_table, NULL, NULL, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve specifiers in %s, ignoring assignment: %m", word); + continue; + } + + /* The restriction for udev property is not clear. Let's apply the one for environment variable here. */ + if (!env_name_is_valid(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property name, ignoring assignment: %s", resolved); + continue; + } + + if (!device_property_can_set(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid udev property name, ignoring assignment: %s", resolved); + continue; + } + + r = strv_consume(properties, TAKE_PTR(resolved)); + if (r < 0) + return log_error_errno(r, "Failed to update properties: %m"); + } } int config_parse_ifalias( @@ -1110,6 +1378,63 @@ int config_parse_wol_password( return 0; } +int config_parse_rps_cpu_mask( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(cpu_set_freep) CPUSet *allocated = NULL; + CPUSet *mask, **rps_cpu_mask = ASSERT_PTR(data); + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *rps_cpu_mask = cpu_set_free(*rps_cpu_mask); + return 0; + } + + if (*rps_cpu_mask) + mask = *rps_cpu_mask; + else { + allocated = new0(CPUSet, 1); + if (!allocated) + return log_oom(); + + mask = allocated; + } + + if (streq(rvalue, "disable")) + cpu_set_reset(mask); + + else if (streq(rvalue, "all")) { + r = cpu_mask_add_all(mask); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to create CPU affinity mask representing \"all\" cpus, ignoring: %m"); + return 0; + } + } else { + r = parse_cpu_set_extend(rvalue, mask, /* warn= */ true, unit, filename, line, lvalue); + if (r < 0) + return 0; + } + + if (allocated) + *rps_cpu_mask = TAKE_PTR(allocated); + + return 0; +} + static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = { [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent", [MAC_ADDRESS_POLICY_RANDOM] = "random", diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index bab9d12..103343f 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -6,11 +6,13 @@ #include "condition.h" #include "conf-parser.h" +#include "cpu-set-util.h" #include "ethtool-util.h" #include "hashmap.h" #include "list.h" #include "net-condition.h" #include "netif-naming-scheme.h" +#include "udev-event.h" typedef struct LinkConfigContext LinkConfigContext; typedef struct LinkConfig LinkConfig; @@ -31,6 +33,7 @@ typedef struct Link { LinkConfig *config; sd_device *device; + sd_device *device_db_clone; sd_device_action_t action; char *kind; @@ -51,6 +54,9 @@ struct LinkConfig { LIST_HEAD(Condition, conditions); char *description; + char **properties; + char **import_properties; + char **unset_properties; struct hw_addr_data hw_addr; MACAddressPolicy mac_address_policy; NamePolicy *name_policy; @@ -80,6 +86,7 @@ struct LinkConfig { int autoneg_flow_control; netdev_coalesce_param coalesce; uint8_t mdi; + CPUSet *rps_cpu_mask; uint32_t sr_iov_num_vfs; OrderedHashmap *sr_iov_by_section; @@ -95,12 +102,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_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link **ret); +int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, sd_device *device_db_clone, 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); +int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link, EventMode mode); const char *mac_address_policy_to_string(MACAddressPolicy p) _const_; MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_; @@ -108,6 +115,8 @@ MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_; /* gperf lookup function */ const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN_TYPE length); +CONFIG_PARSER_PROTOTYPE(config_parse_udev_property); +CONFIG_PARSER_PROTOTYPE(config_parse_udev_property_name); CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); CONFIG_PARSER_PROTOTYPE(config_parse_rx_tx_queues); CONFIG_PARSER_PROTOTYPE(config_parse_txqueuelen); @@ -115,3 +124,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wol_password); CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy); CONFIG_PARSER_PROTOTYPE(config_parse_name_policy); CONFIG_PARSER_PROTOTYPE(config_parse_alternative_names_policy); +CONFIG_PARSER_PROTOTYPE(config_parse_rps_cpu_mask); |