aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTom Herbert <tom@herbertland.com>2015-06-04 12:16:40 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-04 18:44:30 -0400
commitc3f8324188fa80178f20c8209b492ca6191177e8 (patch)
tree7a79eea92ad702932fd81977118f6ab6394a9769 /net
parent42aecaa9bb2bd57eb8d61b4565cee5d3640863fb (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.c116
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/sched/cls_flow.c14
-rw-r--r--net/sched/cls_flower.c11
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
390static inline size_t flow_keys_hash_length(struct flow_keys *flow) 397static 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}
427EXPORT_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}
441EXPORT_SYMBOL(flow_get_u32_dst);
442
443static 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
396static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) 476static 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}
457EXPORT_SYMBOL(make_flow_keys_digest); 531EXPORT_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
69static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow) 69static 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
76static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow) 79static 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)) ||