[ovs-dev] [PATCH v2] datapath: Streamline tunnel port lookup

Pravin Shelar pshelar at nicira.com
Fri Sep 30 17:07:55 UTC 2011


Fixed according to comments from Jesse.
	- Use jhash2()
	- fixed for old kernel.

--8<--------------------------cut here-------------------------->8--

This change is meant to cleanup the tunnel lookup code. We are now using
kernel hash table so we can simplify `struct port_lookup_key`.

Signed-off-by: Pravin B Shelar <pshelar at nicira.com>

---
 datapath/tunnel.c    |  116 +++++++++++++++++++------------------------------
 datapath/tunnel.h    |   15 +++++--
 datapath/vport-gre.c |    2 +-
 3 files changed, 57 insertions(+), 76 deletions(-)

diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 67fbd2b..730b5b9 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -74,6 +74,8 @@
 static struct hlist_head *port_table __read_mostly;
 static int port_table_count;
 
+static unsigned int hash_seed __read_mostly;
+
 static void cache_cleaner(struct work_struct *work);
 static DECLARE_DELAYED_WORK(cache_cleaner_wq, cache_cleaner);
 
@@ -160,61 +162,23 @@ static void assign_cache_rcu(struct vport *vport, struct tnl_cache *new_cache)
 static unsigned int *find_port_pool(const struct tnl_mutable_config *mutable)
 {
 	if (mutable->flags & TNL_F_IN_KEY_MATCH) {
-		if (mutable->saddr)
+		if (mutable->key.saddr)
 			return &local_remote_ports;
 		else
 			return &remote_ports;
 	} else {
-		if (mutable->saddr)
+		if (mutable->key.saddr)
 			return &key_local_remote_ports;
 		else
 			return &key_remote_ports;
 	}
 }
 
-struct port_lookup_key {
-	const struct tnl_mutable_config *mutable;
-	__be64 key;
-	u32 tunnel_type;
-	__be32 saddr;
-	__be32 daddr;
-};
-
-/*
- * Modifies 'target' to store the rcu_dereferenced pointer that was used to do
- * the comparision.
- */
-static int port_cmp(const struct tnl_vport *tnl_vport,
-                    struct port_lookup_key *lookup)
-{
-	lookup->mutable = rcu_dereference_rtnl(tnl_vport->mutable);
-
-	return (lookup->mutable->tunnel_type == lookup->tunnel_type &&
-		lookup->mutable->daddr == lookup->daddr &&
-		lookup->mutable->in_key == lookup->key &&
-		lookup->mutable->saddr == lookup->saddr);
-}
-
-static u32 port_hash(struct port_lookup_key *k)
+static u32 port_hash(const struct port_lookup_key *key)
 {
-	u32 x = jhash_3words((__force u32)k->saddr, (__force u32)k->daddr,
-			     k->tunnel_type, 0);
-	return jhash_2words((__force u64)k->key >> 32, (__force u32)k->key, x);
+	return jhash2((u32*)key, (sizeof(*key) / sizeof(u32)), hash_seed);
 }
 
