[ovs-dev] [PATCH 2/2] datapath: Add flow matching for tunnel keys

Kyle Mestery kmestery at cisco.com
Tue Oct 9 18:49:12 UTC 2012


Move struct ovs_key_ipv4_tunnel to the top of sw_flow_key. Add a new
struct ovs_flow_hash, which contains both the key_len and the offset to
use when hashing. This allows the outer tunnel to be hashed and used when
looking up flows.

Signed-off-by: Kyle Mestery <kmestery at cisco.com>
---
 datapath/actions.c  |  1 +
 datapath/datapath.c | 33 +++++++++++++++++---------
 datapath/datapath.h |  1 +
 datapath/flow.c     | 68 ++++++++++++++++++++++++++++++++++-------------------
 datapath/flow.h     | 21 +++++++++++------
 datapath/tunnel.c   |  5 ++--
 6 files changed, 85 insertions(+), 44 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index fa8c10d..e430dfc 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -289,6 +289,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
 
 	upcall.cmd = OVS_PACKET_CMD_ACTION;
 	upcall.key = &OVS_CB(skb)->flow->key;
+	upcall.tun_key = &OVS_CB(skb)->flow->key.tun.tun_key;
 	upcall.userdata = NULL;
 	upcall.pid = 0;
 
diff --git a/datapath/datapath.c b/datapath/datapath.c
index d8a198e..b9f95dc 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -313,10 +313,12 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 
 	if (!OVS_CB(skb)->flow) {
 		struct sw_flow_key key;
+		struct sw_flow_hash flowhash;
 		int key_len;
 
 		/* Extract flow from 'skb' into 'key'. */
-		error = ovs_flow_extract(skb, p->port_no, &key, &key_len);
+		error = ovs_flow_extract(skb, p->port_no, &key, &key_len,
+					 &flowhash);
 		if (unlikely(error)) {
 			kfree_skb(skb);
 			return;
@@ -324,12 +326,13 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 
 		/* Look up flow. */
 		flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table),
-					   &key, key_len);
+					   &flowhash);
 		if (unlikely(!flow)) {
 			struct dp_upcall_info upcall;
 
 			upcall.cmd = OVS_PACKET_CMD_MISS;
 			upcall.key = &key;
+			upcall.tun_key = &key.tun.tun_key;
 			upcall.userdata = NULL;
 			upcall.pid = p->upcall_pid;
 			ovs_dp_upcall(dp, skb, &upcall);
@@ -747,6 +750,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	struct ovs_header *ovs_header = info->userhdr;
 	struct nlattr **a = info->attrs;
 	struct sw_flow_actions *acts;
+	struct sw_flow_hash flowhash;
 	struct sk_buff *packet;
 	struct sw_flow *flow;
 	struct datapath *dp;
@@ -787,7 +791,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	if (IS_ERR(flow))
 		goto err_kfree_skb;
 
-	err = ovs_flow_extract(packet, -1, &flow->key, &key_len);
+	err = ovs_flow_extract(packet, -1, &flow->key, &key_len, &flowhash);
 	if (err)
 		goto err_flow_put;
 
@@ -802,7 +806,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	if (err)
 		goto err_flow_put;
 
-	flow->hash = ovs_flow_hash(&flow->key, key_len);
+	flow->hash = ovs_flow_hash(&flowhash);
 
 	acts = ovs_flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]);
 	err = PTR_ERR(acts);
@@ -1017,6 +1021,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 	struct ovs_header *ovs_header = info->userhdr;
 	struct sw_flow_key key;
 	struct sw_flow *flow;
+	struct sw_flow_hash flowhash;
 	struct sk_buff *reply;
 	struct datapath *dp;
 	struct flow_table *table;
@@ -1027,7 +1032,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 	error = -EINVAL;
 	if (!a[OVS_FLOW_ATTR_KEY])
 		goto error;
-	error = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
+	error = ovs_flow_from_nlattrs(&key, &key_len, &flowhash,
+				      a[OVS_FLOW_ATTR_KEY]);
 	if (error)
 		goto error;
 
@@ -1047,7 +1053,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 		goto error;
 
 	table = genl_dereference(dp->table);
