From 6d9a72f3b9b4d00ec80051503e5e3d4d7cd46c05 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Sep 2021 01:28:29 +0900 Subject: [PATCH 1/5] ethtool-util: use sizeof() --- src/shared/ethtool-util.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index af3b917c75cb..d1f5eac63334 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -214,7 +214,7 @@ int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret) { if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -254,7 +254,7 @@ int ethtool_get_link_info( if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -303,7 +303,7 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -362,7 +362,7 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts) { if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -405,7 +405,7 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -538,7 +538,7 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = get_stringset(*ethtool_fd, &ifr, ETH_SS_FEATURES, &strings); if (r < 0) @@ -787,7 +787,7 @@ int ethtool_set_glinksettings( if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = get_glinksettings(*fd, &ifr, &u); if (r < 0) { @@ -857,7 +857,7 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -906,7 +906,7 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*fd, SIOCETHTOOL, &ifr); if (r < 0) @@ -974,7 +974,7 @@ int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const if (r < 0) return r; - strscpy(ifr.ifr_name, IFNAMSIZ, ifname); + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); if (r < 0) From 4253dab576b3ff17887c3e0d97380aab2aa29d82 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Sep 2021 01:41:15 +0900 Subject: [PATCH 2/5] ethtool-util: shorten code a bit Also fixes a error code in debugging log. --- src/shared/ethtool-util.c | 70 ++++++++++++--------------------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index d1f5eac63334..ac21ef0f61a8 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -216,8 +216,7 @@ int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret) { strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (isempty(ecmd.driver)) @@ -256,8 +255,7 @@ int ethtool_get_link_info( strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (ret_autonegotiation) @@ -305,8 +303,7 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (epaddr.addr.size != 6) @@ -364,8 +361,7 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts) { strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; UPDATE(ecmd.wolopts, wolopts, need_update); @@ -374,8 +370,7 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts) { return 0; ecmd.cmd = ETHTOOL_SWOL; - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; return 0; @@ -407,8 +402,7 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (ring->rx.set) @@ -427,8 +421,7 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde return 0; ecmd.cmd = ETHTOOL_SRINGPARAM; - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; return 0; @@ -446,7 +439,6 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st }, }; unsigned len; - int r; assert(ethtool_fd >= 0); assert(ifr); @@ -454,8 +446,7 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st ifr->ifr_data = (void *) &buffer.info; - r = ioctl(ethtool_fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(ethtool_fd, SIOCETHTOOL, ifr) < 0) return -errno; if (!buffer.info.sset_mask) @@ -478,8 +469,7 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st ifr->ifr_data = (void *) strings; - r = ioctl(ethtool_fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(ethtool_fd, SIOCETHTOOL, ifr) < 0) return -errno; *ret = TAKE_PTR(strings); @@ -559,9 +549,8 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features ifr.ifr_data = (void *) sfeatures; - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) - return log_debug_errno(r, "ethtool: could not set ethtool features for %s", ifname); + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) + return log_debug_errno(errno, "ethtool: could not set ethtool features for %s", ifname); return 0; } @@ -575,7 +564,6 @@ static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_uset }; struct ethtool_link_usettings *u; unsigned offset; - int r; assert(fd >= 0); assert(ifr); @@ -591,8 +579,7 @@ static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_uset ifr->ifr_data = (void *) &ecmd; - r = ioctl(fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(fd, SIOCETHTOOL, ifr) < 0) return -errno; if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) @@ -602,8 +589,7 @@ static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_uset ifr->ifr_data = (void *) &ecmd; - r = ioctl(fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(fd, SIOCETHTOOL, ifr) < 0) return -errno; if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) @@ -636,7 +622,6 @@ static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **r struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, }; - int r; assert(fd >= 0); assert(ifr); @@ -644,8 +629,7 @@ static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **r ifr->ifr_data = (void *) &ecmd; - r = ioctl(fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(fd, SIOCETHTOOL, ifr) < 0) return -errno; e = new(struct ethtool_link_usettings, 1); @@ -678,7 +662,6 @@ static int set_slinksettings(int fd, struct ifreq *ifr, const struct ethtool_lin __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32]; } ecmd = {}; unsigned offset; - int r; assert(fd >= 0); assert(ifr); @@ -700,8 +683,7 @@ static int set_slinksettings(int fd, struct ifreq *ifr, const struct ethtool_lin ifr->ifr_data = (void *) &ecmd; - r = ioctl(fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(fd, SIOCETHTOOL, ifr) < 0) return -errno; return 0; @@ -711,7 +693,6 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin struct ethtool_cmd ecmd = { .cmd = ETHTOOL_SSET, }; - int r; assert(fd >= 0); assert(ifr); @@ -736,8 +717,7 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin ifr->ifr_data = (void *) &ecmd; - r = ioctl(fd, SIOCETHTOOL, ifr); - if (r < 0) + if (ioctl(fd, SIOCETHTOOL, ifr) < 0) return -errno; return 0; @@ -859,8 +839,7 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (channels->rx.set) @@ -879,8 +858,7 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha return 0; ecmd.cmd = ETHTOOL_SCHANNELS; - r = ioctl(*fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*fd, SIOCETHTOOL, &ifr) < 0) return -errno; return 0; @@ -908,8 +886,7 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (rx >= 0) @@ -925,8 +902,7 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au return 0; ecmd.cmd = ETHTOOL_SPAUSEPARAM; - r = ioctl(*fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*fd, SIOCETHTOOL, &ifr) < 0) return -errno; return 0; @@ -976,8 +952,7 @@ int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; if (coalesce->use_adaptive_rx_coalesce >= 0) @@ -1050,8 +1025,7 @@ int ethtool_set_nic_coalesce_settings(int *ethtool_fd, const char *ifname, const return 0; ecmd.cmd = ETHTOOL_SCOALESCE; - r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); - if (r < 0) + if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; return 0; From 008d3a370ccdea13290ab9277b32cc582b886b17 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Sep 2021 17:42:52 +0900 Subject: [PATCH 3/5] ethtool: do not set unavailable or never_changed bits --- src/shared/ethtool-util.c | 138 ++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 42 deletions(-) diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index ac21ef0f61a8..59b1bd86f085 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -427,30 +427,31 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde return 0; } -static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, struct ethtool_gstrings **ret) { +static int get_stringset(int ethtool_fd, const char *ifname, enum ethtool_stringset stringset_id, struct ethtool_gstrings **ret) { _cleanup_free_ struct ethtool_gstrings *strings = NULL; struct { struct ethtool_sset_info info; uint32_t space; } buffer = { - .info = { - .cmd = ETHTOOL_GSSET_INFO, - .sset_mask = UINT64_C(1) << stringset_id, - }, + .info.cmd = ETHTOOL_GSSET_INFO, + .info.sset_mask = UINT64_C(1) << stringset_id, }; - unsigned len; + struct ifreq ifr = { + .ifr_data = (void*) &buffer, + }; + uint32_t len; assert(ethtool_fd >= 0); - assert(ifr); + assert(ifname); assert(ret); - ifr->ifr_data = (void *) &buffer.info; + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); - if (ioctl(ethtool_fd, SIOCETHTOOL, ifr) < 0) + if (ioctl(ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; - if (!buffer.info.sset_mask) - return -EINVAL; + if (buffer.info.sset_mask == 0) + return -EOPNOTSUPP; #pragma GCC diagnostic push #if HAVE_ZERO_LENGTH_BOUNDS @@ -458,8 +459,10 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st #endif len = buffer.info.data[0]; #pragma GCC diagnostic pop + if (len == 0) + return -EOPNOTSUPP; - strings = malloc0(sizeof(struct ethtool_gstrings) + len * ETH_GSTRING_LEN); + strings = malloc0(offsetof(struct ethtool_gstrings, data) + len * ETH_GSTRING_LEN); if (!strings) return -ENOMEM; @@ -467,47 +470,92 @@ static int get_stringset(int ethtool_fd, struct ifreq *ifr, int stringset_id, st strings->string_set = stringset_id; strings->len = len; - ifr->ifr_data = (void *) strings; + ifr.ifr_data = (void*) strings; - if (ioctl(ethtool_fd, SIOCETHTOOL, ifr) < 0) + if (ioctl(ethtool_fd, SIOCETHTOOL, &ifr) < 0) return -errno; *ret = TAKE_PTR(strings); + return 0; +} + +static int get_features(int ethtool_fd, const char *ifname, uint32_t n_features, struct ethtool_gfeatures **ret) { + _cleanup_free_ struct ethtool_gfeatures *gfeatures = NULL; + struct ifreq ifr; + + assert(ethtool_fd >= 0); + assert(ifname); + assert(ret); + assert(n_features > 0); + + gfeatures = malloc0(offsetof(struct ethtool_gfeatures, features) + + DIV_ROUND_UP(n_features, 32U) * sizeof(gfeatures->features[0])); + if (!gfeatures) + return -ENOMEM; + + gfeatures->cmd = ETHTOOL_GFEATURES; + gfeatures->size = DIV_ROUND_UP(n_features, 32U); + + ifr = (struct ifreq) { + .ifr_data = (void*) gfeatures, + }; + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); + + if (ioctl(ethtool_fd, SIOCETHTOOL, &ifr) < 0) + return -errno; + *ret = TAKE_PTR(gfeatures); return 0; } static int set_features_bit( const struct ethtool_gstrings *strings, + const struct ethtool_gfeatures *gfeatures, + struct ethtool_sfeatures *sfeatures, const char *feature, - bool flag, - struct ethtool_sfeatures *sfeatures) { + int flag) { + bool found = false; + int r = -ENODATA; assert(strings); - assert(feature); + assert(gfeatures); assert(sfeatures); + assert(feature); + + if (flag < 0) + return 0; + + for (uint32_t i = 0; i < strings->len; i++) { + uint32_t block, mask; - for (size_t i = 0; i < strings->len; i++) - if (streq((char *) &strings->data[i * ETH_GSTRING_LEN], feature) || - (endswith(feature, "-") && startswith((char *) &strings->data[i * ETH_GSTRING_LEN], feature))) { - size_t block, bit; + if (!strneq((const char*) &strings->data[i * ETH_GSTRING_LEN], feature, ETH_GSTRING_LEN) && + !(endswith(feature, "-") && startswith((const char*) &strings->data[i * ETH_GSTRING_LEN], feature))) + continue; - block = i / 32; - bit = i % 32; + block = i / 32; + mask = UINT32_C(1) << (i % 32); - sfeatures->features[block].valid |= 1 << bit; - SET_FLAG(sfeatures->features[block].requested, 1 << bit, flag); - found = true; + if (!FLAGS_SET(gfeatures->features[block].available, mask) || + FLAGS_SET(gfeatures->features[block].never_changed, mask)) { + r = -EOPNOTSUPP; + continue; } - return found ? 0 : -ENODATA; + sfeatures->features[block].valid |= mask; + SET_FLAG(sfeatures->features[block].requested, mask, flag); + + found = true; + } + + return found ? 0 : r; } int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features[static _NET_DEV_FEAT_MAX]) { _cleanup_free_ struct ethtool_gstrings *strings = NULL; - struct ethtool_sfeatures *sfeatures; - struct ifreq ifr = {}; + _cleanup_free_ struct ethtool_gfeatures *gfeatures = NULL; + _cleanup_free_ struct ethtool_sfeatures *sfeatures = NULL; + struct ifreq ifr; bool have = false; int r; @@ -528,26 +576,32 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features if (r < 0) return r; - strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); + r = get_stringset(*ethtool_fd, ifname, ETH_SS_FEATURES, &strings); + if (r < 0) + return log_debug_errno(r, "ethtool: could not get ethtool feature strings: %m"); - r = get_stringset(*ethtool_fd, &ifr, ETH_SS_FEATURES, &strings); + r = get_features(*ethtool_fd, ifname, strings->len, &gfeatures); if (r < 0) - return log_debug_errno(r, "ethtool: could not get ethtool features for %s", ifname); + return log_debug_errno(r, "ethtool: could not get ethtool features for %s: %m", ifname); + + sfeatures = malloc0(offsetof(struct ethtool_sfeatures, features) + + DIV_ROUND_UP(strings->len, 32U) * sizeof(sfeatures->features[0])); + if (!sfeatures) + return log_oom_debug(); - sfeatures = alloca0(sizeof(struct ethtool_sfeatures) + DIV_ROUND_UP(strings->len, 32U) * sizeof(sfeatures->features[0])); sfeatures->cmd = ETHTOOL_SFEATURES; sfeatures->size = DIV_ROUND_UP(strings->len, 32U); - for (size_t i = 0; i < _NET_DEV_FEAT_MAX; i++) - if (features[i] >= 0) { - r = set_features_bit(strings, netdev_feature_table[i], features[i], sfeatures); - if (r < 0) { - log_debug_errno(r, "ethtool: could not find feature, ignoring: %s", netdev_feature_table[i]); - continue; - } - } + for (size_t i = 0; i < _NET_DEV_FEAT_MAX; i++) { + r = set_features_bit(strings, gfeatures, sfeatures, netdev_feature_table[i], features[i]); + if (r < 0) + log_debug_errno(r, "ethtool: could not set feature %s for %s, ignoring: %m", netdev_feature_table[i], ifname); + } - ifr.ifr_data = (void *) sfeatures; + ifr = (struct ifreq) { + .ifr_data = (void*) sfeatures, + }; + strscpy(ifr.ifr_name, sizeof(ifr.ifr_name), ifname); if (ioctl(*ethtool_fd, SIOCETHTOOL, &ifr) < 0) return log_debug_errno(errno, "ethtool: could not set ethtool features for %s", ifname); From 7a4f203547c62cdc7611f38d97058b530570048f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 15 Sep 2021 01:48:59 +0900 Subject: [PATCH 4/5] ethtool-util: apply tx-checksum-* features at last NET_DEV_FEAT_TX matches multiple features. In the next commit, all features whose strings start with "tx-checksum-" will be added. To make them take precedence over NET_DEV_FEAT_TX, it will be applied only when each explicit feature is not applied. --- src/shared/ethtool-util.c | 55 ++++++++++++++++++++++++++++++++++++--- src/shared/ethtool-util.h | 4 ++- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index 59b1bd86f085..e95ce1a20917 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -71,13 +71,14 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse P static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = { [NET_DEV_FEAT_RX] = "rx-checksum", - [NET_DEV_FEAT_TX] = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */ [NET_DEV_FEAT_GSO] = "tx-generic-segmentation", [NET_DEV_FEAT_GRO] = "rx-gro", [NET_DEV_FEAT_GRO_HW] = "rx-gro-hw", [NET_DEV_FEAT_LRO] = "rx-lro", [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation", [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation", + + [NET_DEV_FEAT_TX] = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */ }; static const char* const ethtool_link_mode_bit_table[] = { @@ -515,6 +516,43 @@ static int set_features_bit( const char *feature, int flag) { + assert(strings); + assert(gfeatures); + assert(sfeatures); + assert(feature); + + if (flag < 0) + return 0; + + for (uint32_t i = 0; i < strings->len; i++) { + uint32_t block, mask; + + if (!strneq((const char*) &strings->data[i * ETH_GSTRING_LEN], feature, ETH_GSTRING_LEN)) + continue; + + block = i / 32; + mask = UINT32_C(1) << (i % 32); + + if (!FLAGS_SET(gfeatures->features[block].available, mask) || + FLAGS_SET(gfeatures->features[block].never_changed, mask)) + return -EOPNOTSUPP; + + sfeatures->features[block].valid |= mask; + SET_FLAG(sfeatures->features[block].requested, mask, flag); + + return 0; + } + + return -ENODATA; +} + +static int set_features_multiple_bit( + const struct ethtool_gstrings *strings, + const struct ethtool_gfeatures *gfeatures, + struct ethtool_sfeatures *sfeatures, + const char *feature, + int flag) { + bool found = false; int r = -ENODATA; @@ -529,8 +567,7 @@ static int set_features_bit( for (uint32_t i = 0; i < strings->len; i++) { uint32_t block, mask; - if (!strneq((const char*) &strings->data[i * ETH_GSTRING_LEN], feature, ETH_GSTRING_LEN) && - !(endswith(feature, "-") && startswith((const char*) &strings->data[i * ETH_GSTRING_LEN], feature))) + if (!startswith((const char*) &strings->data[i * ETH_GSTRING_LEN], feature)) continue; block = i / 32; @@ -542,6 +579,10 @@ static int set_features_bit( continue; } + /* The flags is explicitly set by set_features_bit() */ + if (FLAGS_SET(sfeatures->features[block].valid, mask)) + continue; + sfeatures->features[block].valid |= mask; SET_FLAG(sfeatures->features[block].requested, mask, flag); @@ -592,12 +633,18 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int features sfeatures->cmd = ETHTOOL_SFEATURES; sfeatures->size = DIV_ROUND_UP(strings->len, 32U); - for (size_t i = 0; i < _NET_DEV_FEAT_MAX; i++) { + for (size_t i = 0; i < _NET_DEV_FEAT_SIMPLE_MAX; i++) { r = set_features_bit(strings, gfeatures, sfeatures, netdev_feature_table[i], features[i]); if (r < 0) log_debug_errno(r, "ethtool: could not set feature %s for %s, ignoring: %m", netdev_feature_table[i], ifname); } + for (size_t i = _NET_DEV_FEAT_SIMPLE_MAX; i < _NET_DEV_FEAT_MAX; i++) { + r = set_features_multiple_bit(strings, gfeatures, sfeatures, netdev_feature_table[i], features[i]); + if (r < 0) + log_debug_errno(r, "ethtool: could not set feature %s for %s, ignoring: %m", netdev_feature_table[i], ifname); + } + ifr = (struct ifreq) { .ifr_data = (void*) sfeatures, }; diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h index 6e180995055b..3f2252563304 100644 --- a/src/shared/ethtool-util.h +++ b/src/shared/ethtool-util.h @@ -20,13 +20,15 @@ typedef enum Duplex { typedef enum NetDevFeature { NET_DEV_FEAT_RX, - NET_DEV_FEAT_TX, NET_DEV_FEAT_GSO, NET_DEV_FEAT_GRO, NET_DEV_FEAT_GRO_HW, NET_DEV_FEAT_LRO, NET_DEV_FEAT_TSO, NET_DEV_FEAT_TSO6, + _NET_DEV_FEAT_SIMPLE_MAX, + + NET_DEV_FEAT_TX = _NET_DEV_FEAT_SIMPLE_MAX, _NET_DEV_FEAT_MAX, _NET_DEV_FEAT_INVALID = -EINVAL, } NetDevFeature; From 77bf5c31de1d01edd49ac6aa25cdbe7734a11a25 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 14 Sep 2021 22:12:42 +0900 Subject: [PATCH 5/5] ethtool-util: add more network device features Then, we can easily add new settings to configure features in .link file. --- src/shared/ethtool-util.c | 73 ++++++++++++++++++++++++---- src/shared/ethtool-util.h | 59 +++++++++++++++++++++- src/udev/net/link-config-gperf.gperf | 4 +- 3 files changed, 123 insertions(+), 13 deletions(-) diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index e95ce1a20917..00060abff40f 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -70,15 +70,70 @@ DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort); DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting"); static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = { - [NET_DEV_FEAT_RX] = "rx-checksum", - [NET_DEV_FEAT_GSO] = "tx-generic-segmentation", - [NET_DEV_FEAT_GRO] = "rx-gro", - [NET_DEV_FEAT_GRO_HW] = "rx-gro-hw", - [NET_DEV_FEAT_LRO] = "rx-lro", - [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation", - [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation", - - [NET_DEV_FEAT_TX] = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */ + [NET_DEV_FEAT_SG] = "tx-scatter-gather", + [NET_DEV_FEAT_IP_CSUM] = "tx-checksum-ipv4", + [NET_DEV_FEAT_HW_CSUM] = "tx-checksum-ip-generic", + [NET_DEV_FEAT_IPV6_CSUM] = "tx-checksum-ipv6", + [NET_DEV_FEAT_HIGHDMA] = "highdma", + [NET_DEV_FEAT_FRAGLIST] = "tx-scatter-gather-fraglist", + [NET_DEV_FEAT_HW_VLAN_CTAG_TX] = "tx-vlan-hw-insert", + [NET_DEV_FEAT_HW_VLAN_CTAG_RX] = "rx-vlan-hw-parse", + [NET_DEV_FEAT_HW_VLAN_CTAG_FILTER] = "rx-vlan-filter", + [NET_DEV_FEAT_HW_VLAN_STAG_TX] = "tx-vlan-stag-hw-insert", + [NET_DEV_FEAT_HW_VLAN_STAG_RX] = "rx-vlan-stag-hw-parse", + [NET_DEV_FEAT_HW_VLAN_STAG_FILTER] = "rx-vlan-stag-filter", + [NET_DEV_FEAT_VLAN_CHALLENGED] = "vlan-challenged", + [NET_DEV_FEAT_GSO] = "tx-generic-segmentation", + [NET_DEV_FEAT_LLTX] = "tx-lockless", + [NET_DEV_FEAT_NETNS_LOCAL] = "netns-local", + [NET_DEV_FEAT_GRO] = "rx-gro", + [NET_DEV_FEAT_GRO_HW] = "rx-gro-hw", + [NET_DEV_FEAT_LRO] = "rx-lro", + [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation", + [NET_DEV_FEAT_GSO_ROBUST] = "tx-gso-robust", + [NET_DEV_FEAT_TSO_ECN] = "tx-tcp-ecn-segmentation", + [NET_DEV_FEAT_TSO_MANGLEID] = "tx-tcp-mangleid-segmentation", + [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation", + [NET_DEV_FEAT_FSO] = "tx-fcoe-segmentation", + [NET_DEV_FEAT_GSO_GRE] = "tx-gre-segmentation", + [NET_DEV_FEAT_GSO_GRE_CSUM] = "tx-gre-csum-segmentation", + [NET_DEV_FEAT_GSO_IPXIP4] = "tx-ipxip4-segmentation", + [NET_DEV_FEAT_GSO_IPXIP6] = "tx-ipxip6-segmentation", + [NET_DEV_FEAT_GSO_UDP_TUNNEL] = "tx-udp_tnl-segmentation", + [NET_DEV_FEAT_GSO_UDP_TUNNEL_CSUM] = "tx-udp_tnl-csum-segmentation", + [NET_DEV_FEAT_GSO_PARTIAL] = "tx-gso-partial", + [NET_DEV_FEAT_GSO_TUNNEL_REMCSUM] = "tx-tunnel-remcsum-segmentation", + [NET_DEV_FEAT_GSO_SCTP] = "tx-sctp-segmentation", + [NET_DEV_FEAT_GSO_ESP] = "tx-esp-segmentation", + [NET_DEV_FEAT_GSO_UDP_L4] = "tx-udp-segmentation", + [NET_DEV_FEAT_GSO_FRAGLIST] = "tx-gso-list", + [NET_DEV_FEAT_FCOE_CRC] = "tx-checksum-fcoe-crc", + [NET_DEV_FEAT_SCTP_CRC] = "tx-checksum-sctp", + [NET_DEV_FEAT_FCOE_MTU] = "fcoe-mtu", + [NET_DEV_FEAT_NTUPLE] = "rx-ntuple-filter", + [NET_DEV_FEAT_RXHASH] = "rx-hashing", + [NET_DEV_FEAT_RXCSUM] = "rx-checksum", + [NET_DEV_FEAT_NOCACHE_COPY] = "tx-nocache-copy", + [NET_DEV_FEAT_LOOPBACK] = "loopback", + [NET_DEV_FEAT_RXFCS] = "rx-fcs", + [NET_DEV_FEAT_RXALL] = "rx-all", + [NET_DEV_FEAT_HW_L2FW_DOFFLOAD] = "l2-fwd-offload", + [NET_DEV_FEAT_HW_TC] = "hw-tc-offload", + [NET_DEV_FEAT_HW_ESP] = "esp-hw-offload", + [NET_DEV_FEAT_HW_ESP_TX_CSUM] = "esp-tx-csum-hw-offload", + [NET_DEV_FEAT_RX_UDP_TUNNEL_PORT] = "rx-udp_tunnel-port-offload", + [NET_DEV_FEAT_HW_TLS_RECORD] = "tls-hw-record", + [NET_DEV_FEAT_HW_TLS_TX] = "tls-hw-tx-offload", + [NET_DEV_FEAT_HW_TLS_RX] = "tls-hw-rx-offload", + [NET_DEV_FEAT_GRO_FRAGLIST] = "rx-gro-list", + [NET_DEV_FEAT_HW_MACSEC] = "macsec-hw-offload", + [NET_DEV_FEAT_GRO_UDP_FWD] = "rx-udp-gro-forwarding", + [NET_DEV_FEAT_HW_HSR_TAG_INS] = "hsr-tag-ins-offload", + [NET_DEV_FEAT_HW_HSR_TAG_RM] = "hsr-tag-rm-offload", + [NET_DEV_FEAT_HW_HSR_FWD] = "hsr-fwd-offload", + [NET_DEV_FEAT_HW_HSR_DUP] = "hsr-dup-offload", + + [NET_DEV_FEAT_TXCSUM] = "tx-checksum-", /* The suffix "-" means any feature beginning with "tx-checksum-" */ }; static const char* const ethtool_link_mode_bit_table[] = { diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h index 3f2252563304..cc0655893175 100644 --- a/src/shared/ethtool-util.h +++ b/src/shared/ethtool-util.h @@ -19,16 +19,71 @@ typedef enum Duplex { } Duplex; typedef enum NetDevFeature { - NET_DEV_FEAT_RX, + NET_DEV_FEAT_SG, + NET_DEV_FEAT_IP_CSUM, + NET_DEV_FEAT_HW_CSUM, + NET_DEV_FEAT_IPV6_CSUM, + NET_DEV_FEAT_HIGHDMA, + NET_DEV_FEAT_FRAGLIST, + NET_DEV_FEAT_HW_VLAN_CTAG_TX, + NET_DEV_FEAT_HW_VLAN_CTAG_RX, + NET_DEV_FEAT_HW_VLAN_CTAG_FILTER, + NET_DEV_FEAT_HW_VLAN_STAG_TX, + NET_DEV_FEAT_HW_VLAN_STAG_RX, + NET_DEV_FEAT_HW_VLAN_STAG_FILTER, + NET_DEV_FEAT_VLAN_CHALLENGED, NET_DEV_FEAT_GSO, + NET_DEV_FEAT_LLTX, + NET_DEV_FEAT_NETNS_LOCAL, NET_DEV_FEAT_GRO, NET_DEV_FEAT_GRO_HW, NET_DEV_FEAT_LRO, NET_DEV_FEAT_TSO, + NET_DEV_FEAT_GSO_ROBUST, + NET_DEV_FEAT_TSO_ECN, + NET_DEV_FEAT_TSO_MANGLEID, NET_DEV_FEAT_TSO6, + NET_DEV_FEAT_FSO, + NET_DEV_FEAT_GSO_GRE, + NET_DEV_FEAT_GSO_GRE_CSUM, + NET_DEV_FEAT_GSO_IPXIP4, + NET_DEV_FEAT_GSO_IPXIP6, + NET_DEV_FEAT_GSO_UDP_TUNNEL, + NET_DEV_FEAT_GSO_UDP_TUNNEL_CSUM, + NET_DEV_FEAT_GSO_PARTIAL, + NET_DEV_FEAT_GSO_TUNNEL_REMCSUM, + NET_DEV_FEAT_GSO_SCTP, + NET_DEV_FEAT_GSO_ESP, + NET_DEV_FEAT_GSO_UDP_L4, + NET_DEV_FEAT_GSO_FRAGLIST, + NET_DEV_FEAT_FCOE_CRC, + NET_DEV_FEAT_SCTP_CRC, + NET_DEV_FEAT_FCOE_MTU, + NET_DEV_FEAT_NTUPLE, + NET_DEV_FEAT_RXHASH, + NET_DEV_FEAT_RXCSUM, + NET_DEV_FEAT_NOCACHE_COPY, + NET_DEV_FEAT_LOOPBACK, + NET_DEV_FEAT_RXFCS, + NET_DEV_FEAT_RXALL, + NET_DEV_FEAT_HW_L2FW_DOFFLOAD, + NET_DEV_FEAT_HW_TC, + NET_DEV_FEAT_HW_ESP, + NET_DEV_FEAT_HW_ESP_TX_CSUM, + NET_DEV_FEAT_RX_UDP_TUNNEL_PORT, + NET_DEV_FEAT_HW_TLS_RECORD, + NET_DEV_FEAT_HW_TLS_TX, + NET_DEV_FEAT_HW_TLS_RX, + NET_DEV_FEAT_GRO_FRAGLIST, + NET_DEV_FEAT_HW_MACSEC, + NET_DEV_FEAT_GRO_UDP_FWD, + NET_DEV_FEAT_HW_HSR_TAG_INS, + NET_DEV_FEAT_HW_HSR_TAG_RM, + NET_DEV_FEAT_HW_HSR_FWD, + NET_DEV_FEAT_HW_HSR_DUP, _NET_DEV_FEAT_SIMPLE_MAX, - NET_DEV_FEAT_TX = _NET_DEV_FEAT_SIMPLE_MAX, + NET_DEV_FEAT_TXCSUM = _NET_DEV_FEAT_SIMPLE_MAX, _NET_DEV_FEAT_MAX, _NET_DEV_FEAT_INVALID = -EINVAL, } NetDevFeature; diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 44b46cb17c0b..e3cdaaee0509 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -50,8 +50,8 @@ Link.Duplex, config_parse_duplex, Link.AutoNegotiation, config_parse_tristate, 0, offsetof(LinkConfig, autonegotiation) Link.WakeOnLan, config_parse_wol, 0, offsetof(LinkConfig, wol) Link.Port, config_parse_port, 0, offsetof(LinkConfig, port) -Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_RX]) -Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TX]) +Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_RXCSUM]) +Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TXCSUM]) Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_GSO]) Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO]) Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TSO6])