aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hyperv/netvsc_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
-rw-r--r--drivers/net/hyperv/netvsc_drv.c67
1 files changed, 3 insertions, 64 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 1c8db9afdcda..1d3a66563bac 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -196,65 +196,6 @@ static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
196 return ppi; 196 return ppi;
197} 197}
198 198
199union sub_key {
200 u64 k;
201 struct {
202 u8 pad[3];
203 u8 kb;
204 u32 ka;
205 };
206};
207
208/* Toeplitz hash function
209 * data: network byte order
210 * return: host byte order
211 */
212static u32 comp_hash(u8 *key, int klen, void *data, int dlen)
213{
214 union sub_key subk;
215 int k_next = 4;
216 u8 dt;
217 int i, j;
218 u32 ret = 0;
219
220 subk.k = 0;
221 subk.ka = ntohl(*(u32 *)key);
222
223 for (i = 0; i < dlen; i++) {
224 subk.kb = key[k_next];
225 k_next = (k_next + 1) % klen;
226 dt = ((u8 *)data)[i];
227 for (j = 0; j < 8; j++) {
228 if (dt & 0x80)
229 ret ^= subk.ka;
230 dt <<= 1;
231 subk.k <<= 1;
232 }
233 }
234
235 return ret;
236}
237
238static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
239{
240 struct flow_keys flow;
241 int data_len;
242
243 if (!skb_flow_dissect_flow_keys(skb, &flow, 0) ||
244 !(flow.basic.n_proto == htons(ETH_P_IP) ||
245 flow.basic.n_proto == htons(ETH_P_IPV6)))
246 return false;
247
248 if (flow.basic.ip_proto == IPPROTO_TCP)
249 data_len = 12;
250 else
251 data_len = 8;
252
253 *hash = comp_hash(netvsc_hash_key, HASH_KEYLEN, &flow, data_len);
254
255 return true;
256}
257
258static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, 199static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
259 void *accel_priv, select_queue_fallback_t fallback) 200 void *accel_priv, select_queue_fallback_t fallback)
260{ 201{
@@ -267,11 +208,9 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
267 if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1) 208 if (nvsc_dev == NULL || ndev->real_num_tx_queues <= 1)
268 return 0; 209 return 0;
269 210
270 if (netvsc_set_hash(&hash, skb)) { 211 hash = skb_get_hash(skb);
271 q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] % 212 q_idx = nvsc_dev->send_table[hash % VRSS_SEND_TAB_SIZE] %
272 ndev->real_num_tx_queues; 213 ndev->real_num_tx_queues;
273 skb_set_hash(skb, hash, PKT_HASH_TYPE_L3);
274 }
275 214
276 if (!nvsc_dev->chn_table[q_idx]) 215 if (!nvsc_dev->chn_table[q_idx])
277 q_idx = 0; 216 q_idx = 0;