Merge branch 'rss_key_fill'

Eric Dumazet says:

====================
net: provide common RSS key infrastructure

RSS (Receive Side Scaling) uses a 40 bytes key to provide hash for incoming
packets to select appropriate incoming queue on NIC.

Hash algo (Toeplitz) is also well known and documented by Microsoft
(search for "Verifying the RSS Hash Calculation")

Problem is that some drivers use a well known key.
It makes very easy for attackers to target one particular RX queue,
knowing that number of RX queues is a power of two, or at least some
small number.

Other drivers use a random value per port, making difficult
tuning on bonding setups.

Lets add a common infrastructure, so that host gets an unique
RSS key, and drivers do not have to worry about this.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-11-16 15:59:19 -05:00
commit 65622ed40e
20 changed files with 104 additions and 73 deletions

View File

@ -142,6 +142,28 @@ netdev_max_backlog
Maximum number of packets, queued on the INPUT side, when the interface Maximum number of packets, queued on the INPUT side, when the interface
receives packets faster than kernel can process them. receives packets faster than kernel can process them.
netdev_rss_key
--------------
RSS (Receive Side Scaling) enabled drivers use a 40 bytes host key that is
randomly generated.
Some user space might need to gather its content even if drivers do not
provide ethtool -x support yet.
myhost:~# cat /proc/sys/net/core/netdev_rss_key
84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8: ... (52 bytes total)
File contains nul bytes if no driver ever called netdev_rss_key_fill() function.
Note:
/proc/sys/net/core/netdev_rss_key contains 52 bytes of key,
but most drivers only use 40 bytes of it.
myhost:~# ethtool -x eth0
RX flow hash indirection table for eth0 with 8 RX ring(s):
0: 0 1 2 3 4 5 6 7
RSS hash key:
84:50:f4:00:a8:15:d1:a7:e9:7f:1d:60:35:c7:47:25:42:97:74:ca:56:bb:b6:a1:d8:43:e3:c9:0c:fd:17:55:c2:3a:4d:69:ed:f1:42:89
netdev_tstamp_prequeue netdev_tstamp_prequeue
---------------------- ----------------------

View File

@ -338,7 +338,7 @@ static int xgbe_probe(struct platform_device *pdev)
} }
/* Initialize RSS hash key and lookup table */ /* Initialize RSS hash key and lookup table */
get_random_bytes(pdata->rss_key, sizeof(pdata->rss_key)); netdev_rss_key_fill(pdata->rss_key, sizeof(pdata->rss_key));
for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++) for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++)
XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH, XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,

View File

@ -2099,7 +2099,7 @@ int bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
if (config_hash) { if (config_hash) {
/* RSS keys */ /* RSS keys */
prandom_bytes(params.rss_key, T_ETH_RSS_KEY * 4); netdev_rss_key_fill(params.rss_key, T_ETH_RSS_KEY * 4);
__set_bit(BNX2X_RSS_SET_SRCH, &params.rss_flags); __set_bit(BNX2X_RSS_SET_SRCH, &params.rss_flags);
} }

View File

@ -10540,19 +10540,14 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
udelay(100); udelay(100);
if (tg3_flag(tp, ENABLE_RSS)) { if (tg3_flag(tp, ENABLE_RSS)) {
u32 rss_key[10];
tg3_rss_write_indir_tbl(tp); tg3_rss_write_indir_tbl(tp);
/* Setup the "secret" hash key. */ netdev_rss_key_fill(rss_key, 10 * sizeof(u32));
tw32(MAC_RSS_HASH_KEY_0, 0x5f865437);
tw32(MAC_RSS_HASH_KEY_1, 0xe4ac62cc); for (i = 0; i < 10 ; i++)
tw32(MAC_RSS_HASH_KEY_2, 0x50103a45); tw32(MAC_RSS_HASH_KEY_0 + i*4, rss_key[i]);
tw32(MAC_RSS_HASH_KEY_3, 0x36621985);
tw32(MAC_RSS_HASH_KEY_4, 0xbf14c0e8);
tw32(MAC_RSS_HASH_KEY_5, 0x1bc27a1e);
tw32(MAC_RSS_HASH_KEY_6, 0x84f4b556);
tw32(MAC_RSS_HASH_KEY_7, 0x094ea6fe);
tw32(MAC_RSS_HASH_KEY_8, 0x7dda01e7);
tw32(MAC_RSS_HASH_KEY_9, 0xc04d7481);
} }
tp->rx_mode = RX_MODE_ENABLE; tp->rx_mode = RX_MODE_ENABLE;

