diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e813eaf69256..51fa90365348 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -191,6 +191,36 @@ static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, return ppi; } +/* Azure hosts don't support non-TCP port numbers in hashing yet. We compute + * hash for non-TCP traffic with only IP numbers. + */ +static inline u32 netvsc_get_hash(struct sk_buff *skb, struct sock *sk) +{ + struct flow_keys flow; + u32 hash; + static u32 hashrnd __read_mostly; + + net_get_random_once(&hashrnd, sizeof(hashrnd)); + + if (!skb_flow_dissect_flow_keys(skb, &flow, 0)) + return 0; + + if (flow.basic.ip_proto == IPPROTO_TCP) { + return skb_get_hash(skb); + } else { + if (flow.basic.n_proto == htons(ETH_P_IP)) + hash = jhash2((u32 *)&flow.addrs.v4addrs, 2, hashrnd); + else if (flow.basic.n_proto == htons(ETH_P_IPV6)) + hash = jhash2((u32 *)&flow.addrs.v6addrs, 8, hashrnd); + else + hash = 0; + + skb_set_hash(skb, hash, PKT_HASH_TYPE_L3); + } + + return hash; +} + static inline int netvsc_get_tx_queue(struct net_device *ndev, struct sk_buff *skb, int old_idx) { @@ -198,7 +228,7 @@ static inline int netvsc_get_tx_queue(struct net_device *ndev, struct sock *sk = skb->sk; int q_idx; - q_idx = ndc->tx_send_table[skb_get_hash(skb) & + q_idx = ndc->tx_send_table[netvsc_get_hash(skb, sk) & (VRSS_SEND_TAB_SIZE - 1)]; /* If queue index changed record the new value */ |