-static u32 mutable_hash(const struct tnl_mutable_config *mutable)
-{
-	struct port_lookup_key lookup;
-
-	lookup.saddr = mutable->saddr;
-	lookup.daddr = mutable->daddr;
-	lookup.key = mutable->in_key;
-	lookup.tunnel_type = mutable->tunnel_type;
-
-	return port_hash(&lookup);
-}
-
-
 static inline struct hlist_head *find_bucket(u32 hash)
 {
 	return &port_table[(hash & (PORT_TABLE_SIZE - 1))];
@@ -223,11 +187,14 @@ static inline struct hlist_head *find_bucket(u32 hash)
 static void port_table_add_port(struct vport *vport)
 {
 	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-	u32 hash = mutable_hash(rtnl_dereference(tnl_vport->mutable));
+	const struct tnl_mutable_config *mutable;
+	u32 hash;
 
 	if (port_table_count == 0)
 		schedule_cache_cleaner();
 
+	mutable = rtnl_dereference(tnl_vport->mutable);
+	hash = port_hash(&mutable->key);
 	hlist_add_head_rcu(&tnl_vport->hash_node, find_bucket(hash));
 	port_table_count++;
 
@@ -240,7 +207,7 @@ static void port_table_move_port(struct vport *vport,
 	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
 	u32 hash;
 
-	hash = mutable_hash(new_mutable);
+	hash = port_hash(&new_mutable->key);
 	hlist_del_init_rcu(&tnl_vport->hash_node);
 	hlist_add_head_rcu(&tnl_vport->hash_node, find_bucket(hash));
 
@@ -262,18 +229,24 @@ static void port_table_remove_port(struct vport *vport)
 	(*find_port_pool(rtnl_dereference(tnl_vport->mutable)))--;
 }
 
-static struct tnl_vport *port_table_lookup(struct port_lookup_key *lookup)
+static struct tnl_vport *port_table_lookup(struct port_lookup_key *key,
+			    const struct tnl_mutable_config **pmutable)
 {
 	struct hlist_node *n;
 	struct hlist_head *bucket;
-	u32 hash = port_hash(lookup);
+	u32 hash = port_hash(key);
 	struct tnl_vport * tnl_vport;
 
 	bucket = find_bucket(hash);
 
 	hlist_for_each_entry_rcu(tnl_vport, n, bucket, hash_node) {
-		if (port_cmp(tnl_vport, lookup))
+		struct tnl_mutable_config *mutable;
+
+		mutable = rcu_dereference_rtnl(tnl_vport->mutable);
+		if (!memcmp(&mutable->key, key, sizeof(*key))) {
+			*pmutable = mutable;
 			return tnl_vport;
+		}
 	}
 
 	return NULL;
@@ -290,18 +263,18 @@ struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be64 key,
 	lookup.daddr = daddr;
 
 	if (tunnel_type & TNL_T_KEY_EXACT) {
-		lookup.key = key;
+		lookup.in_key = key;
 		lookup.tunnel_type = tunnel_type & ~TNL_T_KEY_MATCH;
 
 		if (key_local_remote_ports) {
-			tnl_vport = port_table_lookup(&lookup);
+			tnl_vport = port_table_lookup(&lookup, mutable);
 			if (tnl_vport)
 				goto found;
 		}
 
 		if (key_remote_ports) {
 			lookup.saddr = 0;
-			tnl_vport = port_table_lookup(&lookup);
+			tnl_vport = port_table_lookup(&lookup, mutable);
 			if (tnl_vport)
 				goto found;
 
@@ -310,18 +283,18 @@ struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be64 key,
 	}
 
 	if (tunnel_type & TNL_T_KEY_MATCH) {
-		lookup.key = 0;
+		lookup.in_key = 0;
 		lookup.tunnel_type = tunnel_type & ~TNL_T_KEY_EXACT;
 
 		if (local_remote_ports) {
-			tnl_vport = port_table_lookup(&lookup);
+			tnl_vport = port_table_lookup(&lookup, mutable);
 			if (tnl_vport)
 				goto found;
 		}
 
 		if (remote_ports) {
 			lookup.saddr = 0;
-			tnl_vport = port_table_lookup(&lookup);
+			tnl_vport = port_table_lookup(&lookup, mutable);
 			if (tnl_vport)
 				goto found;
 		}
@@ -330,7 +303,6 @@ struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be64 key,
 	return NULL;
 
 found:
-	*mutable = lookup.mutable;
 	return tnl_vport_to_vport(tnl_vport);
 }
 
@@ -965,16 +937,16 @@ static struct rtable *find_route(struct vport *vport,
 		struct rtable *rt;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
 		struct flowi fl = { .nl_u = { .ip4_u =
-					      { .daddr = mutable->daddr,
-						.saddr = mutable->saddr,
+					      { .daddr = mutable->key.daddr,
+						.saddr = mutable->key.saddr,
 						.tos = tos } },
 				    .proto = tnl_vport->tnl_ops->ipproto };
 
 		if (unlikely(ip_route_output_key(&init_net, &rt, &fl)))
 			return NULL;
 #else
-		struct flowi4 fl = { .daddr = mutable->daddr,
-				     .saddr = mutable->saddr,
+		struct flowi4 fl = { .daddr = mutable->key.daddr,
+				     .saddr = mutable->key.saddr,
 				     .flowi4_tos = tos,
 				     .flowi4_proto = tnl_vport->tnl_ops->ipproto };
 
@@ -1327,8 +1299,8 @@ static int tnl_set_config(struct nlattr *options, const struct tnl_ops *tnl_ops,
 	mutable->flags = nla_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_PUBLIC;
 
 	if (a[OVS_TUNNEL_ATTR_SRC_IPV4])
-		mutable->saddr = nla_get_be32(a[OVS_TUNNEL_ATTR_SRC_IPV4]);
-	mutable->daddr = nla_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
+		mutable->key.saddr = nla_get_be32(a[OVS_TUNNEL_ATTR_SRC_IPV4]);
+	mutable->key.daddr = nla_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
 
 	if (a[OVS_TUNNEL_ATTR_TOS]) {
 		mutable->tos = nla_get_u8(a[OVS_TUNNEL_ATTR_TOS]);
@@ -1339,13 +1311,13 @@ static int tnl_set_config(struct nlattr *options, const struct tnl_ops *tnl_ops,
 	if (a[OVS_TUNNEL_ATTR_TTL])
 		mutable->ttl = nla_get_u8(a[OVS_TUNNEL_ATTR_TTL]);
 
-	mutable->tunnel_type = tnl_ops->tunnel_type;
+	mutable->key.tunnel_type = tnl_ops->tunnel_type;
 	if (!a[OVS_TUNNEL_ATTR_IN_KEY]) {
-		mutable->tunnel_type |= TNL_T_KEY_MATCH;
+		mutable->key.tunnel_type |= TNL_T_KEY_MATCH;
 		mutable->flags |= TNL_F_IN_KEY_MATCH;
 	} else {
-		mutable->tunnel_type |= TNL_T_KEY_EXACT;
-		mutable->in_key = nla_get_be64(a[OVS_TUNNEL_ATTR_IN_KEY]);
+		mutable->key.tunnel_type |= TNL_T_KEY_EXACT;
+		mutable->key.in_key = nla_get_be64(a[OVS_TUNNEL_ATTR_IN_KEY]);
 	}
 
 	if (!a[OVS_TUNNEL_ATTR_OUT_KEY])
@@ -1359,8 +1331,8 @@ static int tnl_set_config(struct nlattr *options, const struct tnl_ops *tnl_ops,
 
 	mutable->tunnel_hlen += sizeof(struct iphdr);
 
-	old_vport = tnl_find_port(mutable->saddr, mutable->daddr,
-				  mutable->in_key, mutable->tunnel_type,
+	old_vport = tnl_find_port(mutable->key.saddr, mutable->key.daddr,
+				  mutable->key.in_key, mutable->key.tunnel_type,
 				  &old_mutable);
 
 	if (old_vport && old_vport != cur_vport)
@@ -1448,7 +1420,7 @@ int tnl_set_options(struct vport *vport, struct nlattr *options)
 	if (err)
 		goto error_free;
 
-	if (mutable_hash(mutable) != mutable_hash(old_mutable))
+	if (port_hash(&mutable->key) != port_hash(&old_mutable->key))
 		port_table_move_port(vport, mutable);
 
 	return 0;
@@ -1465,14 +1437,14 @@ int tnl_get_options(const struct vport *vport, struct sk_buff *skb)
 	const struct tnl_mutable_config *mutable = rcu_dereference_rtnl(tnl_vport->mutable);
 
 	NLA_PUT_U32(skb, OVS_TUNNEL_ATTR_FLAGS, mutable->flags & TNL_F_PUBLIC);
-	NLA_PUT_BE32(skb, OVS_TUNNEL_ATTR_DST_IPV4, mutable->daddr);
+	NLA_PUT_BE32(skb, OVS_TUNNEL_ATTR_DST_IPV4, mutable->key.daddr);
 
 	if (!(mutable->flags & TNL_F_IN_KEY_MATCH))
-		NLA_PUT_BE64(skb, OVS_TUNNEL_ATTR_IN_KEY, mutable->in_key);
+		NLA_PUT_BE64(skb, OVS_TUNNEL_ATTR_IN_KEY, mutable->key.in_key);
 	if (!(mutable->flags & TNL_F_OUT_KEY_ACTION))
 		NLA_PUT_BE64(skb, OVS_TUNNEL_ATTR_OUT_KEY, mutable->out_key);
-	if (mutable->saddr)
-		NLA_PUT_BE32(skb, OVS_TUNNEL_ATTR_SRC_IPV4, mutable->saddr);
+	if (mutable->key.saddr)
+		NLA_PUT_BE32(skb, OVS_TUNNEL_ATTR_SRC_IPV4, mutable->key.saddr);
 	if (mutable->tos)
 		NLA_PUT_U8(skb, OVS_TUNNEL_ATTR_TOS, mutable->tos);
 	if (mutable->ttl)
@@ -1553,6 +1525,8 @@ int tnl_init(void)
 	for (i = 0; i < PORT_TABLE_SIZE; i++)
 		INIT_HLIST_HEAD(&port_table[i]);
 
+	get_random_bytes(&hash_seed, sizeof(hash_seed));
+
 	return 0;
 }
 
diff --git a/datapath/tunnel.h b/datapath/tunnel.h
index a051495..1790c16 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -45,6 +45,16 @@
 		      TNL_F_HDR_CACHE | TNL_F_IPSEC)
 
 /**
+ * Tunnel port key, used as hash table key.
+ */
+struct port_lookup_key {
+	__be64 in_key;
+	u32 tunnel_type;
+	__be32 saddr;
+	__be32 daddr;
+};
+
+/**
  * struct tnl_mutable_config - modifiable configuration for a tunnel.
  * @rcu: RCU callback head for deferred destruction.
  * @seq: Sequence number for distinguishing configuration versions.
@@ -61,21 +71,18 @@
  * @ttl: IPv4 TTL value to use for tunnel, 0 if no fixed TTL.
  */
 struct tnl_mutable_config {
+	struct port_lookup_key key;
 	struct rcu_head rcu;
 
 	unsigned seq;
 
-	u32 tunnel_type;
 	unsigned tunnel_hlen;
 
 	unsigned char eth_addr[ETH_ALEN];
 
 	/* Configured via OVS_TUNNEL_ATTR_* attributes. */
-	__be64	in_key;
 	__be64	out_key;
 	u32	flags;
-	__be32	saddr;
-	__be32	daddr;
 	u8	tos;
 	u8	ttl;
 };
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index 5beae42..8775d38 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -207,7 +207,7 @@ static void gre_err(struct sk_buff *skb, u32 info)
 	 * out key as if it were the in key and then check to see if the input
 	 * and output keys are the same.
 	 */
-	if (mutable->in_key != mutable->out_key)
+	if (mutable->key.in_key != mutable->out_key)
 		return;
 
 	if (!!(mutable->flags & TNL_F_IN_KEY_MATCH) !=
-- 
1.7.1




More information about the dev mailing list