aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv
diff options
context:
space:
mode:
authorHaiyang Zhang <haiyangz@microsoft.com>2014-10-16 17:47:58 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-17 23:43:40 -0400
commitf88e67149f97d73c704d6fe6f492edde97463025 (patch)
tree3f7fa7be6589fa32d74d2c7c0c3e82bde97a3968 /drivers/net/hyperv
parentf47de068f68db91b89e0d3335230d07e02da8727 (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.c26
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 */
165static u32 comp_hash(u8 *key, int klen, u8 *data, int dlen) 165static 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
191static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) 191static 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
215static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, 209static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,