-	flow = ovs_flow_tbl_lookup(table, &key, key_len);
+	flow = ovs_flow_tbl_lookup(table, &flowhash);
 	if (!flow) {
 		struct sw_flow_actions *acts;
 
@@ -1085,7 +1091,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 		rcu_assign_pointer(flow->sf_acts, acts);
 
 		/* Put flow in bucket. */
-		flow->hash = ovs_flow_hash(&key, key_len);
+		flow->hash = ovs_flow_hash(&flowhash);
+		flow->flowhash = flowhash;
 		ovs_flow_tbl_insert(table, flow);
 
 		reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid,
@@ -1157,6 +1164,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 	struct nlattr **a = info->attrs;
 	struct ovs_header *ovs_header = info->userhdr;
 	struct sw_flow_key key;
+	struct sw_flow_hash flowhash;
 	struct sk_buff *reply;
 	struct sw_flow *flow;
 	struct datapath *dp;
@@ -1166,7 +1174,8 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 
 	if (!a[OVS_FLOW_ATTR_KEY])
 		return -EINVAL;
-	err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
+	err = ovs_flow_from_nlattrs(&key, &key_len, &flowhash,
+				    a[OVS_FLOW_ATTR_KEY]);
 	if (err)
 		return err;
 
@@ -1175,7 +1184,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 		return -ENODEV;
 
 	table = genl_dereference(dp->table);
-	flow = ovs_flow_tbl_lookup(table, &key, key_len);
+	flow = ovs_flow_tbl_lookup(table, &flowhash);
 	if (!flow)
 		return -ENOENT;
 
@@ -1192,6 +1201,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	struct nlattr **a = info->attrs;
 	struct ovs_header *ovs_header = info->userhdr;
 	struct sw_flow_key key;
+	struct sw_flow_hash flowhash;
 	struct sk_buff *reply;
 	struct sw_flow *flow;
 	struct datapath *dp;
@@ -1206,12 +1216,13 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	if (!a[OVS_FLOW_ATTR_KEY])
 		return flush_flows(dp);
 
-	err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
+	err = ovs_flow_from_nlattrs(&key, &key_len, &flowhash,
+				    a[OVS_FLOW_ATTR_KEY]);
 	if (err)
 		return err;
 
 	table = genl_dereference(dp->table);
-	flow = ovs_flow_tbl_lookup(table, &key, key_len);
+	flow = ovs_flow_tbl_lookup(table, &flowhash);
 	if (!flow)
 		return -ENOENT;
 
diff --git a/datapath/datapath.h b/datapath/datapath.h
index c5df12d..074aa85 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -132,6 +132,7 @@ struct ovs_skb_cb {
 struct dp_upcall_info {
 	u8 cmd;
 	const struct sw_flow_key *key;
+	const struct ovs_key_ipv4_tunnel *tun_key;
 	const struct nlattr *userdata;
 	u32 pid;
 };
diff --git a/datapath/flow.c b/datapath/flow.c
index 376f4be..c15b22c 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -620,17 +620,22 @@ out:
  *      For other key->dl_type values it is left untouched.
  */
 int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
-		 int *key_lenp)
+		 int *key_lenp, struct sw_flow_hash *flowhash)
 {
 	int error = 0;
 	int key_len = SW_FLOW_KEY_OFFSET(eth);
 	struct ethhdr *eth;
 
 	memset(key, 0, sizeof(*key));
+	memset(flowhash, 0, sizeof(*flowhash));
 
 	key->phy.priority = skb->priority;
-	if (OVS_CB(skb)->tun_key)
-		key->tun.tun_key = *OVS_CB(skb)->tun_key;
+	if (OVS_CB(skb)->tun_key) {
+		key->tun.tun_key = OVS_CB(skb)->flow->key.tun.tun_key;
+		flowhash->offset = (u32 *)&key->tun;
+	} else {
+		flowhash->offset = (u32 *)&key->phy;
+	}
 	key->phy.in_port = in_port;
 
 	skb_reset_mac_header(skb);
@@ -783,32 +788,32 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 	}
 
 out:
-	*key_lenp = key_len;
+	*key_lenp = flowhash->key_len = key_len;
 	return error;
 }
 
-u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len)
+u32 ovs_flow_hash(const struct sw_flow_hash *flowhash)
 {
-	return jhash2((u32 *)key, DIV_ROUND_UP(key_len, sizeof(u32)), 0);
+	return jhash2((u32 *)flowhash->offset, DIV_ROUND_UP(flowhash->key_len,
+		      sizeof(u32)), 0);
 }
 
 struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
