diff options
Diffstat (limited to 'net/core/flow_dissector.c')
-rw-r--r-- | net/core/flow_dissector.c | 85 |
1 files changed, 49 insertions, 36 deletions
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 107ed12a5323..5f362c1d0332 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
@@ -80,6 +80,8 @@ ip: | |||
80 | case htons(ETH_P_IPV6): { | 80 | case htons(ETH_P_IPV6): { |
81 | const struct ipv6hdr *iph; | 81 | const struct ipv6hdr *iph; |
82 | struct ipv6hdr _iph; | 82 | struct ipv6hdr _iph; |
83 | __be32 flow_label; | ||
84 | |||
83 | ipv6: | 85 | ipv6: |
84 | iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); | 86 | iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); |
85 | if (!iph) | 87 | if (!iph) |
@@ -89,6 +91,21 @@ ipv6: | |||
89 | flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); | 91 | flow->src = (__force __be32)ipv6_addr_hash(&iph->saddr); |
90 | flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); | 92 | flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); |
91 | nhoff += sizeof(struct ipv6hdr); | 93 | nhoff += sizeof(struct ipv6hdr); |
94 | |||
95 | flow_label = ip6_flowlabel(iph); | ||
96 | if (flow_label) { | ||
97 | /* Awesome, IPv6 packet has a flow label so we can | ||
98 | * use that to represent the ports without any | ||
99 | * further dissection. | ||
100 | */ | ||
101 | flow->n_proto = proto; | ||
102 | flow->ip_proto = ip_proto; | ||
103 | flow->ports = flow_label; | ||
104 | flow->thoff = (u16)nhoff; | ||
105 | |||
106 | return true; | ||
107 | } | ||
108 | |||
92 | break; | 109 | break; |
93 | } | 110 | } |
94 | case htons(ETH_P_8021AD): | 111 | case htons(ETH_P_8021AD): |
@@ -175,6 +192,7 @@ ipv6: | |||
175 | break; | 192 | break; |
176 | } | 193 | } |
177 | 194 | ||
195 | flow->n_proto = proto; | ||
178 | flow->ip_proto = ip_proto; | 196 | flow->ip_proto = ip_proto; |
179 | flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); | 197 | flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto); |
180 | flow->thoff = (u16) nhoff; | 198 | flow->thoff = (u16) nhoff; |
@@ -195,12 +213,33 @@ static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c) | |||
195 | return jhash_3words(a, b, c, hashrnd); | 213 | return jhash_3words(a, b, c, hashrnd); |
196 | } | 214 | } |
197 | 215 | ||
198 | static __always_inline u32 __flow_hash_1word(u32 a) | 216 | static inline u32 __flow_hash_from_keys(struct flow_keys *keys) |
199 | { | 217 | { |
200 | __flow_hash_secret_init(); | 218 | u32 hash; |
201 | return jhash_1word(a, hashrnd); | 219 | |
220 | /* get a consistent hash (same value on both flow directions) */ | ||
221 | if (((__force u32)keys->dst < (__force u32)keys->src) || | ||
222 | (((__force u32)keys->dst == (__force u32)keys->src) && | ||
223 | ((__force u16)keys->port16[1] < (__force u16)keys->port16[0]))) { | ||
224 | swap(keys->dst, keys->src); | ||
225 | swap(keys->port16[0], keys->port16[1]); | ||
226 | } | ||
227 | |||
228 | hash = __flow_hash_3words((__force u32)keys->dst, | ||
229 | (__force u32)keys->src, | ||
230 | (__force u32)keys->ports); | ||
231 | if (!hash) | ||
232 | hash = 1; | ||
233 | |||
234 | return hash; | ||
202 | } | 235 | } |
203 | 236 | ||
237 | u32 flow_hash_from_keys(struct flow_keys *keys) | ||
238 | { | ||
239 | return __flow_hash_from_keys(keys); | ||
240 | } | ||
241 | EXPORT_SYMBOL(flow_hash_from_keys); | ||
242 | |||
204 | /* | 243 | /* |
205 | * __skb_get_hash: calculate a flow hash based on src/dst addresses | 244 | * __skb_get_hash: calculate a flow hash based on src/dst addresses |
206 | * and src/dst port numbers. Sets hash in skb to non-zero hash value | 245 | * and src/dst port numbers. Sets hash in skb to non-zero hash value |
@@ -210,7 +249,6 @@ static __always_inline u32 __flow_hash_1word(u32 a) | |||
210 | void __skb_get_hash(struct sk_buff *skb) | 249 | void __skb_get_hash(struct sk_buff *skb) |
211 | { | 250 | { |
212 | struct flow_keys keys; | 251 | struct flow_keys keys; |
213 | u32 hash; | ||
214 | 252 | ||
215 | if (!skb_flow_dissect(skb, &keys)) | 253 | if (!skb_flow_dissect(skb, &keys)) |
216 | return; | 254 | return; |
@@ -218,21 +256,9 @@ void __skb_get_hash(struct sk_buff *skb) | |||
218 | if (keys.ports) | 256 | if (keys.ports) |
219 | skb->l4_hash = 1; | 257 | skb->l4_hash = 1; |
220 | 258 | ||
221 | /* get a consistent hash (same value on both flow directions) */ | 259 | skb->sw_hash = 1; |
222 | if (((__force u32)keys.dst < (__force u32)keys.src) || | ||
223 | (((__force u32)keys.dst == (__force u32)keys.src) && | ||
224 | ((__force u16)keys.port16[1] < (__force u16)keys.port16[0]))) { | ||
225 | swap(keys.dst, keys.src); | ||
226 | swap(keys.port16[0], keys.port16[1]); | ||
227 | } | ||
228 | |||
229 | hash = __flow_hash_3words((__force u32)keys.dst, | ||
230 | (__force u32)keys.src, | ||
231 | (__force u32)keys.ports); | ||
232 | if (!hash) | ||
233 | hash = 1; | ||
234 | 260 | ||
235 | skb->hash = hash; | 261 | skb->hash = __flow_hash_from_keys(&keys); |
236 | } | 262 | } |
237 | EXPORT_SYMBOL(__skb_get_hash); | 263 | EXPORT_SYMBOL(__skb_get_hash); |
238 | 264 | ||
@@ -240,7 +266,7 @@ EXPORT_SYMBOL(__skb_get_hash); | |||
240 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number | 266 | * Returns a Tx hash based on the given packet descriptor a Tx queues' number |
241 | * to be used as a distribution range. | 267 | * to be used as a distribution range. |
242 | */ | 268 | */ |
243 | u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | 269 | u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, |
244 | unsigned int num_tx_queues) | 270 | unsigned int num_tx_queues) |
245 | { | 271 | { |
246 | u32 hash; | 272 | u32 hash; |
@@ -260,13 +286,7 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb, | |||
260 | qcount = dev->tc_to_txq[tc].count; | 286 | qcount = dev->tc_to_txq[tc].count; |
261 | } | 287 | } |
262 | 288 | ||
263 | if (skb->sk && skb->sk->sk_hash) | 289 | return (u16) (((u64)skb_get_hash(skb) * qcount) >> 32) + qoffset; |
264 | hash = skb->sk->sk_hash; | ||
265 | else | ||
266 | hash = (__force u16) skb->protocol; | ||
267 | hash = __flow_hash_1word(hash); | ||
268 | |||
269 | return (u16) (((u64) hash * qcount) >> 32) + qoffset; | ||
270 | } | 290 | } |
271 | EXPORT_SYMBOL(__skb_tx_hash); | 291 | EXPORT_SYMBOL(__skb_tx_hash); |
272 | 292 | ||
@@ -338,17 +358,10 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) | |||
338 | if (map) { | 358 | if (map) { |
339 | if (map->len == 1) | 359 | if (map->len == 1) |
340 | queue_index = map->queues[0]; | 360 | queue_index = map->queues[0]; |
341 | else { | 361 | else |
342 | u32 hash; | ||
343 | if (skb->sk && skb->sk->sk_hash) | ||
344 | hash = skb->sk->sk_hash; | ||
345 | else | ||
346 | hash = (__force u16) skb->protocol ^ | ||
347 | skb->hash; | ||
348 | hash = __flow_hash_1word(hash); | ||
349 | queue_index = map->queues[ | 362 | queue_index = map->queues[ |
350 | ((u64)hash * map->len) >> 32]; | 363 | ((u64)skb_get_hash(skb) * map->len) >> 32]; |
351 | } | 364 | |
352 | if (unlikely(queue_index >= dev->real_num_tx_queues)) | 365 | if (unlikely(queue_index >= dev->real_num_tx_queues)) |
353 | queue_index = -1; | 366 | queue_index = -1; |
354 | } | 367 | } |