Skip to content

Commit

Permalink
netvsc: add ethtool ops to get/set RSS key
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
stephen hemminger authored and David S. Miller committed Jan 24, 2017
1 parent b5a5dc8 commit 962f3fe
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 17 deletions.
7 changes: 6 additions & 1 deletion drivers/net/hyperv/hyperv_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ enum rndis_device_state {
RNDIS_DEV_DATAINITIALIZED,
};

#define NETVSC_HASH_KEYLEN 40

struct rndis_device {
struct net_device *ndev;

Expand All @@ -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];
};


Expand Down Expand Up @@ -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,
Expand Down
46 changes: 46 additions & 0 deletions drivers/net/hyperv/netvsc_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 = {
Expand Down
34 changes: 18 additions & 16 deletions drivers/net/hyperv/rndis_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -784,16 +784,17 @@ 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)
goto cleanup;

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;
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 962f3fe

Please sign in to comment.