diff options
author | Tom Herbert <tom@herbertland.com> | 2015-06-04 12:16:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-06-04 18:44:30 -0400 |
commit | c3f8324188fa80178f20c8209b492ca6191177e8 (patch) | |
tree | 7a79eea92ad702932fd81977118f6ab6394a9769 /net | |
parent | 42aecaa9bb2bd57eb8d61b4565cee5d3640863fb (diff) |
net: Add full IPv6 addresses to flow_keys
This patch adds full IPv6 addresses into flow_keys and uses them as
input to the flow hash function. The implementation supports either
IPv4 or IPv6 addresses in a union, and selector is used to determine
how may words to input to jhash2.
We also add flow_get_u32_dst and flow_get_u32_src functions which are
used to get a u32 representation of the source and destination
addresses. For IPv6, ipv6_addr_hash is called. These functions retain
getting the legacy values of src and dst in flow_keys.
With this patch, Ethertype and IP protocol are now included in the
flow hash input.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/flow_dissector.c | 116 | ||||
-rw-r--r-- | net/ethernet/eth.c | 2 | ||||
-rw-r--r-- | net/sched/cls_flow.c | 14 | ||||
-rw-r--r-- | net/sched/cls_flower.c | 11 |
4 files changed, 114 insertions, 29 deletions
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 55b5f2962afa..ca9d22488cfb 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
@@ -178,10 +178,12 @@ ip: | |||
178 | if (!skb_flow_dissector_uses_key(flow_dissector, | 178 | if (!skb_flow_dissector_uses_key(flow_dissector, |
179 | FLOW_DISSECTOR_KEY_IPV4_ADDRS)) | 179 | FLOW_DISSECTOR_KEY_IPV4_ADDRS)) |
180 | break; | 180 | break; |
181 | |||
181 | key_addrs = skb_flow_dissector_target(flow_dissector, | 182 | key_addrs = skb_flow_dissector_target(flow_dissector, |
182 | FLOW_DISSECTOR_KEY_IPV4_ADDRS, | 183 | FLOW_DISSECTOR_KEY_IPV4_ADDRS, target_container); |
183 | target_container); | 184 | memcpy(&key_addrs->v4addrs, &iph->saddr, |
184 | memcpy(key_addrs, &iph->saddr, sizeof(*key_addrs)); | 185 | sizeof(key_addrs->v4addrs)); |
186 | key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; | ||
185 | break; | 187 | break; |
186 | } | 188 | } |
187 | case htons(ETH_P_IPV6): { | 189 | case htons(ETH_P_IPV6): { |
@@ -203,8 +205,11 @@ ipv6: | |||
203 | FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, | 205 | FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, |
204 | target_container); | 206 | target_container); |
205 | 207 | ||
206 | key_addrs->src = (__force __be32)ipv6_addr_hash(&iph->saddr); | 208 | key_addrs->v4addrs.src = |
207 | key_addrs->dst = (__force __be32)ipv6_addr_hash(&iph->daddr); | 209 | (__force __be32)ipv6_addr_hash(&iph->saddr); |
210 | key_addrs->v4addrs.dst = | ||
211 | (__force __be32)ipv6_addr_hash(&iph->daddr); | ||
212 | key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; | ||
208 | goto flow_label; | 213 | goto flow_label; |
209 | } | 214 | } |
210 | if (skb_flow_dissector_uses_key(flow_dissector, | 215 | if (skb_flow_dissector_uses_key(flow_dissector, |
@@ -216,6 +221,7 @@ ipv6: | |||
216 | target_container); | 221 | target_container); |
217 | 222 | ||
218 | memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs)); | 223 | memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs)); |
224 | key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; | ||
219 | goto flow_label; | 225 | goto flow_label; |
220 | } | 226 | } |
221 | break; | 227 | break; |
@@ -292,8 +298,9 @@ flow_label: | |||
292 | key_addrs = skb_flow_dissector_target(flow_dissector, | 298 | key_addrs = skb_flow_dissector_target(flow_dissector, |
293 | FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, | 299 | FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, |
294 | target_container); | 300 | target_container); |
295 | key_addrs->src = hdr->srcnode; | 301 | key_addrs->v4addrs.src = hdr->srcnode; |
296 | key_addrs->dst = 0; | 302 | key_addrs->v4addrs.dst = 0; |
303 | key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; | ||
297 | } | 304 | } |
298 | return true; | 305 | return true; |
299 | } | 306 | } |
@@ -389,21 +396,88 @@ static inline void *flow_keys_hash_start(struct flow_keys *flow) | |||
389 | 396 | ||
390 | static inline size_t flow_keys_hash_length(struct flow_keys *flow) | 397 | static inline size_t flow_keys_hash_length(struct flow_keys *flow) |
391 | { | 398 | { |
399 | size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); | ||
392 | BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); | 400 | BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); |
393 | return (sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) / sizeof(u32); | 401 | BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != |
402 | sizeof(*flow) - sizeof(flow->addrs)); | ||
403 | |||
404 | switch (flow->control.addr_type) { | ||
405 | case FLOW_DISSECTOR_KEY_IPV4_ADDRS: | ||
406 | diff -= sizeof(flow->addrs.v4addrs); | ||
407 | break; | ||
408 | case FLOW_DISSECTOR_KEY_IPV6_ADDRS: | ||
409 | diff -= sizeof(flow->addrs.v6addrs); | ||
410 | break; | ||
411 | } | ||
412 | return (sizeof(*flow) - diff) / sizeof(u32); | ||
413 | } | ||
414 | |||
415 | __be32 flow_get_u32_src(const struct flow_keys *flow) | ||
416 | { | ||
417 | switch (flow->control.addr_type) { | ||
418 | case FLOW_DISSECTOR_KEY_IPV4_ADDRS: | ||
419 | return flow->addrs.v4addrs.src; | ||
420 | case FLOW_DISSECTOR_KEY_IPV6_ADDRS: | ||
421 | return (__force __be32)ipv6_addr_hash( | ||
422 | &flow->addrs.v6addrs.src); | ||
423 | default: | ||
424 | return 0; | ||
425 | } | ||
426 | } | ||
427 | EXPORT_SYMBOL(flow_get_u32_src); | ||
428 | |||
429 | __be32 flow_get_u32_dst(const struct flow_keys *flow) | ||
430 | { | ||
431 | switch (flow->control.addr_type) { | ||
432 | case FLOW_DISSECTOR_KEY_IPV4_ADDRS: | ||
433 | return flow->addrs.v4addrs.dst; | ||
434 | case FLOW_DISSECTOR_KEY_IPV6_ADDRS: | ||
435 | return (__force __be32)ipv6_addr_hash( | ||
436 | &flow->addrs.v6addrs.dst); | ||
437 | default: | ||
438 | return 0; | ||
439 | } | ||
440 | } | ||
441 | EXPORT_SYMBOL(flow_get_u32_dst); | ||
442 | |||
443 | static inline void __flow_hash_consistentify(struct flow_keys *keys) | ||
444 | { | ||
445 | int addr_diff, i; | ||
446 | |||
447 | switch (keys->control.addr_type) { | ||
448 | case FLOW_DISSECTOR_KEY_IPV4_ADDRS: | ||
449 | addr_diff = (__force u32)keys->addrs.v4addrs.dst - | ||
450 | (__force u32)keys->addrs.v4addrs.src; | ||
451 | if ((addr_diff < 0) || | ||
452 | (addr_diff == 0 && | ||
453 | ((__force u16)keys->ports.dst < | ||
454 | (__force u16)keys->ports.src))) { | ||
455 | swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst); | ||
456 | swap(keys->ports.src, keys->ports.dst); | ||
457 | } | ||
458 | break; | ||
459 | case FLOW_DISSECTOR_KEY_IPV6_ADDRS: | ||
460 | addr_diff = memcmp(&keys->addrs.v6addrs.dst, | ||
461 | &keys->addrs.v6addrs.src, | ||
462 | sizeof(keys->addrs.v6addrs.dst)); | ||
463 | if ((addr_diff < 0) || | ||
464 | (addr_diff == 0 && | ||
465 | ((__force u16)keys->ports.dst < | ||
466 | (__force u16)keys->ports.src))) { | ||
467 | for (i = 0; i < 4; i++) | ||
468 | swap(keys->addrs.v6addrs.src.s6_addr32[i], | ||
469 | keys->addrs.v6addrs.dst.s6_addr32[i]); | ||
470 | swap(keys->ports.src, keys->ports.dst); | ||
471 | } | ||
472 | break; | ||
473 | } | ||
394 | } | 474 | } |
395 | 475 | ||
396 | static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) | 476 | static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) |
397 | { | 477 | { |
398 | u32 hash; | 478 | u32 hash; |
399 | 479 | ||
400 | /* get a consistent hash (same value on both flow directions) */ | 480 | __flow_hash_consistentify(keys); |
401 | if (((__force u32)keys->addrs.dst < (__force u32)keys->addrs.src) || | ||
402 | (((__force u32)keys->addrs.dst == (__force u32)keys->addrs.src) && | ||
403 | ((__force u16)keys->ports.dst < (__force u16)keys->ports.src))) { | ||
404 | swap(keys->addrs.dst, keys->addrs.src); | ||
405 | swap(keys->ports.src, keys->ports.dst); | ||
406 | } | ||
407 | 481 | ||
408 | hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys), | 482 | hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys), |
409 | flow_keys_hash_length(keys), keyval); | 483 | flow_keys_hash_length(keys), keyval); |
@@ -451,8 +525,8 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, | |||
451 | data->n_proto = flow->basic.n_proto; | 525 | data->n_proto = flow->basic.n_proto; |
452 | data->ip_proto = flow->basic.ip_proto; | 526 | data->ip_proto = flow->basic.ip_proto; |
453 | data->ports = flow->ports.ports; | 527 | data->ports = flow->ports.ports; |
454 | data->src = flow->addrs.src; | 528 | data->src = flow->addrs.v4addrs.src; |
455 | data->dst = flow->addrs.dst; | 529 | data->dst = flow->addrs.v4addrs.dst; |
456 | } | 530 | } |
457 | EXPORT_SYMBOL(make_flow_keys_digest); | 531 | EXPORT_SYMBOL(make_flow_keys_digest); |
458 | 532 | ||
@@ -566,11 +640,15 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = { | |||
566 | }, | 640 | }, |
567 | { | 641 | { |
568 | .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, | 642 | .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, |
569 | .offset = offsetof(struct flow_keys, addrs), | 643 | .offset = offsetof(struct flow_keys, addrs.v4addrs), |
644 | }, | ||
645 | { | ||
646 | .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, | ||
647 | .offset = offsetof(struct flow_keys, addrs.v6addrs), | ||
570 | }, | 648 | }, |
571 | { | 649 | { |
572 | .key_id = FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, | 650 | .key_id = FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, |
573 | .offset = offsetof(struct flow_keys, addrs), | 651 | .offset = offsetof(struct flow_keys, addrs.v4addrs), |
574 | }, | 652 | }, |
575 | { | 653 | { |
576 | .key_id = FLOW_DISSECTOR_KEY_PORTS, | 654 | .key_id = FLOW_DISSECTOR_KEY_PORTS, |
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 7d0e239a6755..77e0f0e7a88e 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
@@ -133,7 +133,7 @@ u32 eth_get_headlen(void *data, unsigned int len) | |||
133 | /* parse any remaining L2/L3 headers, check for L4 */ | 133 | /* parse any remaining L2/L3 headers, check for L4 */ |
134 | if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, | 134 | if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, |
135 | sizeof(*eth), len)) | 135 | sizeof(*eth), len)) |
136 | return max_t(u32, keys.basic.thoff, sizeof(*eth)); | 136 | return max_t(u32, keys.control.thoff, sizeof(*eth)); |
137 | 137 | ||
138 | /* parse for any L4 headers */ | 138 | /* parse for any L4 headers */ |
139 | return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); | 139 | return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); |
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index b4359924846c..76bc3a20ffdb 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
@@ -68,15 +68,21 @@ static inline u32 addr_fold(void *addr) | |||
68 | 68 | ||
69 | static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow) | 69 | static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow) |
70 | { | 70 | { |
71 | if (flow->addrs.src) | 71 | __be32 src = flow_get_u32_src(flow); |
72 | return ntohl(flow->addrs.src); | 72 | |
73 | if (src) | ||
74 | return ntohl(src); | ||
75 | |||
73 | return addr_fold(skb->sk); | 76 | return addr_fold(skb->sk); |
74 | } | 77 | } |
75 | 78 | ||
76 | static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow) | 79 | static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow) |
77 | { | 80 | { |
78 | if (flow->addrs.dst) | 81 | __be32 dst = flow_get_u32_dst(flow); |
79 | return ntohl(flow->addrs.dst); | 82 | |
83 | if (dst) | ||
84 | return ntohl(dst); | ||
85 | |||
80 | return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); | 86 | return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb); |
81 | } | 87 | } |
82 | 88 | ||
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 5a7d66c59684..b92d3f49c23e 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c | |||
@@ -28,8 +28,9 @@ struct fl_flow_key { | |||
28 | struct flow_dissector_key_control control; | 28 | struct flow_dissector_key_control control; |
29 | struct flow_dissector_key_basic basic; | 29 | struct flow_dissector_key_basic basic; |
30 | struct flow_dissector_key_eth_addrs eth; | 30 | struct flow_dissector_key_eth_addrs eth; |
31 | struct flow_dissector_key_addrs ipaddrs; | ||
31 | union { | 32 | union { |
32 | struct flow_dissector_key_addrs ipv4; | 33 | struct flow_dissector_key_ipv4_addrs ipv4; |
33 | struct flow_dissector_key_ipv6_addrs ipv6; | 34 | struct flow_dissector_key_ipv6_addrs ipv6; |
34 | }; | 35 | }; |
35 | struct flow_dissector_key_ports tp; | 36 | struct flow_dissector_key_ports tp; |
@@ -260,14 +261,14 @@ static int fl_set_key(struct net *net, struct nlattr **tb, | |||
260 | &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, | 261 | &mask->basic.ip_proto, TCA_FLOWER_UNSPEC, |
261 | sizeof(key->basic.ip_proto)); | 262 | sizeof(key->basic.ip_proto)); |
262 | } | 263 | } |
263 | if (key->basic.n_proto == htons(ETH_P_IP)) { | 264 | if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { |
264 | fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, | 265 | fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, |
265 | &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, | 266 | &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, |
266 | sizeof(key->ipv4.src)); | 267 | sizeof(key->ipv4.src)); |
267 | fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, | 268 | fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST, |
268 | &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, | 269 | &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, |
269 | sizeof(key->ipv4.dst)); | 270 | sizeof(key->ipv4.dst)); |
270 | } else if (key->basic.n_proto == htons(ETH_P_IPV6)) { | 271 | } else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { |
271 | fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, | 272 | fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, |
272 | &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, | 273 | &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, |
273 | sizeof(key->ipv6.src)); | 274 | sizeof(key->ipv6.src)); |
@@ -610,7 +611,7 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, | |||
610 | sizeof(key->basic.ip_proto))) | 611 | sizeof(key->basic.ip_proto))) |
611 | goto nla_put_failure; | 612 | goto nla_put_failure; |
612 | 613 | ||
613 | if (key->basic.n_proto == htons(ETH_P_IP) && | 614 | if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS && |
614 | (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, | 615 | (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC, |
615 | &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, | 616 | &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK, |
616 | sizeof(key->ipv4.src)) || | 617 | sizeof(key->ipv4.src)) || |
@@ -618,7 +619,7 @@ static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, | |||
618 | &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, | 619 | &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK, |
619 | sizeof(key->ipv4.dst)))) | 620 | sizeof(key->ipv4.dst)))) |
620 | goto nla_put_failure; | 621 | goto nla_put_failure; |
621 | else if (key->basic.n_proto == htons(ETH_P_IPV6) && | 622 | else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS && |
622 | (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, | 623 | (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC, |
623 | &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, | 624 | &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK, |
624 | sizeof(key->ipv6.src)) || | 625 | sizeof(key->ipv6.src)) || |