[ovs-dev] [PATCH 1/2] datapath: Always execute actions in BH context.

Pravin B Shelar pshelar at nicira.com
Wed Oct 5 19:39:02 UTC 2011


    Following patch make sure that BH is disabled while running
execute_actions() on packets from userspace. RCU annotation for BH is
used to fix false positive warning message.

Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
Bug #7621
---
 datapath/actions.c                             |    5 +++--
 datapath/datapath.c                            |    6 ++++--
 datapath/linux/compat/include/linux/rcupdate.h |    4 +++-
 datapath/tunnel.c                              |    8 ++++----
 datapath/vport-patch.c                         |    2 +-
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 36437a4..76d378f 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -234,7 +234,7 @@ static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
 	if (unlikely(!skb))
 		return -ENOMEM;
 
-	vport = rcu_dereference(dp->ports[out_port]);
+	vport = rcu_dereference_bh(dp->ports[out_port]);
 	if (unlikely(!vport)) {
 		kfree_skb(skb);
 		return -ENODEV;
@@ -383,10 +383,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 /* Execute a list of actions against 'skb'. */
 int execute_actions(struct datapath *dp, struct sk_buff *skb)
 {
-	struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
+	struct sw_flow_actions *acts;
 	struct loop_counter *loop;
 	int error;
 
+	acts = rcu_dereference_bh(OVS_CB(skb)->flow->sf_acts);
 	/* Check whether we've looped too much. */
 	loop = loop_get_counter();
 	if (unlikely(++loop->count > MAX_LOOPS))
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 15c1e33..b912ee3 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -304,7 +304,8 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 		}
 
 		/* Look up flow. */
-		flow = flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len);
+		flow = flow_tbl_lookup(rcu_dereference_bh(dp->table),
+					 &key, key_len);
 		if (unlikely(!flow)) {
 			struct dp_upcall_info upcall;
 
@@ -705,8 +706,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	if (flow->key.eth.in_port < DP_MAX_PORTS)
 		OVS_CB(packet)->vport = get_vport_protected(dp,
 							flow->key.eth.in_port);
-
+	local_bh_disable();
 	err = execute_actions(dp, packet);
+	local_bh_enable();
 	rcu_read_unlock();
 
 	flow_put(flow);
diff --git a/datapath/linux/compat/include/linux/rcupdate.h b/datapath/linux/compat/include/linux/rcupdate.h
index 99459ea..6c9a0a6 100644
--- a/datapath/linux/compat/include/linux/rcupdate.h
+++ b/datapath/linux/compat/include/linux/rcupdate.h
@@ -17,5 +17,7 @@ static inline int rcu_read_lock_held(void)
 	return 1;
 }
 #endif
-
+#ifndef rcu_dereference_bh
+#define rcu_dereference_bh(p) rcu_dereference(p)
+#endif
 #endif /* linux/rcupdate.h wrapper */
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 3576df8..176c5c6 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -898,7 +898,7 @@ static struct tnl_cache *build_cache(struct vport *vport,
 		if (err || is_frag)
 			goto done;
 
-		flow = flow_tbl_lookup(rcu_dereference(dst_vport->dp->table),
+		flow = flow_tbl_lookup(rcu_dereference_bh(dst_vport->dp->table),
 					 &flow_key, flow_key_len);
 		if (flow) {
 			cache->flow = flow;
@@ -920,7 +920,7 @@ static struct rtable *find_route(struct vport *vport,
 				 u8 tos, struct tnl_cache **cache)
 {
 	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-	struct tnl_cache *cur_cache = rcu_dereference(tnl_vport->cache);
+	struct tnl_cache *cur_cache = rcu_dereference_bh(tnl_vport->cache);
 
 	*cache = NULL;
 	tos = RT_TOS(tos);
@@ -1074,8 +1074,7 @@ free_frags:
 int tnl_send(struct vport *vport, struct sk_buff *skb)
 {
 	struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-	const struct tnl_mutable_config *mutable = rcu_dereference(tnl_vport->mutable);
-
+	const struct tnl_mutable_config *mutable;
 	enum vport_err_type err = VPORT_E_TX_ERROR;
 	struct rtable *rt;
 	struct dst_entry *unattached_dst = NULL;
@@ -1119,6 +1118,7 @@ int tnl_send(struct vport *vport, struct sk_buff *skb)
 	else
 		inner_tos = 0;
 
+	mutable = rcu_dereference_bh(tnl_vport->mutable);
 	if (mutable->flags & TNL_F_TOS_INHERIT)
 		tos = inner_tos;
 	else
diff --git a/datapath/vport-patch.c b/datapath/vport-patch.c
index 9554f12..c18b59d 100644
--- a/datapath/vport-patch.c
+++ b/datapath/vport-patch.c
@@ -271,7 +271,7 @@ static int patch_get_options(const struct vport *vport, struct sk_buff *skb)
 static int patch_send(struct vport *vport, struct sk_buff *skb)
 {
 	struct patch_vport *patch_vport = patch_vport_priv(vport);
-	struct vport *peer = rcu_dereference(patch_vport->peer);
+	struct vport *peer = rcu_dereference_bh(patch_vport->peer);
 	int skb_len = skb->len;
 
 	if (!peer) {
-- 
1.7.1




More information about the dev mailing list