View File

@ -2054,7 +2054,7 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
BFI_ENET_RSS_IPV4_TCP); BFI_ENET_RSS_IPV4_TCP);
rx_config->rss_config.hash_mask = rx_config->rss_config.hash_mask =
bnad->num_rxp_per_rx - 1; bnad->num_rxp_per_rx - 1;
get_random_bytes(rx_config->rss_config.toeplitz_hash_key, netdev_rss_key_fill(rx_config->rss_config.toeplitz_hash_key,
sizeof(rx_config->rss_config.toeplitz_hash_key)); sizeof(rx_config->rss_config.toeplitz_hash_key));
} else { } else {
rx_config->rss_status = BNA_STATUS_T_DISABLED; rx_config->rss_status = BNA_STATUS_T_DISABLED;

View File

@ -2853,10 +2853,10 @@ static int be_close(struct net_device *netdev)
static int be_rx_qs_create(struct be_adapter *adapter) static int be_rx_qs_create(struct be_adapter *adapter)
{ {
struct rss_info *rss = &adapter->rss_info;
u8 rss_key[RSS_HASH_KEY_LEN];
struct be_rx_obj *rxo; struct be_rx_obj *rxo;
int rc, i, j; int rc, i, j;
u8 rss_hkey[RSS_HASH_KEY_LEN];
struct rss_info *rss = &adapter->rss_info;
for_all_rx_queues(adapter, rxo, i) { for_all_rx_queues(adapter, rxo, i) {
rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN, rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN,
@ -2901,15 +2901,15 @@ static int be_rx_qs_create(struct be_adapter *adapter)
rss->rss_flags = RSS_ENABLE_NONE; rss->rss_flags = RSS_ENABLE_NONE;
} }
get_random_bytes(rss_hkey, RSS_HASH_KEY_LEN); netdev_rss_key_fill(rss_key, RSS_HASH_KEY_LEN);
rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags, rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags,
128, rss_hkey); 128, rss_key);
if (rc) { if (rc) {
rss->rss_flags = RSS_ENABLE_NONE; rss->rss_flags = RSS_ENABLE_NONE;
return rc; return rc;
} }
memcpy(rss->rss_hkey, rss_hkey, RSS_HASH_KEY_LEN); memcpy(rss->rss_hkey, rss_key, RSS_HASH_KEY_LEN);
/* First time posting */ /* First time posting */
for_all_rx_queues(adapter, rxo, i) for_all_rx_queues(adapter, rxo, i)

View File

@ -3449,15 +3449,12 @@ static void e1000e_setup_rss_hash(struct e1000_adapter *adapter)
{ {
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum; u32 mrqc, rxcsum;
u32 rss_key[10];
int i; int i;
static const u32 rsskey[10] = {
0xda565a6d, 0xc20e5b25, 0x3d256741, 0xb08fa343, 0xcb2bcad0,
0xb4307bae, 0xa32dcb77, 0x0cf23080, 0x3bb7426a, 0xfa01acbe
};
/* Fill out hash function seed */ netdev_rss_key_fill(rss_key, sizeof(rss_key));
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
ew32(RSSRK(i), rsskey[i]); ew32(RSSRK(i), rss_key[i]);
/* Direct all traffic to queue 0 */ /* Direct all traffic to queue 0 */
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)

View File

@ -1551,15 +1551,11 @@ void fm10k_down(struct fm10k_intfc *interface)
static int fm10k_sw_init(struct fm10k_intfc *interface, static int fm10k_sw_init(struct fm10k_intfc *interface,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
static const u32 seed[FM10K_RSSRK_SIZE] = { 0xda565a6d, 0xc20e5b25,
0x3d256741, 0xb08fa343,
0xcb2bcad0, 0xb4307bae,
0xa32dcb77, 0x0cf23080,
0x3bb7426a, 0xfa01acbe };
const struct fm10k_info *fi = fm10k_info_tbl[ent->driver_data]; const struct fm10k_info *fi = fm10k_info_tbl[ent->driver_data];
struct fm10k_hw *hw = &interface->hw; struct fm10k_hw *hw = &interface->hw;
struct pci_dev *pdev = interface->pdev; struct pci_dev *pdev = interface->pdev;
struct net_device *netdev = interface->netdev; struct net_device *netdev = interface->netdev;
u32 rss_key[FM10K_RSSRK_SIZE];
unsigned int rss; unsigned int rss;
int err; int err;
@ -1673,8 +1669,8 @@ static int fm10k_sw_init(struct fm10k_intfc *interface,
/* initialize vxlan_port list */ /* initialize vxlan_port list */
INIT_LIST_HEAD(&interface->vxlan_port); INIT_LIST_HEAD(&interface->vxlan_port);
/* initialize RSS key */ netdev_rss_key_fill(rss_key, sizeof(rss_key));
memcpy(interface->rssrk, seed, sizeof(seed)); memcpy(interface->rssrk, rss_key, sizeof(rss_key));
/* Start off interface as being down */ /* Start off interface as being down */
set_bit(__FM10K_DOWN, &interface->state); set_bit(__FM10K_DOWN, &interface->state);

View File

@ -7002,20 +7002,16 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
**/ **/
static int i40e_config_rss(struct i40e_pf *pf) static int i40e_config_rss(struct i40e_pf *pf)
{ {
/* Set of random keys generated using kernel random number generator */ u32 rss_key[I40E_PFQF_HKEY_MAX_INDEX + 1];
static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687,
0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377,
0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d,
0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be};
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
u32 lut = 0; u32 lut = 0;
int i, j; int i, j;
u64 hena; u64 hena;
u32 reg_val; u32 reg_val;
/* Fill out hash function seed */ netdev_rss_key_fill(rss_key, sizeof(rss_key));
for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
wr32(hw, I40E_PFQF_HKEY(i), seed[i]); wr32(hw, I40E_PFQF_HKEY(i), rss_key[i]);
/* By default we enable TCP/UDP with IPv4/IPv6 ptypes */ /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */
hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |

View File

@ -1434,18 +1434,12 @@ static int next_queue(struct i40evf_adapter *adapter, int j)
**/ **/
static void i40evf_configure_rss(struct i40evf_adapter *adapter) static void i40evf_configure_rss(struct i40evf_adapter *adapter)
{ {
u32 rss_key[I40E_VFQF_HKEY_MAX_INDEX + 1];
struct i40e_hw *hw = &adapter->hw; struct i40e_hw *hw = &adapter->hw;
u32 lut = 0; u32 lut = 0;
int i, j; int i, j;
u64 hena; u64 hena;
/* Set of random keys generated using kernel random number generator */
static const u32 seed[I40E_VFQF_HKEY_MAX_INDEX + 1] = {
0x794221b4, 0xbca0c5ab, 0x6cd5ebd9, 0x1ada6127,
0x983b3aa1, 0x1c4e71eb, 0x7f6328b2, 0xfcdc0da0,
0xc135cafa, 0x7a6f7e2d, 0xe7102d28, 0x163cd12e,
0x4954b126 };
/* No RSS for single queue. */ /* No RSS for single queue. */
if (adapter->num_active_queues == 1) { if (adapter->num_active_queues == 1) {
wr32(hw, I40E_VFQF_HENA(0), 0); wr32(hw, I40E_VFQF_HENA(0), 0);
@ -1454,8 +1448,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
} }
/* Hash type is configured by the PF - we just supply the key */ /* Hash type is configured by the PF - we just supply the key */
netdev_rss_key_fill(rss_key, sizeof(rss_key));
for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
wr32(hw, I40E_VFQF_HKEY(i), seed[i]); wr32(hw, I40E_VFQF_HKEY(i), rss_key[i]);
/* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
hena = I40E_DEFAULT_RSS_HENA; hena = I40E_DEFAULT_RSS_HENA;

View File

@ -3372,14 +3372,11 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum; u32 mrqc, rxcsum;
u32 j, num_rx_queues; u32 j, num_rx_queues;
static const u32 rsskey[10] = { 0xDA565A6D, 0xC20E5B25, 0x3D256741, u32 rss_key[10];
0xB08FA343, 0xCB2BCAD0, 0xB4307BAE,
0xA32DCB77, 0x0CF23080, 0x3BB7426A,
0xFA01ACBE };
/* Fill out hash function seeds */ netdev_rss_key_fill(rss_key, sizeof(rss_key));
for (j = 0; j < 10; j++) for (j = 0; j < 10; j++)
wr32(E1000_RSSRK(j), rsskey[j]); wr32(E1000_RSSRK(j), rss_key[j]);
num_rx_queues = adapter->rss_queues; num_rx_queues = adapter->rss_queues;

View File

@ -3243,10 +3243,8 @@ static void ixgbe_setup_reta(struct ixgbe_adapter *adapter, const u32 *seed)
static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter) static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
{ {
struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_hw *hw = &adapter->hw;
static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D,
0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
0x6A3E67EA, 0x14364D17, 0x3BED200D};
u32 mrqc = 0, rss_field = 0; u32 mrqc = 0, rss_field = 0;
u32 rss_key[10];
u32 rxcsum; u32 rxcsum;
/* Disable indicating checksum in descriptor, enables RSS hash */ /* Disable indicating checksum in descriptor, enables RSS hash */
@ -3290,7 +3288,8 @@ static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP) if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
rss_field |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; rss_field |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
ixgbe_setup_reta(adapter, seed); netdev_rss_key_fill(rss_key, sizeof(rss_key));
ixgbe_setup_reta(adapter, rss_key);
mrqc |= rss_field; mrqc |= rss_field;
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
} }

View File

@ -973,6 +973,11 @@ static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev)
return priv->rx_ring_num; return priv->rx_ring_num;
} }
static u32 mlx4_en_get_rxfh_key_size(struct net_device *netdev)
{
return MLX4_EN_RSS_KEY_SIZE;
}
static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key) static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
{ {
struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_priv *priv = netdev_priv(dev);
@ -988,7 +993,8 @@ static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key)
ring_index[n] = rss_map->qps[n % rss_rings].qpn - ring_index[n] = rss_map->qps[n % rss_rings].qpn -
rss_map->base_qpn; rss_map->base_qpn;
} }
if (key)
netdev_rss_key_fill(key, MLX4_EN_RSS_KEY_SIZE);
return err; return err;
} }
@ -1799,6 +1805,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_rxnfc = mlx4_en_get_rxnfc, .get_rxnfc = mlx4_en_get_rxnfc,
.set_rxnfc = mlx4_en_set_rxnfc, .set_rxnfc = mlx4_en_set_rxnfc,
.get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size,
.get_rxfh_key_size = mlx4_en_get_rxfh_key_size,
.get_rxfh = mlx4_en_get_rxfh, .get_rxfh = mlx4_en_get_rxfh,
.set_rxfh = mlx4_en_set_rxfh, .set_rxfh = mlx4_en_set_rxfh,
.get_channels = mlx4_en_get_channels, .get_channels = mlx4_en_get_channels,

