| From foo@baz Thu Jul 14 07:36:31 JST 2016 |
| From: "David S. Miller" <davem@davemloft.net> |
| Date: Fri, 1 Jul 2016 16:07:50 -0400 |
| Subject: packet: Use symmetric hash for PACKET_FANOUT_HASH. |
| |
| From: "David S. Miller" <davem@davemloft.net> |
| |
| [ Upstream commit eb70db8756717b90c01ccc765fdefc4dd969fc74 ] |
| |
| People who use PACKET_FANOUT_HASH want a symmetric hash, meaning that |
| they want packets going in both directions on a flow to hash to the |
| same bucket. |
| |
| The core kernel SKB hash became non-symmetric when the ipv6 flow label |
| and other entities were incorporated into the standard flow hash order |
| to increase entropy. |
| |
| But there are no users of PACKET_FANOUT_HASH who want an assymetric |
| hash, they all want a symmetric one. |
| |
| Therefore, use the flow dissector to compute a flat symmetric hash |
| over only the protocol, addresses and ports. This hash does not get |
| installed into and override the normal skb hash, so this change has |
| no effect whatsoever on the rest of the stack. |
| |
| Reported-by: Eric Leblond <eric@regit.org> |
| Tested-by: Eric Leblond <eric@regit.org> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/skbuff.h | 1 + |
| net/core/flow_dissector.c | 43 +++++++++++++++++++++++++++++++++++++++++++ |
| net/packet/af_packet.c | 2 +- |
| 3 files changed, 45 insertions(+), 1 deletion(-) |
| |
| --- a/include/linux/skbuff.h |
| +++ b/include/linux/skbuff.h |
| @@ -982,6 +982,7 @@ __skb_set_sw_hash(struct sk_buff *skb, _ |
| } |
| |
| void __skb_get_hash(struct sk_buff *skb); |
| +u32 __skb_get_hash_symmetric(struct sk_buff *skb); |
| u32 skb_get_poff(const struct sk_buff *skb); |
| u32 __skb_get_poff(const struct sk_buff *skb, void *data, |
| const struct flow_keys *keys, int hlen); |
| --- a/net/core/flow_dissector.c |
| +++ b/net/core/flow_dissector.c |
| @@ -662,6 +662,23 @@ void make_flow_keys_digest(struct flow_k |
| } |
| EXPORT_SYMBOL(make_flow_keys_digest); |
| |
| +static struct flow_dissector flow_keys_dissector_symmetric __read_mostly; |
| + |
| +u32 __skb_get_hash_symmetric(struct sk_buff *skb) |
| +{ |
| + struct flow_keys keys; |
| + |
| + __flow_hash_secret_init(); |
| + |
| + memset(&keys, 0, sizeof(keys)); |
| + __skb_flow_dissect(skb, &flow_keys_dissector_symmetric, &keys, |
| + NULL, 0, 0, 0, |
| + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); |
| + |
| + return __flow_hash_from_keys(&keys, hashrnd); |
| +} |
| +EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); |
| + |
| /** |
| * __skb_get_hash: calculate a flow hash |
| * @skb: sk_buff to calculate flow hash from |
| @@ -874,6 +891,29 @@ static const struct flow_dissector_key f |
| }, |
| }; |
| |
| +static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = { |
| + { |
| + .key_id = FLOW_DISSECTOR_KEY_CONTROL, |
| + .offset = offsetof(struct flow_keys, control), |
| + }, |
| + { |
| + .key_id = FLOW_DISSECTOR_KEY_BASIC, |
| + .offset = offsetof(struct flow_keys, basic), |
| + }, |
| + { |
| + .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, |
| + .offset = offsetof(struct flow_keys, addrs.v4addrs), |
| + }, |
| + { |
| + .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, |
| + .offset = offsetof(struct flow_keys, addrs.v6addrs), |
| + }, |
| + { |
| + .key_id = FLOW_DISSECTOR_KEY_PORTS, |
| + .offset = offsetof(struct flow_keys, ports), |
| + }, |
| +}; |
| + |
| static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { |
| { |
| .key_id = FLOW_DISSECTOR_KEY_CONTROL, |
| @@ -895,6 +935,9 @@ static int __init init_default_flow_diss |
| skb_flow_dissector_init(&flow_keys_dissector, |
| flow_keys_dissector_keys, |
| ARRAY_SIZE(flow_keys_dissector_keys)); |
| + skb_flow_dissector_init(&flow_keys_dissector_symmetric, |
| + flow_keys_dissector_symmetric_keys, |
| + ARRAY_SIZE(flow_keys_dissector_symmetric_keys)); |
| skb_flow_dissector_init(&flow_keys_buf_dissector, |
| flow_keys_buf_dissector_keys, |
| ARRAY_SIZE(flow_keys_buf_dissector_keys)); |
| --- a/net/packet/af_packet.c |
| +++ b/net/packet/af_packet.c |
| @@ -1341,7 +1341,7 @@ static unsigned int fanout_demux_hash(st |
| struct sk_buff *skb, |
| unsigned int num) |
| { |
| - return reciprocal_scale(skb_get_hash(skb), num); |
| + return reciprocal_scale(__skb_get_hash_symmetric(skb), num); |
| } |
| |
| static unsigned int fanout_demux_lb(struct packet_fanout *f, |