Commit 7195f0ef authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

ethtool: fix setting key and resetting indir at once

The indirection table and the key follow struct ethtool_rxfh
in user memory.

To reset the indirection table user space calls SET_RXFH with
table of size 0 (OTOH to say "no change" it should use -1 / ~0).
The logic for calculating the offset where they key sits is
incorrect in this case, as kernel would still offset by the full
table length, while for the reset there is no indir table and
key is immediately after the struct.

  $ ethtool -X eth0 default hkey 01:02:03...
  $ ethtool -x eth0
  [...]
  RSS hash key:
00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
  [...]

Fixes: 3de0b592 ("ethtool: Support for configurable RSS hash key")
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9dbad383
...@@ -1331,13 +1331,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1331,13 +1331,13 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]);
const struct ethtool_ops *ops = dev->ethtool_ops; const struct ethtool_ops *ops = dev->ethtool_ops;
u32 dev_indir_size = 0, dev_key_size = 0, i; u32 dev_indir_size = 0, dev_key_size = 0, i;
u32 user_indir_len = 0, indir_bytes = 0;
struct ethtool_rxfh_param rxfh_dev = {}; struct ethtool_rxfh_param rxfh_dev = {};
struct ethtool_rxfh_context *ctx = NULL; struct ethtool_rxfh_context *ctx = NULL;
struct netlink_ext_ack *extack = NULL; struct netlink_ext_ack *extack = NULL;
struct ethtool_rxnfc rx_rings; struct ethtool_rxnfc rx_rings;
struct ethtool_rxfh rxfh; struct ethtool_rxfh rxfh;
bool locked = false; /* dev->ethtool->rss_lock taken */ bool locked = false; /* dev->ethtool->rss_lock taken */
u32 indir_bytes = 0;
bool create = false; bool create = false;
u8 *rss_config; u8 *rss_config;
int ret; int ret;
...@@ -1400,6 +1400,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1400,6 +1400,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
*/ */
if (rxfh.indir_size && if (rxfh.indir_size &&
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) { rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) {
user_indir_len = indir_bytes;
rxfh_dev.indir = (u32 *)rss_config; rxfh_dev.indir = (u32 *)rss_config;
rxfh_dev.indir_size = dev_indir_size; rxfh_dev.indir_size = dev_indir_size;
ret = ethtool_copy_validate_indir(rxfh_dev.indir, ret = ethtool_copy_validate_indir(rxfh_dev.indir,
...@@ -1426,7 +1427,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1426,7 +1427,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
rxfh_dev.key_size = dev_key_size; rxfh_dev.key_size = dev_key_size;
rxfh_dev.key = rss_config + indir_bytes; rxfh_dev.key = rss_config + indir_bytes;
if (copy_from_user(rxfh_dev.key, if (copy_from_user(rxfh_dev.key,
useraddr + rss_cfg_offset + indir_bytes, useraddr + rss_cfg_offset + user_indir_len,
rxfh.key_size)) { rxfh.key_size)) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment