Commit e96a79b1 authored by David S. Miller's avatar David S. Miller

Merge branch 'ethtool-rss-fixes' into main

Jakub Kicinski says;

====================
ethtool: more RSS fixes

More fixes for RSS setting. First two patches fix my own bugs
in bnxt conversion to the new API. The third patch fixes
what seems to be a 10 year old issue (present since the Linux
RSS API was created). Fourth patch fixes an issue with
the XArray state being out of sync. And then a small test.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9da49aa8 0d6ccfe6
...@@ -1863,8 +1863,14 @@ static void bnxt_modify_rss(struct bnxt *bp, struct ethtool_rxfh_context *ctx, ...@@ -1863,8 +1863,14 @@ static void bnxt_modify_rss(struct bnxt *bp, struct ethtool_rxfh_context *ctx,
} }
static int bnxt_rxfh_context_check(struct bnxt *bp, static int bnxt_rxfh_context_check(struct bnxt *bp,
const struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP) {
NL_SET_ERR_MSG_MOD(extack, "RSS hash function not supported");
return -EOPNOTSUPP;
}
if (!BNXT_SUPPORTS_MULTI_RSS_CTX(bp)) { if (!BNXT_SUPPORTS_MULTI_RSS_CTX(bp)) {
NL_SET_ERR_MSG_MOD(extack, "RSS contexts not supported"); NL_SET_ERR_MSG_MOD(extack, "RSS contexts not supported");
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1888,7 +1894,7 @@ static int bnxt_create_rxfh_context(struct net_device *dev, ...@@ -1888,7 +1894,7 @@ static int bnxt_create_rxfh_context(struct net_device *dev,
struct bnxt_vnic_info *vnic; struct bnxt_vnic_info *vnic;
int rc; int rc;
rc = bnxt_rxfh_context_check(bp, extack); rc = bnxt_rxfh_context_check(bp, rxfh, extack);
if (rc) if (rc)
return rc; return rc;
...@@ -1915,8 +1921,12 @@ static int bnxt_create_rxfh_context(struct net_device *dev, ...@@ -1915,8 +1921,12 @@ static int bnxt_create_rxfh_context(struct net_device *dev,
if (rc) if (rc)
goto out; goto out;
/* Populate defaults in the context */
bnxt_set_dflt_rss_indir_tbl(bp, ctx); bnxt_set_dflt_rss_indir_tbl(bp, ctx);
ctx->hfunc = ETH_RSS_HASH_TOP;
memcpy(vnic->rss_hash_key, bp->rss_hash_key, HW_HASH_KEY_SIZE); memcpy(vnic->rss_hash_key, bp->rss_hash_key, HW_HASH_KEY_SIZE);
memcpy(ethtool_rxfh_context_key(ctx),
bp->rss_hash_key, HW_HASH_KEY_SIZE);
rc = bnxt_hwrm_vnic_alloc(bp, vnic, 0, bp->rx_nr_rings); rc = bnxt_hwrm_vnic_alloc(bp, vnic, 0, bp->rx_nr_rings);
if (rc) { if (rc) {
...@@ -1953,7 +1963,7 @@ static int bnxt_modify_rxfh_context(struct net_device *dev, ...@@ -1953,7 +1963,7 @@ static int bnxt_modify_rxfh_context(struct net_device *dev,
struct bnxt_rss_ctx *rss_ctx; struct bnxt_rss_ctx *rss_ctx;
int rc; int rc;
rc = bnxt_rxfh_context_check(bp, extack); rc = bnxt_rxfh_context_check(bp, rxfh, extack);
if (rc) if (rc)
return rc; return rc;
......
...@@ -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;
...@@ -1382,10 +1382,9 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1382,10 +1382,9 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
rxfh.input_xfrm == RXH_XFRM_NO_CHANGE)) rxfh.input_xfrm == RXH_XFRM_NO_CHANGE))
return -EINVAL; return -EINVAL;
if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) indir_bytes = dev_indir_size * sizeof(rxfh_dev.indir[0]);
indir_bytes = dev_indir_size * sizeof(rxfh_dev.indir[0]);
rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER); rss_config = kzalloc(indir_bytes + dev_key_size, GFP_USER);
if (!rss_config) if (!rss_config)
return -ENOMEM; return -ENOMEM;
...@@ -1400,6 +1399,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1400,6 +1399,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 +1426,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1426,7 +1426,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;
...@@ -1474,16 +1474,21 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1474,16 +1474,21 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
rxfh_dev.input_xfrm = rxfh.input_xfrm; rxfh_dev.input_xfrm = rxfh.input_xfrm;
if (rxfh.rss_context && ops->create_rxfh_context) { if (rxfh.rss_context && ops->create_rxfh_context) {
if (create) if (create) {
ret = ops->create_rxfh_context(dev, ctx, &rxfh_dev, ret = ops->create_rxfh_context(dev, ctx, &rxfh_dev,
extack); extack);
else if (rxfh_dev.rss_delete) /* Make sure driver populates defaults */
WARN_ON_ONCE(!ret && !rxfh_dev.key &&
!memchr_inv(ethtool_rxfh_context_key(ctx),
0, ctx->key_size));
} else if (rxfh_dev.rss_delete) {
ret = ops->remove_rxfh_context(dev, ctx, ret = ops->remove_rxfh_context(dev, ctx,
rxfh.rss_context, rxfh.rss_context,
extack); extack);
else } else {
ret = ops->modify_rxfh_context(dev, ctx, &rxfh_dev, ret = ops->modify_rxfh_context(dev, ctx, &rxfh_dev,
extack); extack);
}
} else { } else {
ret = ops->set_rxfh(dev, &rxfh_dev, extack); ret = ops->set_rxfh(dev, &rxfh_dev, extack);
} }
...@@ -1522,6 +1527,22 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1522,6 +1527,22 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
kfree(ctx); kfree(ctx);
goto out; goto out;
} }
/* Fetch the defaults for the old API, in the new API drivers
* should write defaults into ctx themselves.
*/
rxfh_dev.indir = (u32 *)rss_config;
rxfh_dev.indir_size = dev_indir_size;
rxfh_dev.key = rss_config + indir_bytes;
rxfh_dev.key_size = dev_key_size;
ret = ops->get_rxfh(dev, &rxfh_dev);
if (WARN_ON(ret)) {
xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context);
kfree(ctx);
goto out;
}
} }
if (rxfh_dev.rss_delete) { if (rxfh_dev.rss_delete) {
WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx); WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx);
...@@ -1530,12 +1551,14 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1530,12 +1551,14 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
if (rxfh_dev.indir) { if (rxfh_dev.indir) {
for (i = 0; i < dev_indir_size; i++) for (i = 0; i < dev_indir_size; i++)
ethtool_rxfh_context_indir(ctx)[i] = rxfh_dev.indir[i]; ethtool_rxfh_context_indir(ctx)[i] = rxfh_dev.indir[i];
ctx->indir_configured = 1; ctx->indir_configured =
rxfh.indir_size &&
rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE;
} }
if (rxfh_dev.key) { if (rxfh_dev.key) {
memcpy(ethtool_rxfh_context_key(ctx), rxfh_dev.key, memcpy(ethtool_rxfh_context_key(ctx), rxfh_dev.key,
dev_key_size); dev_key_size);
ctx->key_configured = 1; ctx->key_configured = !!rxfh.key_size;
} }
if (rxfh_dev.hfunc != ETH_RSS_HASH_NO_CHANGE) if (rxfh_dev.hfunc != ETH_RSS_HASH_NO_CHANGE)
ctx->hfunc = rxfh_dev.hfunc; ctx->hfunc = rxfh_dev.hfunc;
......
...@@ -19,6 +19,15 @@ def _rss_key_rand(length): ...@@ -19,6 +19,15 @@ def _rss_key_rand(length):
return [random.randint(0, 255) for _ in range(length)] return [random.randint(0, 255) for _ in range(length)]
def _rss_key_check(cfg, data=None, context=0):
if data is None:
data = get_rss(cfg, context=context)
if 'rss-hash-key' not in data:
return
non_zero = [x for x in data['rss-hash-key'] if x != 0]
ksft_eq(bool(non_zero), True, comment=f"RSS key is all zero {data['rss-hash-key']}")
def get_rss(cfg, context=0): def get_rss(cfg, context=0):
return ethtool(f"-x {cfg.ifname} context {context}", json=True)[0] return ethtool(f"-x {cfg.ifname} context {context}", json=True)[0]
...@@ -90,8 +99,9 @@ def _send_traffic_check(cfg, port, name, params): ...@@ -90,8 +99,9 @@ def _send_traffic_check(cfg, port, name, params):
def test_rss_key_indir(cfg): def test_rss_key_indir(cfg):
"""Test basics like updating the main RSS key and indirection table.""" """Test basics like updating the main RSS key and indirection table."""
if len(_get_rx_cnts(cfg)) < 2: qcnt = len(_get_rx_cnts(cfg))
KsftSkipEx("Device has only one queue (or doesn't support queue stats)") if qcnt < 3:
KsftSkipEx("Device has fewer than 3 queues (or doesn't support queue stats)")
data = get_rss(cfg) data = get_rss(cfg)
want_keys = ['rss-hash-key', 'rss-hash-function', 'rss-indirection-table'] want_keys = ['rss-hash-key', 'rss-hash-function', 'rss-indirection-table']
...@@ -101,6 +111,7 @@ def test_rss_key_indir(cfg): ...@@ -101,6 +111,7 @@ def test_rss_key_indir(cfg):
if not data[k]: if not data[k]:
raise KsftFailEx(f"ethtool results empty for '{k}': {data[k]}") raise KsftFailEx(f"ethtool results empty for '{k}': {data[k]}")
_rss_key_check(cfg, data=data)
key_len = len(data['rss-hash-key']) key_len = len(data['rss-hash-key'])
# Set the key # Set the key
...@@ -110,9 +121,26 @@ def test_rss_key_indir(cfg): ...@@ -110,9 +121,26 @@ def test_rss_key_indir(cfg):
data = get_rss(cfg) data = get_rss(cfg)
ksft_eq(key, data['rss-hash-key']) ksft_eq(key, data['rss-hash-key'])
# Set the indirection table and the key together
key = _rss_key_rand(key_len)
ethtool(f"-X {cfg.ifname} equal 3 hkey " + _rss_key_str(key))
reset_indir = defer(ethtool, f"-X {cfg.ifname} default")
data = get_rss(cfg)
_rss_key_check(cfg, data=data)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(2, max(data['rss-indirection-table']))
# Reset indirection table and set the key
key = _rss_key_rand(key_len)
ethtool(f"-X {cfg.ifname} default hkey " + _rss_key_str(key))
data = get_rss(cfg)
_rss_key_check(cfg, data=data)
ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(qcnt - 1, max(data['rss-indirection-table']))
# Set the indirection table # Set the indirection table
ethtool(f"-X {cfg.ifname} equal 2") ethtool(f"-X {cfg.ifname} equal 2")
reset_indir = defer(ethtool, f"-X {cfg.ifname} default")
data = get_rss(cfg) data = get_rss(cfg)
ksft_eq(0, min(data['rss-indirection-table'])) ksft_eq(0, min(data['rss-indirection-table']))
ksft_eq(1, max(data['rss-indirection-table'])) ksft_eq(1, max(data['rss-indirection-table']))
...@@ -317,8 +345,11 @@ def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None): ...@@ -317,8 +345,11 @@ def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
ctx_cnt = i ctx_cnt = i
break break
_rss_key_check(cfg, context=ctx_id)
if not create_with_cfg: if not create_with_cfg:
ethtool(f"-X {cfg.ifname} context {ctx_id} {want_cfg}") ethtool(f"-X {cfg.ifname} context {ctx_id} {want_cfg}")
_rss_key_check(cfg, context=ctx_id)
# Sanity check the context we just created # Sanity check the context we just created
data = get_rss(cfg, ctx_id) data = get_rss(cfg, ctx_id)
......
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