[ovs-dev] [PATCH 3/7] datapath: Enable usage of cached flows.

Jesse Gross jesse at nicira.com
Mon Sep 20 18:13:41 UTC 2010


An upcoming commit will add support for supplying cached flows for
packets entering the datapath.  This adds the code in the datapath
itself to recognize these cached flows and use them instead of
extracting the flow fields and doing a lookup.

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 datapath/datapath.c           |   53 ++++++++++++++++++++++------------------
 datapath/datapath.h           |    6 +++-
 datapath/vport-internal_dev.c |    3 +-
 datapath/vport.c              |    3 ++
 datapath/vport.h              |    3 +-
 5 files changed, 40 insertions(+), 28 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 6196ede..11d3026 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -543,40 +543,44 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
 	struct datapath *dp = p->dp;
 	struct dp_stats_percpu *stats;
 	int stats_counter_off;
-	struct odp_flow_key key;
-	struct tbl_node *flow_node;
-	struct sw_flow *flow;
 	struct sw_flow_actions *acts;
 	struct loop_counter *loop;
 	int error;
 
 	OVS_CB(skb)->dp_port = p;
 
-	/* Extract flow from 'skb' into 'key'. */
-	error = flow_extract(skb, p ? p->port_no : ODPP_NONE, &key);
-	if (unlikely(error)) {
-		kfree_skb(skb);
-		return;
-	}
+	if (!OVS_CB(skb)->flow) {
+		struct odp_flow_key key;
+		struct tbl_node *flow_node;
 
-	if (OVS_CB(skb)->is_frag && dp->drop_frags) {
-		kfree_skb(skb);
-		stats_counter_off = offsetof(struct dp_stats_percpu, n_frags);
-		goto out;
-	}
+		/* Extract flow from 'skb' into 'key'. */
+		error = flow_extract(skb, p ? p->port_no : ODPP_NONE, &key);
+		if (unlikely(error)) {
+			kfree_skb(skb);
+			return;
+		}
 
-	/* Look up flow. */
-	flow_node = tbl_lookup(rcu_dereference(dp->table), &key, flow_hash(&key), flow_cmp);
-	if (unlikely(!flow_node)) {
-		dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
-		stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
-		goto out;
+		if (OVS_CB(skb)->is_frag && dp->drop_frags) {
+			kfree_skb(skb);
+			stats_counter_off = offsetof(struct dp_stats_percpu, n_frags);
+			goto out;
+		}
+
+		/* Look up flow. */
+		flow_node = tbl_lookup(rcu_dereference(dp->table), &key,
+					flow_hash(&key), flow_cmp);
+		if (unlikely(!flow_node)) {
+			dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
+			stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
+			goto out;
+		}
+
+		OVS_CB(skb)->flow = flow_cast(flow_node);
 	}
 
-	flow = flow_cast(flow_node);
-	flow_used(flow, skb);
+	flow_used(OVS_CB(skb)->flow, skb);
 
-	acts = rcu_dereference(flow->sf_acts);
+	acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
 
 	/* Check whether we've looped too much. */
 	loop = &get_cpu_var(dp_loop_counters).counters[!!in_interrupt()];
@@ -588,7 +592,8 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
 	}
 
 	/* Execute actions. */
-	execute_actions(dp, skb, &key, acts->actions, acts->n_actions, GFP_ATOMIC);
+	execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions,
+			acts->n_actions, GFP_ATOMIC);
 	stats_counter_off = offsetof(struct dp_stats_percpu, n_hit);
 
 	/* Check whether sub-actions looped too much. */
diff --git a/datapath/datapath.h b/datapath/datapath.h
index abc6aea..dacc3a4 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -146,17 +146,19 @@ enum csum_type {
 /**
  * struct ovs_skb_cb - OVS data in skb CB
  * @dp_port: The datapath port on which the skb entered the switch.
+ * @flow: The flow associated with this packet.  May be %NULL if no flow.
+ * @is_frag: %true if this packet is an IPv4 fragment, %false otherwise.
  * @ip_summed: Consistently stores L4 checksumming status across different
  * kernel versions.
  * @tun_id: ID (in network byte order) of the tunnel that encapsulated this
  * packet. It is 0 if the packet was not received on a tunnel.
- * @is_frag: %true if this packet is an IPv4 fragment, %false otherwise.
  */
 struct ovs_skb_cb {
 	struct dp_port		*dp_port;
+	struct sw_flow		*flow;
+	bool			is_frag;
 	enum csum_type		ip_summed;
 	__be32			tun_id;
-	bool			is_frag;
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 6cbfdf8..514d00c 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -82,6 +82,7 @@ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 	skb_reset_mac_header(skb);
 	compute_ip_summed(skb, true);
+	OVS_CB(skb)->flow = NULL;
 
 	vport_receive(vport, skb);
 
@@ -293,7 +294,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
 
 struct vport_ops internal_vport_ops = {
 	.type		= "internal",
-	.flags		= VPORT_F_REQUIRED | VPORT_F_GEN_STATS,
+	.flags		= VPORT_F_REQUIRED | VPORT_F_GEN_STATS | VPORT_F_FLOW,
 	.create		= internal_dev_create,
 	.destroy	= internal_dev_destroy,
 	.attach		= internal_dev_attach,
diff --git a/datapath/vport.c b/datapath/vport.c
index 91b650e..6c8eb08 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -1217,6 +1217,9 @@ void vport_receive(struct vport *vport, struct sk_buff *skb)
 		local_bh_enable();
 	}
 
+	if (!(vport->ops->flags & VPORT_F_FLOW))
+		OVS_CB(skb)->flow = NULL;
+
 	if (!(vport->ops->flags & VPORT_F_TUN_ID))
 		OVS_CB(skb)->tun_id = 0;
 
diff --git a/datapath/vport.h b/datapath/vport.h
index fca5f1a..30b0cc6 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -112,7 +112,8 @@ struct vport {
 
 #define VPORT_F_REQUIRED	(1 << 0) /* If init fails, module loading fails. */
 #define VPORT_F_GEN_STATS	(1 << 1) /* Track stats at the generic layer. */
-#define VPORT_F_TUN_ID		(1 << 2) /* Sets OVS_CB(skb)->tun_id. */
+#define VPORT_F_FLOW		(1 << 2) /* Sets OVS_CB(skb)->flow. */
+#define VPORT_F_TUN_ID		(1 << 3) /* Sets OVS_CB(skb)->tun_id. */
 
 /**
  * struct vport_ops - definition of a type of virtual port
-- 
1.7.0.4





More information about the dev mailing list