From: Tom Herbert <tom@herbertland.com>
To: <davem@davemloft.net>, <netdev@vger.kernel.org>
Subject: [PATCH v4 net-next 04/11] net: Get skb hash over flow_keys structure
Date: Thu, 28 May 2015 11:19:01 -0700 [thread overview]
Message-ID: <1432837148-1359931-5-git-send-email-tom@herbertland.com> (raw)
In-Reply-To: <1432837148-1359931-1-git-send-email-tom@herbertland.com>
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>
---
include/linux/skbuff.h | 2 +-
include/net/flow_dissector.h | 21 ++++++++++++++---
include/net/ip.h | 2 ++
include/net/ipv6.h | 2 ++
net/core/flow_dissector.c | 54 +++++++++++++++++++++++++++++++++-----------
net/sched/cls_flower.c | 2 ++
6 files changed, 66 insertions(+), 17 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 6b41c15..cc612fc 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1943,7 +1943,7 @@ static inline void skb_probe_transport_header(struct sk_buff *skb,
if (skb_transport_header_was_set(skb))
return;
else if (skb_flow_dissect_flow_keys(skb, &keys))
- skb_set_transport_header(skb, keys.basic.thoff);
+ skb_set_transport_header(skb, keys.control.thoff);
else
skb_set_transport_header(skb, offset_hint);
}
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index bac9c14..cba6a10 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -7,15 +7,24 @@
#include <uapi/linux/if_ether.h>
/**
+ * struct flow_dissector_key_control:
+ * @thoff: Transport header offset
+ */
+struct flow_dissector_key_control {
+ u16 thoff;
+ u16 padding;
+};
+
+/**
* struct flow_dissector_key_basic:
* @thoff: Transport header offset
* @n_proto: Network header protocol (eg. IPv4/IPv6)
* @ip_proto: Transport header protocol (eg. TCP/UDP)
*/
struct flow_dissector_key_basic {
- u16 thoff;
__be16 n_proto;
u8 ip_proto;
+ u8 padding;
};
/**
@@ -70,6 +79,7 @@ struct flow_dissector_key_eth_addrs {
};
enum flow_dissector_key_id {
+ FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */
FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */
FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_addrs */
FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS, /* struct flow_dissector_key_addrs */
@@ -109,11 +119,16 @@ static inline bool skb_flow_dissect(const struct sk_buff *skb,
}
struct flow_keys {
- struct flow_dissector_key_addrs addrs;
- struct flow_dissector_key_ports ports;
+ struct flow_dissector_key_control control;
+#define FLOW_KEYS_HASH_START_FIELD basic
struct flow_dissector_key_basic basic;
+ struct flow_dissector_key_ports ports;
+ struct flow_dissector_key_addrs addrs;
};
+#define FLOW_KEYS_HASH_OFFSET \
+ offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD)
+
extern struct flow_dissector flow_keys_dissector;
extern struct flow_dissector flow_keys_buf_dissector;
diff --git a/include/net/ip.h b/include/net/ip.h
index 9b976cf..16cfc87 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -360,6 +360,8 @@ static inline void inet_set_txhash(struct sock *sk)
struct inet_sock *inet = inet_sk(sk);
struct flow_keys keys;
+ memset(&keys, 0, sizeof(keys));
+
keys.addrs.src = inet->inet_saddr;
keys.addrs.dst = inet->inet_daddr;
keys.ports.src = inet->inet_sport;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 35d485c..474ca46 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -699,6 +699,8 @@ static inline void ip6_set_txhash(struct sock *sk)
struct ipv6_pinfo *np = inet6_sk(sk);
struct flow_keys keys;
+ memset(&keys, 0, sizeof(keys));
+
keys.addrs.src = (__force __be32)ipv6_addr_hash(&np->saddr);
keys.addrs.dst = (__force __be32)ipv6_addr_hash(&sk->sk_v6_daddr);
keys.ports.src = inet->inet_sport;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 0763795..55b5f29 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,
flow_dissector->offset[key->key_id] = key->offset;
}
- /* Ensure that the dissector always includes basic key. That way
- * we are able to avoid handling lack of it in fast path.
+ /* Ensure that the dissector always includes control and basic key.
+ * That way we are able to avoid handling lack of these in fast path.
*/
BUG_ON(!skb_flow_dissector_uses_key(flow_dissector,
+ FLOW_DISSECTOR_KEY_CONTROL));
+ BUG_ON(!skb_flow_dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_BASIC));
}
EXPORT_SYMBOL(skb_flow_dissector_init);
@@ -120,6 +122,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
void *target_container,
void *data, __be16 proto, int nhoff, int hlen)
{
+ struct flow_dissector_key_control *key_control;
struct flow_dissector_key_basic *key_basic;
struct flow_dissector_key_addrs *key_addrs;
struct flow_dissector_key_ports *key_ports;
@@ -132,6 +135,13 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
hlen = skb_headlen(skb);
}
+ /* It is ensured by skb_flow_dissector_init() that control key will
+ * be always present.
+ */
+ key_control = skb_flow_dissector_target(flow_dissector,
+ FLOW_DISSECTOR_KEY_CONTROL,
+ target_container);
+
/* It is ensured by skb_flow_dissector_init() that basic key will
* be always present.
*/
@@ -219,7 +229,7 @@ flow_label:
key_basic->n_proto = proto;
key_basic->ip_proto = ip_proto;
- key_basic->thoff = (u16)nhoff;
+ key_control->thoff = (u16)nhoff;
if (skb_flow_dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_PORTS)) {
@@ -275,7 +285,7 @@ flow_label:
if (!hdr)
return false;
key_basic->n_proto = proto;
- key_basic->thoff = (u16)nhoff;
+ key_control->thoff = (u16)nhoff;
if (skb_flow_dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_IPV6_HASH_ADDRS)) {
@@ -288,7 +298,7 @@ flow_label:
return true;
}
case htons(ETH_P_FCOE):
- key_basic->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
+ key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
/* fall through */
default:
return false;
@@ -345,7 +355,7 @@ flow_label:
key_basic->n_proto = proto;
key_basic->ip_proto = ip_proto;
- key_basic->thoff = (u16) nhoff;
+ key_control->thoff = (u16)nhoff;
if (skb_flow_dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_PORTS)) {
@@ -366,9 +376,21 @@ static __always_inline void __flow_hash_secret_init(void)
net_get_random_once(&hashrnd, sizeof(hashrnd));
}
-static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c, u32 keyval)
+static __always_inline u32 __flow_hash_words(u32 *words, u32 length, u32 keyval)
+{
+ return jhash2(words, length, keyval);
+}
+
+static inline void *flow_keys_hash_start(struct flow_keys *flow)
{
- return jhash_3words(a, b, c, keyval);
+ BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32));
+ return (void *)flow + FLOW_KEYS_HASH_OFFSET;
+}
+
+static inline size_t flow_keys_hash_length(struct flow_keys *flow)
+{
+ BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
+ return (sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) / sizeof(u32);
}
static 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)
swap(keys->ports.src, keys->ports.dst);
}
- hash = __flow_hash_3words((__force u32)keys->addrs.dst,
- (__force u32)keys->addrs.src,
- (__force u32)keys->ports.ports,
- keyval);
+ hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys),
+ flow_keys_hash_length(keys), keyval);
if (!hash)
hash = 1;
@@ -473,7 +493,7 @@ EXPORT_SYMBOL(skb_get_hash_perturb);
u32 __skb_get_poff(const struct sk_buff *skb, void *data,
const struct flow_keys *keys, int hlen)
{
- u32 poff = keys->basic.thoff;
+ u32 poff = keys->control.thoff;
switch (keys->basic.ip_proto) {
case IPPROTO_TCP: {
@@ -537,6 +557,10 @@ u32 skb_get_poff(const struct sk_buff *skb)
static const struct flow_dissector_key flow_keys_dissector_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),
},
@@ -556,6 +580,10 @@ static const struct flow_dissector_key flow_keys_dissector_keys[] = {
static const struct flow_dissector_key flow_keys_buf_dissector_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),
},
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 8c8f34e..5a7d66c 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -25,6 +25,7 @@
struct fl_flow_key {
int indev_ifindex;
+ struct flow_dissector_key_control control;
struct flow_dissector_key_basic basic;
struct flow_dissector_key_eth_addrs eth;
union {
@@ -347,6 +348,7 @@ static void fl_init_dissector(struct cls_fl_head *head,
struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
size_t cnt = 0;
+ FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
FL_KEY_SET_IF_IN_RANGE(mask, keys, cnt,
FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
--
1.8.1
next prev parent reply other threads:[~2015-05-28 18:19 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-28 18:18 [PATCH v4 net-next 00/11] net: Increase inputs to flow_keys hashing Tom Herbert
2015-05-28 18:18 ` [PATCH v4 net-next 01/11] net: Simplify GRE case in flow_dissector Tom Herbert
2015-05-28 18:18 ` [PATCH v4 net-next 02/11] mpls: Add definition for IPPROTO_MPLS Tom Herbert
2015-05-28 18:19 ` [PATCH v4 net-next 03/11] net: Remove superfluous setting of key_basic Tom Herbert
2015-05-28 18:19 ` Tom Herbert [this message]
2015-05-28 18:19 ` [PATCH v4 net-next 05/11] net: Add full IPv6 addresses to flow_keys Tom Herbert
2015-05-28 21:44 ` Eric Dumazet
2015-05-28 22:38 ` Tom Herbert
2015-05-28 18:19 ` [PATCH v4 net-next 06/11] net: Add keys for TIPC address Tom Herbert
2015-05-28 18:19 ` [PATCH v4 net-next 07/11] net: Get rid of IPv6 hash addresses flow keys Tom Herbert
2015-05-28 18:19 ` [PATCH v4 net-next 08/11] net: Add VLAN ID to flow_keys Tom Herbert
2015-05-28 18:19 ` [PATCH v4 net-next 09/11] net: Add IPv6 flow label " Tom Herbert
2015-05-29 0:36 ` Eric Dumazet
2015-05-28 18:19 ` [PATCH v4 net-next 10/11] net: Add GRE keyid in flow_keys Tom Herbert
2015-05-28 18:19 ` [PATCH v4 net-next 11/11] mpls: Add MPLS entropy label " Tom Herbert
2015-05-31 6:40 ` [PATCH v4 net-next 00/11] net: Increase inputs to flow_keys hashing David Miller
-- strict thread matches above, loose matches on Subject: below --
2015-05-22 0:11 Tom Herbert
2015-05-22 0:11 ` [PATCH v4 net-next 04/11] net: Get skb hash over flow_keys structure Tom Herbert
2015-05-22 6:52 ` Jiri Pirko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1432837148-1359931-5-git-send-email-tom@herbertland.com \
--to=tom@herbertland.com \
--cc=davem@davemloft.net \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).