View File

@ -1169,9 +1169,6 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
int i, qpn; int i, qpn;
int err = 0; int err = 0;
int good_qps = 0; int good_qps = 0;
static const u32 rsskey[10] = { 0xD181C62C, 0xF7F4DB5B, 0x1983A2FC,
0x943E1ADB, 0xD9389E6B, 0xD1039C2C, 0xA74499AD,
0x593D56D9, 0xF3253C06, 0x2ADC1FFC};
en_dbg(DRV, priv, "Configuring rss steering\n"); en_dbg(DRV, priv, "Configuring rss steering\n");
err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num,
@ -1226,8 +1223,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
rss_context->flags = rss_mask; rss_context->flags = rss_mask;
rss_context->hash_fn = MLX4_RSS_HASH_TOP; rss_context->hash_fn = MLX4_RSS_HASH_TOP;
for (i = 0; i < 10; i++) netdev_rss_key_fill(rss_context->rss_key, MLX4_EN_RSS_KEY_SIZE);
rss_context->rss_key[i] = cpu_to_be32(rsskey[i]);
err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context,
&rss_map->indir_qp, &rss_map->indir_state); &rss_map->indir_qp, &rss_map->indir_state);

View File

@ -1616,7 +1616,7 @@ static int efx_probe_nic(struct efx_nic *efx)
goto fail2; goto fail2;
if (efx->n_channels > 1) if (efx->n_channels > 1)
get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); netdev_rss_key_fill(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
efx->rx_indir_table[i] = efx->rx_indir_table[i] =
ethtool_rxfh_indir_default(i, efx->rss_spread); ethtool_rxfh_indir_default(i, efx->rss_spread);

View File

@ -2199,13 +2199,6 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
if (adapter->rss) { if (adapter->rss) {
struct UPT1_RSSConf *rssConf = adapter->rss_conf; struct UPT1_RSSConf *rssConf = adapter->rss_conf;
static const uint8_t rss_key[UPT1_RSS_MAX_KEY_SIZE] = {
0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
};
devRead->misc.uptFeatures |= UPT1_F_RSS; devRead->misc.uptFeatures |= UPT1_F_RSS;
devRead->misc.numRxQueues = adapter->num_rx_queues; devRead->misc.numRxQueues = adapter->num_rx_queues;
@ -2216,7 +2209,7 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ; rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ;
rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE; rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE;
rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE; rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
memcpy(rssConf->hashKey, rss_key, sizeof(rss_key)); netdev_rss_key_fill(rssConf->hashKey, sizeof(rssConf->hashKey));
for (i = 0; i < rssConf->indTableSize; i++) for (i = 0; i < rssConf->indTableSize; i++)
rssConf->indTable[i] = ethtool_rxfh_indir_default( rssConf->indTable[i] = ethtool_rxfh_indir_default(

View File

@ -120,13 +120,15 @@ enum {
MLX4_RSS_QPC_FLAG_OFFSET = 13, MLX4_RSS_QPC_FLAG_OFFSET = 13,
}; };
#define MLX4_EN_RSS_KEY_SIZE 40
struct mlx4_rss_context { struct mlx4_rss_context {
__be32 base_qpn; __be32 base_qpn;
__be32 default_qpn; __be32 default_qpn;
u16 reserved; u16 reserved;
u8 hash_fn; u8 hash_fn;
u8 flags; u8 flags;
__be32 rss_key[10]; __be32 rss_key[MLX4_EN_RSS_KEY_SIZE / sizeof(__be32)];
__be32 base_qpn_udp; __be32 base_qpn_udp;
}; };

View File

@ -3422,6 +3422,12 @@ void netdev_upper_dev_unlink(struct net_device *dev,
void netdev_adjacent_rename_links(struct net_device *dev, char *oldname); void netdev_adjacent_rename_links(struct net_device *dev, char *oldname);
void *netdev_lower_dev_get_private(struct net_device *dev, void *netdev_lower_dev_get_private(struct net_device *dev,
struct net_device *lower_dev); struct net_device *lower_dev);
/* RSS keys are 40 or 52 bytes long */
#define NETDEV_RSS_KEY_LEN 52
extern u8 netdev_rss_key[NETDEV_RSS_KEY_LEN];
void netdev_rss_key_fill(void *buffer, size_t len);
int dev_get_nest_level(struct net_device *dev, int dev_get_nest_level(struct net_device *dev,
bool (*type_check)(struct net_device *dev)); bool (*type_check)(struct net_device *dev));
int skb_checksum_help(struct sk_buff *skb); int skb_checksum_help(struct sk_buff *skb);

View File

@ -25,6 +25,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/net.h>
/* /*
* Some useful ethtool_ops methods that're device independent. * Some useful ethtool_ops methods that're device independent.
@ -573,6 +574,16 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
return 0; return 0;
} }
u8 netdev_rss_key[NETDEV_RSS_KEY_LEN];
void netdev_rss_key_fill(void *buffer, size_t len)
{
BUG_ON(len > sizeof(netdev_rss_key));
net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key));
memcpy(buffer, netdev_rss_key, len);
}
EXPORT_SYMBOL(netdev_rss_key_fill);
static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
void __user *useraddr) void __user *useraddr)
{ {

View File

@ -217,6 +217,18 @@ static int set_default_qdisc(struct ctl_table *table, int write,
} }
#endif #endif
static int proc_do_rss_key(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
struct ctl_table fake_table;
char buf[NETDEV_RSS_KEY_LEN * 3];
snprintf(buf, sizeof(buf), "%*phC", NETDEV_RSS_KEY_LEN, netdev_rss_key);
fake_table.data = buf;
fake_table.maxlen = sizeof(buf);
return proc_dostring(&fake_table, write, buffer, lenp, ppos);
}
static struct ctl_table net_core_table[] = { static struct ctl_table net_core_table[] = {
#ifdef CONFIG_NET #ifdef CONFIG_NET
{ {
@ -265,6 +277,13 @@ static struct ctl_table net_core_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec .proc_handler = proc_dointvec
}, },
{
.procname = "netdev_rss_key",
.data = &netdev_rss_key,
.maxlen = sizeof(int),
.mode = 0444,
.proc_handler = proc_do_rss_key,
},
#ifdef CONFIG_BPF_JIT #ifdef CONFIG_BPF_JIT
{ {
.procname = "bpf_jit_enable", .procname = "bpf_jit_enable",