-				struct sw_flow_key *key, int key_len)
+				struct sw_flow_hash *flowhash)
 {
 	struct sw_flow *flow;
 	struct hlist_node *n;
 	struct hlist_head *head;
 	u32 hash;
 
-	hash = ovs_flow_hash(key, key_len);
+	hash = ovs_flow_hash(flowhash);
 
 	head = find_bucket(table, hash);
 	hlist_for_each_entry_rcu(flow, n, head, hash_node[table->node_ver]) {
 
 		if (flow->hash == hash &&
-		    !memcmp(&flow->key, key, key_len)) {
+		    !memcmp(&flow->flowhash.offset, flowhash->offset, flowhash->key_len))
 			return flow;
-		}
 	}
 	return NULL;
 }
@@ -994,7 +999,7 @@ static int parse_flow_nlattrs(const struct nlattr *attr,
  * sequence.
  */
 int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
-		      const struct nlattr *attr)
+		      struct sw_flow_hash *flowhash, const struct nlattr *attr)
 {
 	const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
 	const struct ovs_key_ethernet *eth_key;
@@ -1003,6 +1008,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 	int err;
 
 	memset(swkey, 0, sizeof(struct sw_flow_key));
+	memset(flowhash, 0, sizeof(*flowhash));
 	key_len = SW_FLOW_KEY_OFFSET(eth);
 
 	err = parse_flow_nlattrs(attr, a, &attrs);
@@ -1024,30 +1030,35 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 		swkey->phy.in_port = DP_MAX_PORTS;
 	}
 
-	/* OVS_KEY_ATTR_TUN_ID and OVS_KEY_ATTR_IPV4_TUNEL must both arrive
+	/* OVS_KEY_ATTR_TUN_ID and OVS_KEY_ATTR_IPV4_TUNNEL must both arrive
 	 * together.
 	 */
-	if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
-	    attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
-		struct ovs_key_ipv4_tunnel *tun_key;
+	if ((attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) &&
+	    (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL))) {
+		struct ovs_key_ipv4_tunnel *tunnel_key;
 		__be64 tun_id = 0;
-		tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
+		tunnel_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
 		tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
 
-		if (tun_id != tun_key->tun_id)
+		if (tun_id != tunnel_key->tun_id)
 			return -EINVAL;
 
-		swkey->tun.tun_key = *tun_key;
+		swkey->tun.tun_key = *tunnel_key;
+		flowhash->offset = (u32 *)&swkey->tun;
 		attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
 		attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
 	} else if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) {
 		swkey->tun.tun_key.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
+		flowhash->offset = (u32 *)&swkey->tun;
 		attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
 	} else if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
 		struct ovs_key_ipv4_tunnel *tun_key;
 		tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
 		swkey->tun.tun_key = *tun_key;
+		flowhash->offset = (u32 *)&swkey->tun;
 		attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
+	} else {
+		flowhash->offset = (u32 *)&swkey->phy;
 	}
 
 	/* Data attributes. */
@@ -1168,7 +1179,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 
 	if (attrs)
 		return -EINVAL;
-	*key_lenp = key_len;
+	*key_lenp = flowhash->key_len = key_len;
 
 	return 0;
 }
@@ -1252,14 +1263,23 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
 	    nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->tun.tun_key.tun_id))
 		goto nla_put_failure;
 
-	if (swkey->tun.tun_key.ipv4_dst) {
-		struct ovs_key_ipv4_tunnel *tun_key;
+	if (swkey->tun.tun_key.ipv4_dst &&
+	    swkey->tun.tun_key.tun_id != cpu_to_be64(0)) {
+		struct ovs_key_ipv4_tunnel *tunnel_key;
 		nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL,
-				  sizeof(*tun_key));
+				  sizeof(*tunnel_key));
 		if (!nla)
 			goto nla_put_failure;
