diff options
Diffstat (limited to 'drivers/net/hyperv/netvsc_drv.c')
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 70 |
1 files changed, 6 insertions, 64 deletions
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 1c8db9afdcda..98e34fee45c7 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 | ||
| 199 | union 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 | */ | ||
| 212 | static 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 | |||
| 238 | static 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 | |||
| 258 | static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, | 199 | static 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; |
| @@ -1150,6 +1089,9 @@ static int netvsc_probe(struct hv_device *dev, | |||
| 1150 | net->ethtool_ops = ðtool_ops; | 1089 | net->ethtool_ops = ðtool_ops; |
| 1151 | SET_NETDEV_DEV(net, &dev->device); | 1090 | SET_NETDEV_DEV(net, &dev->device); |
| 1152 | 1091 | ||
| 1092 | /* We always need headroom for rndis header */ | ||
| 1093 | net->needed_headroom = RNDIS_AND_PPI_SIZE; | ||
| 1094 | |||
| 1153 | /* Notify the netvsc driver of the new device */ | 1095 | /* Notify the netvsc driver of the new device */ |
| 1154 | memset(&device_info, 0, sizeof(device_info)); | 1096 | memset(&device_info, 0, sizeof(device_info)); |
| 1155 | device_info.ring_size = ring_size; | 1097 | device_info.ring_size = ring_size; |
