diff options
| author | Haiyang Zhang <haiyangz@microsoft.com> | 2014-10-16 17:47:58 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-10-17 23:43:40 -0400 |
| commit | f88e67149f97d73c704d6fe6f492edde97463025 (patch) | |
| tree | 3f7fa7be6589fa32d74d2c7c0c3e82bde97a3968 /drivers/net/hyperv | |
| parent | f47de068f68db91b89e0d3335230d07e02da8727 (diff) | |
hyperv: Add handling of IP header with option field in netvsc_set_hash()
In case that the IP header has optional field at the end, this patch will
get the port numbers after that field, and compute the hash. The general
parser skb_flow_dissect() is used here.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/hyperv')
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 26 |
1 files changed, 10 insertions, 16 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 0fcb5e7eb073..9e17d1a91e71 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
| @@ -162,7 +162,7 @@ union sub_key { | |||
| 162 | * data: network byte order | 162 | * data: network byte order |
| 163 | * return: host byte order | 163 | * return: host byte order |
| 164 | */ | 164 | */ |
| 165 | static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen) | 165 | static u32 comp_hash(u8 *key, int klen, void *data, int dlen) |
| 166 | { | 166 | { |
| 167 | union sub_key subk; | 167 | union sub_key subk; |
| 168 | int k_next = 4; | 168 | int k_next = 4; |
| @@ -176,7 +176,7 @@ static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen) | |||
| 176 | for (i = 0; i < dlen; i++) { | 176 | for (i = 0; i < dlen; i++) { |
| 177 | subk.kb = key[k_next]; | 177 | subk.kb = key[k_next]; |
| 178 | k_next = (k_next + 1) % klen; | 178 | k_next = (k_next + 1) % klen; |
| 179 | dt = data[i]; | 179 | dt = ((u8 *)data)[i]; |
| 180 | for (j = 0; j < 8; j++) { | 180 | for (j = 0; j < 8; j++) { |
| 181 | if (dt & 0x80) | 181 | if (dt & 0x80) |
| 182 | ret ^= subk.ka; | 182 | ret ^= subk.ka; |
| @@ -190,26 +190,20 @@ static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen) | |||
| 190 | 190 | ||
| 191 | static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) | 191 | static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) |
| 192 | { | 192 | { |
| 193 | struct iphdr *iphdr; | 193 | struct flow_keys flow; |
| 194 | int data_len; | 194 | int data_len; |
| 195 | bool ret = false; | ||
| 196 | 195 | ||
| 197 | if (eth_hdr(skb)->h_proto != htons(ETH_P_IP)) | 196 | if (!skb_flow_dissect(skb, &flow) || flow.n_proto != htons(ETH_P_IP)) |
| 198 | return false; | 197 | return false; |
| 199 | 198 | ||
| 200 | iphdr = ip_hdr(skb); | 199 | if (flow.ip_proto == IPPROTO_TCP) |
| 200 | data_len = 12; | ||
| 201 | else | ||
| 202 | data_len = 8; | ||
| 201 | 203 | ||
| 202 | if (iphdr->version == 4) { | 204 | *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, &flow, data_len); |
| 203 | if (iphdr->protocol == IPPROTO_TCP) | ||
| 204 | data_len = 12; | ||
| 205 | else | ||
| 206 | data_len = 8; | ||
| 207 | *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, | ||
| 208 | (u8 *)&iphdr->saddr, data_len); | ||
| 209 | ret = true; | ||
| 210 | } | ||
| 211 | 205 | ||
| 212 | return ret; | 206 | return true; |
| 213 | } | 207 | } |
| 214 | 208 | ||
| 215 | static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, | 209 | static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, |
