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 <[email protected]> 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 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
