diff options
| author | Vitaly Kuznetsov <vkuznets@redhat.com> | 2016-01-25 10:00:41 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-01-25 13:51:53 -0500 |
| commit | 757647e10e55c01fb7a9c4356529442e316a7c72 (patch) | |
| tree | 301b90371e403baf51efa162078be19e074f300c /drivers/net | |
| parent | 87e57399e9d3606b08b0e1b2dd0f4aaa1d8ba365 (diff) | |
hv_netvsc: use skb_get_hash() instead of a homegrown implementation
Recent changes to 'struct flow_keys' (e.g commit d34af823ff40 ("net: Add
VLAN ID to flow_keys")) introduced a performance regression in netvsc
driver. Is problem is, however, not the above mentioned commit but the
fact that netvsc_set_hash() function did some assumptions on the struct
flow_keys data layout and this is wrong.
Get rid of netvsc_set_hash() by switching to skb_get_hash(). This change
will also imply switching to Jenkins hash from the currently used Toeplitz
but it seems there is no good excuse for Toeplitz to stay.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 67 |
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 | ||
| 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; |
