netvsc: add ethtool ops to get/set RSS key
For some cases it is useful to be able to change RSS key value. For example, replacing RSS key with a symmetric hash. Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b5a5dc8dc8
commit
962f3fee83
3 changed files with 70 additions and 17 deletions
|
@ -156,6 +156,8 @@ enum rndis_device_state {
|
|||
RNDIS_DEV_DATAINITIALIZED,
|
||||
};
|
||||
|
||||
#define NETVSC_HASH_KEYLEN 40
|
||||
|
||||
struct rndis_device {
|
||||
struct net_device *ndev;
|
||||
|
||||
|
@ -166,7 +168,8 @@ struct rndis_device {
|
|||
spinlock_t request_lock;
|
||||
struct list_head req_list;
|
||||
|
||||
unsigned char hw_mac_adr[ETH_ALEN];
|
||||
u8 hw_mac_adr[ETH_ALEN];
|
||||
u8 rss_key[NETVSC_HASH_KEYLEN];
|
||||
};
|
||||
|
||||
|
||||
|
@ -194,6 +197,8 @@ int rndis_filter_close(struct netvsc_device *nvdev);
|
|||
int rndis_filter_device_add(struct hv_device *dev,
|
||||
void *additional_info);
|
||||
void rndis_filter_device_remove(struct hv_device *dev);
|
||||
int rndis_filter_set_rss_param(struct rndis_device *rdev,
|
||||
const u8 *key, int num_queue);
|
||||
int rndis_filter_receive(struct hv_device *dev,
|
||||
struct hv_netvsc_packet *pkt,
|
||||
void **data,
|
||||
|
|
|
@ -1059,6 +1059,48 @@ static void netvsc_poll_controller(struct net_device *net)
|
|||
}
|
||||
#endif
|
||||
|
||||
static u32 netvsc_get_rxfh_key_size(struct net_device *dev)
|
||||
{
|
||||
return NETVSC_HASH_KEYLEN;
|
||||
}
|
||||
|
||||
static u32 netvsc_rss_indir_size(struct net_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
|
||||
u8 *hfunc)
|
||||
{
|
||||
struct net_device_context *ndc = netdev_priv(dev);
|
||||
struct netvsc_device *ndev = ndc->nvdev;
|
||||
struct rndis_device *rndis_dev = ndev->extension;
|
||||
|
||||
if (hfunc)
|
||||
*hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
|
||||
|
||||
if (key)
|
||||
memcpy(key, rndis_dev->rss_key, NETVSC_HASH_KEYLEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir,
|
||||
const u8 *key, const u8 hfunc)
|
||||
{
|
||||
struct net_device_context *ndc = netdev_priv(dev);
|
||||
struct netvsc_device *ndev = ndc->nvdev;
|
||||
struct rndis_device *rndis_dev = ndev->extension;
|
||||
|
||||
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!key || memcmp(key, rndis_dev->rss_key, NETVSC_HASH_KEYLEN) == 0)
|
||||
return 0; /* no change */
|
||||
|
||||
return rndis_filter_set_rss_param(rndis_dev, key, ndev->num_chn);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops ethtool_ops = {
|
||||
.get_drvinfo = netvsc_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
|
@ -1071,6 +1113,10 @@ static const struct ethtool_ops ethtool_ops = {
|
|||
.get_settings = netvsc_get_settings,
|
||||
.set_settings = netvsc_set_settings,
|
||||
.get_rxnfc = netvsc_get_rxnfc,
|
||||
.get_rxfh_key_size = netvsc_get_rxfh_key_size,
|
||||
.get_rxfh_indir_size = netvsc_rss_indir_size,
|
||||
.get_rxfh = netvsc_get_rxfh,
|
||||
.set_rxfh = netvsc_set_rxfh,
|
||||
};
|
||||
|
||||
static const struct net_device_ops device_ops = {
|
||||
|
|
|
@ -57,6 +57,14 @@ struct rndis_request {
|
|||
u8 request_ext[RNDIS_EXT_LEN];
|
||||
};
|
||||
|
||||
static const u8 netvsc_hash_key[NETVSC_HASH_KEYLEN] = {
|
||||
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
|
||||
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
|
||||
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
|
||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
|
||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
|
||||
};
|
||||
|
||||
static struct rndis_device *get_rndis_device(void)
|
||||
{
|
||||
struct rndis_device *device;
|
||||
|
@ -729,23 +737,15 @@ rndis_filter_set_offload_params(struct net_device *ndev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const u8 netvsc_hash_key[] = {
|
||||
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
|
||||
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
|
||||
0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
|
||||
0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
|
||||
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
|
||||
};
|
||||
#define HASH_KEYLEN ARRAY_SIZE(netvsc_hash_key)
|
||||
|
||||
static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
|
||||
int rndis_filter_set_rss_param(struct rndis_device *rdev,
|
||||
const u8 *rss_key, int num_queue)
|
||||
{
|
||||
struct net_device *ndev = rdev->ndev;
|
||||
struct rndis_request *request;
|
||||
struct rndis_set_request *set;
|
||||
struct rndis_set_complete *set_complete;
|
||||
u32 extlen = sizeof(struct ndis_recv_scale_param) +
|
||||
4*ITAB_NUM + HASH_KEYLEN;
|
||||
4 * ITAB_NUM + NETVSC_HASH_KEYLEN;
|
||||
struct ndis_recv_scale_param *rssp;
|
||||
u32 *itab;
|
||||
u8 *keyp;
|
||||
|
@ -773,7 +773,7 @@ static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
|
|||
NDIS_HASH_TCP_IPV6;
|
||||
rssp->indirect_tabsize = 4*ITAB_NUM;
|
||||
rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param);
|
||||
rssp->hashkey_size = HASH_KEYLEN;
|
||||
rssp->hashkey_size = NETVSC_HASH_KEYLEN;
|
||||
rssp->kashkey_offset = rssp->indirect_taboffset +
|
||||
rssp->indirect_tabsize;
|
||||
|
||||
|
@ -784,8 +784,7 @@ static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
|
|||
|
||||
/* Set hask key values */
|
||||
keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset);
|
||||
for (i = 0; i < HASH_KEYLEN; i++)
|
||||
keyp[i] = netvsc_hash_key[i];
|
||||
memcpy(keyp, rss_key, NETVSC_HASH_KEYLEN);
|
||||
|
||||
ret = rndis_filter_send_request(rdev, request);
|
||||
if (ret != 0)
|
||||
|
@ -793,7 +792,9 @@ static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
|
|||
|
||||
wait_for_completion(&request->wait_event);
|
||||
set_complete = &request->response_msg.msg.set_complete;
|
||||
if (set_complete->status != RNDIS_STATUS_SUCCESS) {
|
||||
if (set_complete->status == RNDIS_STATUS_SUCCESS)
|
||||
memcpy(rdev->rss_key, rss_key, NETVSC_HASH_KEYLEN);
|
||||
else {
|
||||
netdev_err(ndev, "Fail to set RSS parameters:0x%x\n",
|
||||
set_complete->status);
|
||||
ret = -EINVAL;
|
||||
|
@ -1235,7 +1236,8 @@ int rndis_filter_device_add(struct hv_device *dev,
|
|||
net_device->num_chn = 1 +
|
||||
init_packet->msg.v5_msg.subchn_comp.num_subchannels;
|
||||
|
||||
ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
|
||||
ret = rndis_filter_set_rss_param(rndis_device, netvsc_hash_key,
|
||||
net_device->num_chn);
|
||||
|
||||
/*
|
||||
* Set the number of sub-channels to be received.
|
||||
|
|
Loading…
Reference in a new issue