-		tun_key = nla_data(nla);
-		*tun_key = swkey->tun.tun_key;
+		if (!nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID,
+		    swkey->tun.tun_key.tun_id))
+			goto nla_put_failure;
+		tunnel_key = nla_data(nla);
+		tunnel_key->tun_id = swkey->tun.tun_key.tun_id;
+		tunnel_key->tun_flags = swkey->tun.tun_key.tun_flags;
+		tunnel_key->ipv4_src = swkey->tun.tun_key.ipv4_src;
+		tunnel_key->ipv4_dst = swkey->tun.tun_key.ipv4_dst;
+		tunnel_key->ipv4_tos = swkey->tun.tun_key.ipv4_tos;
+		tunnel_key->ipv4_ttl = swkey->tun.tun_key.ipv4_ttl;
 	}
 
 	if (swkey->phy.in_port != DP_MAX_PORTS &&
diff --git a/datapath/flow.h b/datapath/flow.h
index 4430b32..a6f6b79 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -40,14 +40,19 @@ struct sw_flow_actions {
 	struct nlattr actions[];
 };
 
+struct sw_flow_hash {
+	int key_len;
+	u32 *offset;
+};
+
 struct sw_flow_key {
 	struct {
+		struct ovs_key_ipv4_tunnel tun_key;  /* Encapsulating tunnel key. */
+	} tun;
+	struct {
 		u32	priority;	/* Packet QoS priority. */
 		u16	in_port;	/* Input switch port (or DP_MAX_PORTS). */
 	} phy;
-        struct {
-		struct ovs_key_ipv4_tunnel tun_key;  /* Encapsulating tunnel key. */
-	} tun;
 	struct {
 		u8     src[ETH_ALEN];	/* Ethernet source address. */
 		u8     dst[ETH_ALEN];	/* Ethernet destination address. */
@@ -102,6 +107,7 @@ struct sw_flow {
 	u32 hash;
 
 	struct sw_flow_key key;
+	struct sw_flow_hash flowhash;
 	struct sw_flow_actions __rcu *sf_acts;
 
 	atomic_t refcnt;
@@ -141,7 +147,7 @@ void ovs_flow_hold(struct sw_flow *);
 void ovs_flow_put(struct sw_flow *);
 
 int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
-		     int *key_lenp);
+		     int *key_lenp, struct sw_flow_hash *flowhash);
 void ovs_flow_used(struct sw_flow *, struct sk_buff *);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
@@ -169,7 +175,8 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
 int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
 int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
-		      const struct nlattr *);
+			  struct sw_flow_hash *flowhash,
+			  const struct nlattr *attrs);
 int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port,
 				   struct ovs_key_ipv4_tunnel *tun_key,
 				   const struct nlattr *);
@@ -197,7 +204,7 @@ static inline int ovs_flow_tbl_need_to_expand(struct flow_table *table)
 }
 
 struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
-				    struct sw_flow_key *key, int len);
+				    struct sw_flow_hash *flowhash);
 void ovs_flow_tbl_destroy(struct flow_table *table);
 void ovs_flow_tbl_deferred_destroy(struct flow_table *table);
 struct flow_table *ovs_flow_tbl_alloc(int new_size);
@@ -205,7 +212,7 @@ struct flow_table *ovs_flow_tbl_expand(struct flow_table *table);
 struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table);
 void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow);
 void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
-u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len);
+u32 ovs_flow_hash(const struct sw_flow_hash *flowhash);
 
 struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx);
 extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1];
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 739f098..9e0fd22 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -953,6 +953,7 @@ static struct tnl_cache *build_cache(struct vport *vport,
 
 	if (ovs_is_internal_dev(rt_dst(rt).dev)) {
 		struct sw_flow_key flow_key;
+		struct sw_flow_hash flowhash;
 		struct vport *dst_vport;
 		struct sk_buff *skb;
 		int err;
@@ -971,14 +972,14 @@ static struct tnl_cache *build_cache(struct vport *vport,
 		memcpy(skb->data, get_cached_header(cache), cache->len);
 
 		err = ovs_flow_extract(skb, dst_vport->port_no, &flow_key,
-				       &flow_key_len);
+				       &flow_key_len, &flowhash);
 
 		consume_skb(skb);
 		if (err)
 			goto done;
 
 		flow = ovs_flow_tbl_lookup(rcu_dereference(dst_vport->dp->table),
-					   &flow_key, flow_key_len);
+					   &flowhash);
 		if (flow) {
 			cache->flow = flow;
 			ovs_flow_hold(flow);
-- 
1.7.11.4




More information about the dev mailing list