summaryrefslogtreecommitdiff
path: root/datapath/datapath.c
diff options
context:
space:
mode:
authorAndy Zhou <azhou@nicira.com>2014-04-08 11:13:42 +0000
committerAndy Zhou <azhou@nicira.com>2014-04-21 11:06:55 -0700
commita605908001070c27aa8c755c92cd361a10b46beb (patch)
tree045e968a4a113283263a728692674426b8e22f43 /datapath/datapath.c
parent7804df205faf285037994c7d222dfd45d5c00c49 (diff)
downloadopenvswitch-a605908001070c27aa8c755c92cd361a10b46beb.tar.gz
datapath: add recirc action
Recirculation implementation for Linux kernel data path. Signed-off-by: Andy Zhou <azhou@nicira.com> Acked-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'datapath/datapath.c')
-rw-r--r--datapath/datapath.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/datapath/datapath.c b/datapath/datapath.c
index c20d6afee..aa4c1097e 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -239,33 +239,25 @@ void ovs_dp_detach_port(struct vport *p)
ovs_vport_del(p);
}
-/* Must be called with rcu_read_lock. */
-void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
+void ovs_dp_process_packet_with_key(struct sk_buff *skb,
+ struct sw_flow_key *pkt_key)
{
+ const struct vport *p = OVS_CB(skb)->input_vport;
struct datapath *dp = p->dp;
struct sw_flow *flow;
struct dp_stats_percpu *stats;
- struct sw_flow_key key;
u64 *stats_counter;
u32 n_mask_hit;
- int error;
stats = this_cpu_ptr(dp->stats_percpu);
- /* Extract flow from 'skb' into 'key'. */
- error = ovs_flow_extract(skb, p->port_no, &key);
- if (unlikely(error)) {
- kfree_skb(skb);
- return;
- }
-
/* Look up flow. */
- flow = ovs_flow_tbl_lookup_stats(&dp->table, &key, &n_mask_hit);
+ flow = ovs_flow_tbl_lookup_stats(&dp->table, pkt_key, &n_mask_hit);
if (unlikely(!flow)) {
struct dp_upcall_info upcall;
upcall.cmd = OVS_PACKET_CMD_MISS;
- upcall.key = &key;
+ upcall.key = pkt_key;
upcall.userdata = NULL;
upcall.portid = ovs_vport_find_upcall_portid(p, skb);
ovs_dp_upcall(dp, skb, &upcall);
@@ -274,10 +266,10 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
goto out;
}
+ OVS_CB(skb)->pkt_key = pkt_key;
OVS_CB(skb)->flow = flow;
- OVS_CB(skb)->pkt_key = &key;
- ovs_flow_stats_update(OVS_CB(skb)->flow, key.tp.flags, skb);
+ ovs_flow_stats_update(OVS_CB(skb)->flow, pkt_key->tp.flags, skb);
ovs_execute_actions(dp, skb);
stats_counter = &stats->n_hit;
@@ -289,6 +281,24 @@ out:
u64_stats_update_end(&stats->sync);
}
+/* Must be called with rcu_read_lock. */
+void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
+{
+ int error;
+ struct sw_flow_key key;
+
+ OVS_CB(skb)->input_vport = p;
+
+ /* Extract flow from 'skb' into 'key'. */
+ error = ovs_flow_extract(skb, p->port_no, &key);
+ if (unlikely(error)) {
+ kfree_skb(skb);
+ return;
+ }
+
+ ovs_dp_process_packet_with_key(skb, &key);
+}
+
int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
const struct dp_upcall_info *upcall_info)
{
@@ -515,6 +525,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
struct sw_flow *flow;
struct datapath *dp;
struct ethhdr *eth;
+ struct vport *input_vport;
int len;
int err;
@@ -578,6 +589,15 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
if (!dp)
goto err_unlock;
+ input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port);
+ if (!input_vport)
+ input_vport = ovs_vport_rcu(dp, OVSP_LOCAL);
+
+ if (!input_vport)
+ goto err_unlock;
+
+ OVS_CB(packet)->input_vport = input_vport;
+
local_bh_disable();
err = ovs_execute_actions(dp, packet);
local_bh_enable();