aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/flow_dissector.c
diff options
context:
space:
mode:
authorTom Herbert <tom@herbertland.com>2015-06-04 12:16:39 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-04 18:44:30 -0400
commit42aecaa9bb2bd57eb8d61b4565cee5d3640863fb (patch)
tree1f6198f7e7aaccaf60a51a1e69aca366a7fd1374 /net/core/flow_dissector.c
parentc468efe2c7d478bad8855f7d170cf245ee0f1b3f (diff)
net: Get skb hash over flow_keys structure
This patch changes flow hashing to use jhash2 over the flow_keys structure instead just doing jhash_3words over src, dst, and ports. This method will allow us take more input into the hashing function so that we can include full IPv6 addresses, VLAN, flow labels etc. without needing to resort to xor'ing which makes for a poor hash. Acked-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/flow_dissector.c')
-rw-r--r--net/core/flow_dissector.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 0763795bea8f..55b5f2962afa 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -57,10 +57,12 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
57 flow_dissector->offset[key->key_id] = key->offset; 57 flow_dissector->offset[key->key_id] = key->offset;
58 } 58 }
59 59
60 /* Ensure that the dissector always includes basic key. That way 60 /* Ensure that the dissector always includes control and basic key.
61 * we are able to avoid handling lack of it in fast path. 61 * That way we are able to avoid handling lack of these in fast path.
62 */ 62 */
63 BUG_ON(!skb_flow_dissector_uses_key(flow_dissector, 63 BUG_ON(!skb_flow_dissector_uses_key(flow_dissector,
64 FLOW_DISSECTOR_KEY_CONTROL));
65 BUG_ON(!skb_flow_dissector_uses_key(flow_dissector,
64 FLOW_DISSECTOR_KEY_BASIC)); 66 FLOW_DISSECTOR_KEY_BASIC));
65} 67}
66EXPORT_SYMBOL(skb_flow_dissector_init); 68EXPORT_SYMBOL(skb_flow_dissector_init);
@@ -120,6 +122,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
120 void *target_container, 122 void *target_container,
121 void *data, __be16 proto, int nhoff, int hlen) 123 void *data, __be16 proto, int nhoff, int hlen)
122{ 124{
125 struct flow_dissector_key_control *key_control;
123 struct flow_dissector_key_basic *key_basic; 126 struct flow_dissector_key_basic *key_basic;
124 struct flow_dissector_key_addrs *key_addrs; 127 struct flow_dissector_key_addrs *key_addrs;
125 struct flow_dissector_key_ports *key_ports; 128 struct flow_dissector_key_ports *key_ports;
@@ -132,6 +135,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
132 hlen = skb_headlen(skb); 135 hlen = skb_headlen(skb);
133 } 136 }
134 137
138 /* It is ensured by skb_flow_dissector_init() that control key will
139 * be always present.
140 */
141 key_control = skb_flow_dissector_target(flow_dissector,
142 FLOW_DISSECTOR_KEY_CONTROL,
143 target_container);
144
135 /* It is ensured by skb_flow_dissector_init() that basic key will 145 /* It is ensured by skb_flow_dissector_init() that basic key will
136 * be always present. 146 * be always present.
137 */ 147 */
@@ -219,7 +229,7 @@ flow_label:
219 229
220 key_basic->n_proto = proto; 230 key_basic->n_proto = proto;
221 key_basic->ip_proto = ip_proto; 231 key_basic->ip_proto = ip_proto;
222 key_basic->thoff = (u16)nhoff; 232 key_control->thoff = (u16)nhoff;
223 233
224 if (skb_flow_dissector_uses_key(flow_dissector, 234 if (skb_flow_dissector_uses_key(flow_dissector,
225 FLOW_DISSECTOR_KEY_PORTS)) { 235 FLOW_DISSECTOR_KEY_PORTS)) {
@@ -275,7 +285,7 @@ flow_label:
275 if (!hdr) 285 if (!hdr)
276 return false; 286 return false;
277 key_basic->n_proto = proto; 287 key_basic->n_proto = proto;
278 key_basic->thoff = (u16)nhoff; 288 key_control->thoff = (u16)nhoff;
279 289
280 if (skb_flow_dissector_uses_key(flow_dissector, 290 if (skb_flow_dissector_uses_key(flow_dissector,
281 FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) { 291 FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) {
@@ -288,7 +298,7 @@ flow_label:
288 return true; 298 return true;
289 } 299 }
290 case htons(ETH_P_FCOE): 300 case htons(ETH_P_FCOE):
291 key_basic->thoff = (u16)(nhoff + FCOE_HEADER_LEN); 301 key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
292 /* fall through */ 302 /* fall through */
293 default: 303 default:
294 return false; 304 return false;
@@ -345,7 +355,7 @@ flow_label:
345 355
346 key_basic->n_proto = proto; 356 key_basic->n_proto = proto;
347 key_basic->ip_proto = ip_proto; 357 key_basic->ip_proto = ip_proto;
348 key_basic->thoff = (u16) nhoff; 358 key_control->thoff = (u16)nhoff;
349 359
350 if (skb_flow_dissector_uses_key(flow_dissector, 360 if (skb_flow_dissector_uses_key(flow_dissector,
351 FLOW_DISSECTOR_KEY_PORTS)) { 361 FLOW_DISSECTOR_KEY_PORTS)) {
@@ -366,9 +376,21 @@ static __always_inline void __flow_hash_secret_init(void)
366 net_get_random_once(&hashrnd, sizeof(hashrnd)); 376 net_get_random_once(&hashrnd, sizeof(hashrnd));
367} 377}
368 378
369static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c, u32 keyval) 379static __always_inline u32 __flow_hash_words(u32 *words, u32 length, u32 keyval)
380{
381 return jhash2(words, length, keyval);
382}
383
384static inline void *flow_keys_hash_start(struct flow_keys *flow)
370{ 385{
371 return jhash_3words(a, b, c, keyval); 386 BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
387 return (void *)flow + FLOW_KEYS_HASH_OFFSET;
388}
389
390static inline size_t flow_keys_hash_length(struct flow_keys *flow)
391{
392 BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
393 return (sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) / sizeof(u32);
372} 394}
373 395
374static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) 396static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
@@ -383,10 +405,8 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval)
383 swap(keys->ports.src, keys->ports.dst); 405 swap(keys->ports.src, keys->ports.dst);
384 } 406 }
385 407
386 hash = __flow_hash_3words((__force u32)keys->addrs.dst, 408 hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys),
387 (__force u32)keys->addrs.src, 409 flow_keys_hash_length(keys), keyval);
388 (__force u32)keys->ports.ports,
389 keyval);
390 if (!hash) 410 if (!hash)
391 hash = 1; 411 hash = 1;
392 412
@@ -473,7 +493,7 @@ EXPORT_SYMBOL(skb_get_hash_perturb);
473u32 __skb_get_poff(const struct sk_buff *skb, void *data, 493u32 __skb_get_poff(const struct sk_buff *skb, void *data,
474 const struct flow_keys *keys, int hlen) 494 const struct flow_keys *keys, int hlen)
475{ 495{
476 u32 poff = keys->basic.thoff; 496 u32 poff = keys->control.thoff;
477 497
478 switch (keys->basic.ip_proto) { 498 switch (keys->basic.ip_proto) {
479 case IPPROTO_TCP: { 499 case IPPROTO_TCP: {
@@ -537,6 +557,10 @@ u32 skb_get_poff(const struct sk_buff *skb)
537 557
538static const struct flow_dissector_key flow_keys_dissector_keys[] = { 558static const struct flow_dissector_key flow_keys_dissector_keys[] = {
539 { 559 {
560 .key_id = FLOW_DISSECTOR_KEY_CONTROL,
561 .offset = offsetof(struct flow_keys, control),
562 },
563 {
540 .key_id = FLOW_DISSECTOR_KEY_BASIC, 564 .key_id = FLOW_DISSECTOR_KEY_BASIC,
541 .offset = offsetof(struct flow_keys, basic), 565 .offset = offsetof(struct flow_keys, basic),
542 }, 566 },
@@ -556,6 +580,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = {
556 580
557static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { 581static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = {
558 { 582 {
583 .key_id = FLOW_DISSECTOR_KEY_CONTROL,
584 .offset = offsetof(struct flow_keys, control),
585 },
586 {
559 .key_id = FLOW_DISSECTOR_KEY_BASIC, 587 .key_id = FLOW_DISSECTOR_KEY_BASIC,
560 .offset = offsetof(struct flow_keys, basic), 588 .offset = offsetof(struct flow_keys, basic),
561 }, 589 },