Skip to content

Commit 840110a

Browse files
Maxim Mikityanskiydavem330
authored andcommitted
ethtool: Fix preserving of wanted feature bits in netlink interface
Currently, ethtool-netlink calculates new wanted bits as: (req_wanted & req_mask) | (old_active & ~req_mask) It completely discards the old wanted bits, so they are forgotten with the next ethtool command. Sample steps to reproduce: 1. ethtool -k eth0 tx-tcp-segmentation: on # TSO is on from the beginning 2. ethtool -K eth0 tx off tx-tcp-segmentation: off [not requested] 3. ethtool -k eth0 tx-tcp-segmentation: off [requested on] 4. ethtool -K eth0 rx off # Some change unrelated to TSO 5. ethtool -k eth0 tx-tcp-segmentation: off # "Wanted on" is forgotten This commit fixes it by changing the formula to: (req_wanted & req_mask) | (old_wanted & ~req_mask), where old_active was replaced by old_wanted to account for the wanted bits. The shortcut condition for the case where nothing was changed now compares wanted bitmasks, instead of wanted to active. Fixes: 0980bfc ("ethtool: set netdev features with FEATURES_SET request") Signed-off-by: Maxim Mikityanskiy <[email protected]> Reviewed-by: Michal Kubecek <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4ef1a7c commit 840110a

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

net/ethtool/features.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,9 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
224224
DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT);
225225
DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT);
226226
DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT);
227+
DECLARE_BITMAP(old_wanted, NETDEV_FEATURE_COUNT);
227228
DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT);
229+
DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT);
228230
DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT);
229231
DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT);
230232
struct nlattr *tb[ETHTOOL_A_FEATURES_MAX + 1];
@@ -250,6 +252,7 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
250252

251253
rtnl_lock();
252254
ethnl_features_to_bitmap(old_active, dev->features);
255+
ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
253256
ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
254257
tb[ETHTOOL_A_FEATURES_WANTED],
255258
netdev_features_strings, info->extack);
@@ -261,11 +264,11 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
261264
goto out_rtnl;
262265
}
263266

264-
/* set req_wanted bits not in req_mask from old_active */
267+
/* set req_wanted bits not in req_mask from old_wanted */
265268
bitmap_and(req_wanted, req_wanted, req_mask, NETDEV_FEATURE_COUNT);
266-
bitmap_andnot(new_active, old_active, req_mask, NETDEV_FEATURE_COUNT);
267-
bitmap_or(req_wanted, new_active, req_wanted, NETDEV_FEATURE_COUNT);
268-
if (bitmap_equal(req_wanted, old_active, NETDEV_FEATURE_COUNT)) {
269+
bitmap_andnot(new_wanted, old_wanted, req_mask, NETDEV_FEATURE_COUNT);
270+
bitmap_or(req_wanted, new_wanted, req_wanted, NETDEV_FEATURE_COUNT);
271+
if (bitmap_equal(req_wanted, old_wanted, NETDEV_FEATURE_COUNT)) {
269272
ret = 0;
270273
goto out_rtnl;
271274
}

0 commit comments

Comments
 (0)