hv_netvsc: use skb_get_hash() instead of a homegrown implementation
Recent changes to 'struct flow_keys' (e.g commit d34af823ff
("net: Add
VLAN ID to flow_keys")) introduced a performance regression in netvsc
driver. Is problem is, however, not the above mentioned commit but the
fact that netvsc_set_hash() function did some assumptions on the struct
flow_keys data layout and this is wrong.
Get rid of netvsc_set_hash() by switching to skb_get_hash(). This change
will also imply switching to Jenkins hash from the currently used Toeplitz
but it seems there is no good excuse for Toeplitz to stay.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
87e57399e9
commit
757647e10e
|
@ -196,65 +196,6 @@ static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
|
|||
return ppi;
|
||||
}
|
||||
|
||||
union sub_key {
|
||||
u64 k;
|
||||
struct {
|
||||
u8 pad[3];
|
||||
u8 kb;
|
||||
u32 ka;
|
||||
};
|
||||
};
|
||||
|
||||
/* Toeplitz hash function
|
||||
* data: network byte order
|
||||
* return: host byte order
|
||||
*/
|
||||
static u32 comp_hash(u8 *key, int klen, void *data, int dlen)
|
||||
{
|
||||
union sub_key subk;
|
||||
int k_next = 4;
|
||||
u8 dt;
|
||||
int i, j;
|
||||
u32 ret = 0;
|
||||
|
||||
subk.k = 0;
|
||||
subk.ka = ntohl(*(u32 *)key);
|
||||
|
||||
for (i = 0; i < dlen; i++) {
|
||||
subk.kb = key[k_next];
|
||||
k_next = (k_next + 1) % klen;
|
||||
dt = ((u8 *)data)[i];
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (dt & 0x80)
|
||||
ret ^= subk.ka;
|
||||
dt <<= 1;
|
||||
subk.k <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
|
||||
{
|
||||
struct flow_keys flow;
|
||||
int data_len;
|
||||
|
||||
if (!skb_flow_dissect_flow_keys(skb, &flow, 0) ||
|
||||
!(flow.basic.n_proto == htons(ETH_P_IP) ||
|
||||
flow.basic.n_proto == htons(ETH_P_IPV6)))
|
||||
return false;
|
||||
|
||||
if (flow.basic.ip_proto == IPPROTO_TCP)
|
||||
data_len = 12;
|
||||
else
|
||||
data_len = 8;
|
||||
|
||||
*hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, &flow, data_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
|
||||
void *accel_priv, select_queue_fallback_t fallback)
|
||||
{
|
||||
|
@ -267,11 +208,9 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
|
|||
if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1)
|
||||
return 0;
|
||||
|
||||
if (netvsc_set_hash(&hash, skb)) {
|
||||
q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
|
||||
ndev->real_num_tx_queues;
|
||||
skb_set_hash(skb, hash, PKT_HASH_TYPE_L3);
|
||||
}
|
||||
hash = skb_get_hash(skb);
|
||||
q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
|
||||
ndev->real_num_tx_queues;
|
||||
|
||||
if (!nvsc_dev->chn_table[q_idx])
|
||||
q_idx = 0;
|
||||
|
|
Loading…
Reference in New Issue