From 6d9a72f3b9b4d00ec80051503e5e3d4d7cd46c05 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
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 <watanabe.yu+github@gmail.com>
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 <watanabe.yu+github@gmail.com>
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 <watanabe.yu+github@gmail.com>
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 <watanabe.yu+github@gmail.com>
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])