Add RSS indirection table, hash key, and non-default RSS context support to netdevsim. The create/modify/remove context callbacks are no-ops; the core manages context state in its xarray. The table size is dynamic: roundup_pow_of_two(channels) * 16, capped at NSIM_RSS_INDIR_MAX (128). This mimics drivers like bnxt where the table size changes with the queue count. nsim_set_channels() uses the core resize helpers to fold/unfold tables on channel count changes, exercising the full resize path. Signed-off-by: Björn Töpel --- drivers/net/netdevsim/ethtool.c | 119 +++++++++++++++++++++++++++++- drivers/net/netdevsim/netdevsim.h | 4 + 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index 36a201533aae..c6d60b467054 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -2,6 +2,7 @@ // Copyright (c) 2020 Facebook #include +#include #include #include @@ -117,19 +118,121 @@ nsim_wake_queues(struct net_device *dev) rcu_read_unlock(); } +static u32 nsim_get_rx_ring_count(struct net_device *dev) +{ + struct netdevsim *ns = netdev_priv(dev); + + return ns->ethtool.channels; +} + +static u32 nsim_rss_indir_size(u32 channels) +{ + return min_t(u32, roundup_pow_of_two(channels) * 16, NSIM_RSS_INDIR_MAX); +} + +static u32 nsim_get_rxfh_indir_size(struct net_device *dev) +{ + struct netdevsim *ns = netdev_priv(dev); + + return nsim_rss_indir_size(ns->ethtool.channels); +} + +static u32 nsim_get_rxfh_key_size(struct net_device *dev) +{ + return NSIM_RSS_HKEY_SIZE; +} + +static int nsim_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh) +{ + u32 indir_size = nsim_get_rxfh_indir_size(dev); + struct netdevsim *ns = netdev_priv(dev); + + rxfh->hfunc = ETH_RSS_HASH_TOP; + + if (rxfh->indir) + memcpy(rxfh->indir, ns->ethtool.rss_indir_tbl, indir_size * sizeof(u32)); + if (rxfh->key) + memcpy(rxfh->key, ns->ethtool.rss_hkey, NSIM_RSS_HKEY_SIZE); + + return 0; +} + +static int nsim_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + u32 indir_size = nsim_get_rxfh_indir_size(dev); + struct netdevsim *ns = netdev_priv(dev); + + if (rxfh->indir) + memcpy(ns->ethtool.rss_indir_tbl, rxfh->indir, indir_size * sizeof(u32)); + if (rxfh->key) + memcpy(ns->ethtool.rss_hkey, rxfh->key, NSIM_RSS_HKEY_SIZE); + + return 0; +} + +static int nsim_create_rxfh_context(struct net_device *dev, struct ethtool_rxfh_context *ctx, + const struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static int nsim_modify_rxfh_context(struct net_device *dev, struct ethtool_rxfh_context *ctx, + const struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static int nsim_remove_rxfh_context(struct net_device *dev, struct ethtool_rxfh_context *ctx, + u32 rss_context, struct netlink_ext_ack *extack) +{ + return 0; +} + +static void nsim_rss_init(struct netdevsim *ns) +{ + u32 i, indir_size = nsim_rss_indir_size(ns->ethtool.channels); + + for (i = 0; i < indir_size; i++) + ns->ethtool.rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, ns->ethtool.channels); +} + static int nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch) { struct netdevsim *ns = netdev_priv(dev); + u32 old_indir_size, new_indir_size; int err; - err = netif_set_real_num_queues(dev, ch->combined_count, - ch->combined_count); + old_indir_size = nsim_get_rxfh_indir_size(dev); + new_indir_size = nsim_rss_indir_size(ch->combined_count); + + if (old_indir_size != new_indir_size) { + if (netif_is_rxfh_configured(dev) && + ethtool_rxfh_indir_can_resize(ns->ethtool.rss_indir_tbl, + old_indir_size, new_indir_size)) + return -EINVAL; + + err = ethtool_rxfh_contexts_resize_all(dev, new_indir_size); + if (err) + return err; + + if (netif_is_rxfh_configured(dev)) + ethtool_rxfh_indir_resize(ns->ethtool.rss_indir_tbl, + old_indir_size, new_indir_size); + } + + err = netif_set_real_num_queues(dev, ch->combined_count, ch->combined_count); if (err) return err; ns->ethtool.channels = ch->combined_count; + if (old_indir_size != new_indir_size && !netif_is_rxfh_configured(dev)) + nsim_rss_init(ns); + /* Only wake up queues if devices are linked */ if (rcu_access_pointer(ns->peer)) nsim_wake_queues(dev); @@ -209,6 +312,7 @@ static const struct ethtool_ops nsim_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_ALL_PARAMS, .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT | ETHTOOL_RING_USE_HDS_THRS, + .rxfh_indir_space = NSIM_RSS_INDIR_MAX, .get_pause_stats = nsim_get_pause_stats, .get_pauseparam = nsim_get_pauseparam, .set_pauseparam = nsim_set_pauseparam, @@ -218,10 +322,18 @@ static const struct ethtool_ops nsim_ethtool_ops = { .set_ringparam = nsim_set_ringparam, .get_channels = nsim_get_channels, .set_channels = nsim_set_channels, + .get_rx_ring_count = nsim_get_rx_ring_count, .get_fecparam = nsim_get_fecparam, .set_fecparam = nsim_set_fecparam, .get_fec_stats = nsim_get_fec_stats, .get_ts_info = nsim_get_ts_info, + .get_rxfh_indir_size = nsim_get_rxfh_indir_size, + .get_rxfh_key_size = nsim_get_rxfh_key_size, + .get_rxfh = nsim_get_rxfh, + .set_rxfh = nsim_set_rxfh, + .create_rxfh_context = nsim_create_rxfh_context, + .modify_rxfh_context = nsim_modify_rxfh_context, + .remove_rxfh_context = nsim_remove_rxfh_context, }; static void nsim_ethtool_ring_init(struct netdevsim *ns) @@ -250,6 +362,9 @@ void nsim_ethtool_init(struct netdevsim *ns) ns->ethtool.channels = ns->nsim_bus_dev->num_queues; + nsim_rss_init(ns); + get_random_bytes(ns->ethtool.rss_hkey, NSIM_RSS_HKEY_SIZE); + ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir); debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err); diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index f767fc8a7505..3c6dd9a98deb 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -82,6 +82,8 @@ struct nsim_ethtool_pauseparam { bool report_stats_tx; }; +#define NSIM_RSS_INDIR_MAX 128 +#define NSIM_RSS_HKEY_SIZE 40 struct nsim_ethtool { u32 get_err; u32 set_err; @@ -90,6 +92,8 @@ struct nsim_ethtool { struct ethtool_coalesce coalesce; struct ethtool_ringparam ring; struct ethtool_fecparam fec; + u32 rss_indir_tbl[NSIM_RSS_INDIR_MAX]; + u8 rss_hkey[NSIM_RSS_HKEY_SIZE]; }; struct nsim_rq { -- 2.53.0