]>
Commit | Line | Data |
---|---|---|
23de047c GKH |
1 | From foo@baz Thu Jul 14 07:36:41 JST 2016 |
2 | From: "David S. Miller" <davem@davemloft.net> | |
3 | Date: Fri, 1 Jul 2016 16:07:50 -0400 | |
4 | Subject: packet: Use symmetric hash for PACKET_FANOUT_HASH. | |
5 | ||
6 | From: "David S. Miller" <davem@davemloft.net> | |
7 | ||
8 | [ Upstream commit eb70db8756717b90c01ccc765fdefc4dd969fc74 ] | |
9 | ||
10 | People who use PACKET_FANOUT_HASH want a symmetric hash, meaning that | |
11 | they want packets going in both directions on a flow to hash to the | |
12 | same bucket. | |
13 | ||
14 | The core kernel SKB hash became non-symmetric when the ipv6 flow label | |
15 | and other entities were incorporated into the standard flow hash order | |
16 | to increase entropy. | |
17 | ||
18 | But there are no users of PACKET_FANOUT_HASH who want an assymetric | |
19 | hash, they all want a symmetric one. | |
20 | ||
21 | Therefore, use the flow dissector to compute a flat symmetric hash | |
22 | over only the protocol, addresses and ports. This hash does not get | |
23 | installed into and override the normal skb hash, so this change has | |
24 | no effect whatsoever on the rest of the stack. | |
25 | ||
26 | Reported-by: Eric Leblond <eric@regit.org> | |
27 | Tested-by: Eric Leblond <eric@regit.org> | |
28 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
29 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
30 | --- | |
31 | include/linux/skbuff.h | 1 + | |
32 | net/core/flow_dissector.c | 43 +++++++++++++++++++++++++++++++++++++++++++ | |
33 | net/packet/af_packet.c | 2 +- | |
34 | 3 files changed, 45 insertions(+), 1 deletion(-) | |
35 | ||
36 | --- a/include/linux/skbuff.h | |
37 | +++ b/include/linux/skbuff.h | |
38 | @@ -1062,6 +1062,7 @@ __skb_set_sw_hash(struct sk_buff *skb, _ | |
39 | } | |
40 | ||
41 | void __skb_get_hash(struct sk_buff *skb); | |
42 | +u32 __skb_get_hash_symmetric(struct sk_buff *skb); | |
43 | u32 skb_get_poff(const struct sk_buff *skb); | |
44 | u32 __skb_get_poff(const struct sk_buff *skb, void *data, | |
45 | const struct flow_keys *keys, int hlen); | |
46 | --- a/net/core/flow_dissector.c | |
47 | +++ b/net/core/flow_dissector.c | |
48 | @@ -651,6 +651,23 @@ void make_flow_keys_digest(struct flow_k | |
49 | } | |
50 | EXPORT_SYMBOL(make_flow_keys_digest); | |
51 | ||
52 | +static struct flow_dissector flow_keys_dissector_symmetric __read_mostly; | |
53 | + | |
54 | +u32 __skb_get_hash_symmetric(struct sk_buff *skb) | |
55 | +{ | |
56 | + struct flow_keys keys; | |
57 | + | |
58 | + __flow_hash_secret_init(); | |
59 | + | |
60 | + memset(&keys, 0, sizeof(keys)); | |
61 | + __skb_flow_dissect(skb, &flow_keys_dissector_symmetric, &keys, | |
62 | + NULL, 0, 0, 0, | |
63 | + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); | |
64 | + | |
65 | + return __flow_hash_from_keys(&keys, hashrnd); | |
66 | +} | |
67 | +EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); | |
68 | + | |
69 | /** | |
70 | * __skb_get_hash: calculate a flow hash | |
71 | * @skb: sk_buff to calculate flow hash from | |
72 | @@ -868,6 +885,29 @@ static const struct flow_dissector_key f | |
73 | }, | |
74 | }; | |
75 | ||
76 | +static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = { | |
77 | + { | |
78 | + .key_id = FLOW_DISSECTOR_KEY_CONTROL, | |
79 | + .offset = offsetof(struct flow_keys, control), | |
80 | + }, | |
81 | + { | |
82 | + .key_id = FLOW_DISSECTOR_KEY_BASIC, | |
83 | + .offset = offsetof(struct flow_keys, basic), | |
84 | + }, | |
85 | + { | |
86 | + .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, | |
87 | + .offset = offsetof(struct flow_keys, addrs.v4addrs), | |
88 | + }, | |
89 | + { | |
90 | + .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, | |
91 | + .offset = offsetof(struct flow_keys, addrs.v6addrs), | |
92 | + }, | |
93 | + { | |
94 | + .key_id = FLOW_DISSECTOR_KEY_PORTS, | |
95 | + .offset = offsetof(struct flow_keys, ports), | |
96 | + }, | |
97 | +}; | |
98 | + | |
99 | static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { | |
100 | { | |
101 | .key_id = FLOW_DISSECTOR_KEY_CONTROL, | |
102 | @@ -889,6 +929,9 @@ static int __init init_default_flow_diss | |
103 | skb_flow_dissector_init(&flow_keys_dissector, | |
104 | flow_keys_dissector_keys, | |
105 | ARRAY_SIZE(flow_keys_dissector_keys)); | |
106 | + skb_flow_dissector_init(&flow_keys_dissector_symmetric, | |
107 | + flow_keys_dissector_symmetric_keys, | |
108 | + ARRAY_SIZE(flow_keys_dissector_symmetric_keys)); | |
109 | skb_flow_dissector_init(&flow_keys_buf_dissector, | |
110 | flow_keys_buf_dissector_keys, | |
111 | ARRAY_SIZE(flow_keys_buf_dissector_keys)); | |
112 | --- a/net/packet/af_packet.c | |
113 | +++ b/net/packet/af_packet.c | |
114 | @@ -1340,7 +1340,7 @@ static unsigned int fanout_demux_hash(st | |
115 | struct sk_buff *skb, | |
116 | unsigned int num) | |
117 | { | |
118 | - return reciprocal_scale(skb_get_hash(skb), num); | |
119 | + return reciprocal_scale(__skb_get_hash_symmetric(skb), num); | |
120 | } | |
121 | ||
122 | static unsigned int fanout_demux_lb(struct packet_fanout *f, |