ethtool: Centralise validation of ETHTOOL_{G, S}RXFHINDIR parameters

Add a new ethtool operation (get_rxfh_indir_size) to get the
indirectional table size.  Use this to validate the user buffer size
before calling get_rxfh_indir or set_rxfh_indir.  Use get_rxnfc to get
the number of RX rings, and validate the contents of the new
indirection table before calling set_rxfh_indir.  Remove this
validation from drivers.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Acked-by: Dimitris Michailidis <dm@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Ben Hutchings
2011-12-15 13:55:01 +00:00
committed by David S. Miller
parent 14596f7006
commit 7850f63f16
6 changed files with 118 additions and 112 deletions

View File

@@ -2302,18 +2302,20 @@ static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
}
}
static int bnx2x_get_rxfh_indir(struct net_device *dev,
struct ethtool_rxfh_indir *indir)
static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
return (bp->multi_mode == ETH_RSS_MODE_DISABLED ?
0 : T_ETH_INDIRECTION_TABLE_SIZE);
}
static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir)
{
struct bnx2x *bp = netdev_priv(dev);
size_t copy_size =
min_t(size_t, indir->size, T_ETH_INDIRECTION_TABLE_SIZE);
u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
size_t i;
if (bp->multi_mode == ETH_RSS_MODE_DISABLED)
return -EOPNOTSUPP;
/* Get the current configuration of the RSS indirection table */
bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table);
@@ -2326,33 +2328,19 @@ static int bnx2x_get_rxfh_indir(struct net_device *dev,
* align the returned table to the Client ID of the leading RSS
* queue.
*/
for (i = 0; i < copy_size; i++)
indir->ring_index[i] = ind_table[i] - bp->fp->cl_id;
indir->size = T_ETH_INDIRECTION_TABLE_SIZE;
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++)
indir[i] = ind_table[i] - bp->fp->cl_id;
return 0;
}
static int bnx2x_set_rxfh_indir(struct net_device *dev,
const struct ethtool_rxfh_indir *indir)
static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir)
{
struct bnx2x *bp = netdev_priv(dev);
size_t i;
u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
u32 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp);
if (bp->multi_mode == ETH_RSS_MODE_DISABLED)
return -EOPNOTSUPP;
/* validate the size */
if (indir->size != T_ETH_INDIRECTION_TABLE_SIZE)
return -EINVAL;
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
/* validate the indices */
if (indir->ring_index[i] >= num_eth_queues)
return -EINVAL;
/*
* The same as in bnx2x_get_rxfh_indir: we can't use a memcpy()
* as an internal storage of an indirection table is a u8 array
@@ -2362,7 +2350,7 @@ static int bnx2x_set_rxfh_indir(struct net_device *dev,
* align the received table to the Client ID of the leading RSS
* queue
*/
ind_table[i] = indir->ring_index[i] + bp->fp->cl_id;
ind_table[i] = indir[i] + bp->fp->cl_id;
}
return bnx2x_config_rss_pf(bp, ind_table, false);
@@ -2395,6 +2383,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
.set_phys_id = bnx2x_set_phys_id,
.get_ethtool_stats = bnx2x_get_ethtool_stats,
.get_rxnfc = bnx2x_get_rxnfc,
.get_rxfh_indir_size = bnx2x_get_rxfh_indir_size,
.get_rxfh_indir = bnx2x_get_rxfh_indir,
.set_rxfh_indir = bnx2x_set_rxfh_indir,
};

View File

@@ -1871,30 +1871,30 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
return err;
}
static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p)
static u32 get_rss_table_size(struct net_device *dev)
{
const struct port_info *pi = netdev_priv(dev);
unsigned int n = min_t(unsigned int, p->size, pi->rss_size);
p->size = pi->rss_size;
return pi->rss_size;
}
static int get_rss_table(struct net_device *dev, u32 *p)
{
const struct port_info *pi = netdev_priv(dev);
unsigned int n = pi->rss_size;
while (n--)
p->ring_index[n] = pi->rss[n];
p[n] = pi->rss[n];
return 0;
}
static int set_rss_table(struct net_device *dev,
const struct ethtool_rxfh_indir *p)
static int set_rss_table(struct net_device *dev, const u32 *p)
{
unsigned int i;
struct port_info *pi = netdev_priv(dev);
if (p->size != pi->rss_size)
return -EINVAL;
for (i = 0; i < p->size; i++)
if (p->ring_index[i] >= pi->nqsets)
return -EINVAL;
for (i = 0; i < p->size; i++)
pi->rss[i] = p->ring_index[i];
for (i = 0; i < pi->rss_size; i++)
pi->rss[i] = p[i];
if (pi->adapter->flags & FULL_INIT_DONE)
return write_rss(pi, pi->rss);
return 0;
@@ -1989,6 +1989,7 @@ static struct ethtool_ops cxgb_ethtool_ops = {
.get_wol = get_wol,
.set_wol = set_wol,
.get_rxnfc = get_rxnfc,
.get_rxfh_indir_size = get_rss_table_size,
.get_rxfh_indir = get_rss_table,
.set_rxfh_indir = set_rss_table,
.flash_device = set_flash,

View File

@@ -956,40 +956,28 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
return rc < 0 ? rc : 0;
}
static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
struct ethtool_rxfh_indir *indir)
static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
size_t copy_size =
min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table));
if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
return -EOPNOTSUPP;
return (efx_nic_rev(efx) < EFX_REV_FALCON_B0 ?
0 : ARRAY_SIZE(efx->rx_indir_table));
}
indir->size = ARRAY_SIZE(efx->rx_indir_table);
memcpy(indir->ring_index, efx->rx_indir_table,
copy_size * sizeof(indir->ring_index[0]));
static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir)
{
struct efx_nic *efx = netdev_priv(net_dev);
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
return 0;
}
static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
const struct ethtool_rxfh_indir *indir)
const u32 *indir)
{
struct efx_nic *efx = netdev_priv(net_dev);
size_t i;
if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
return -EOPNOTSUPP;
/* Validate size and indices */
if (indir->size != ARRAY_SIZE(efx->rx_indir_table))
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
if (indir->ring_index[i] >= efx->n_rx_channels)
return -EINVAL;
memcpy(efx->rx_indir_table, indir->ring_index,
sizeof(efx->rx_indir_table));
memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table));
efx_nic_push_rx_indir_table(efx);
return 0;
}
@@ -1020,6 +1008,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.reset = efx_ethtool_reset,
.get_rxnfc = efx_ethtool_get_rxnfc,
.set_rx_ntuple = efx_ethtool_set_rx_ntuple,
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_indir = efx_ethtool_get_rxfh_indir,
.set_rxfh_indir = efx_ethtool_set_rxfh_indir,
};