Commit 7fd4b288 authored by Paolo Abeni's avatar Paolo Abeni Committed by David S. Miller

tc/act: remove unneeded RCU lock in action callback

Each lockless action currently does its own RCU locking in ->act().
This allows using plain RCU accessor, even if the context
is really RCU BH.

This change drops the per action RCU lock, replace the accessors
with the _bh variant, cleans up a bit the surrounding code and
documents the RCU status in the relevant header.
No functional nor performance change is intended.

The goal of this patch is clarifying that the RCU critical section
used by the tc actions extends up to the classifier's caller.

v1 -> v2:
 - preserve rcu lock in act_bpf: it's needed by eBPF helpers,
   as pointed out by Daniel

v3 -> v4:
 - fixed some typos in the commit message (JiriP)
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 802bfb19
...@@ -85,7 +85,7 @@ struct tc_action_ops { ...@@ -85,7 +85,7 @@ struct tc_action_ops {
size_t size; size_t size;
struct module *owner; struct module *owner;
int (*act)(struct sk_buff *, const struct tc_action *, int (*act)(struct sk_buff *, const struct tc_action *,
struct tcf_result *); struct tcf_result *); /* called under RCU BH lock*/
int (*dump)(struct sk_buff *, struct tc_action *, int, int); int (*dump)(struct sk_buff *, struct tc_action *, int, int);
void (*cleanup)(struct tc_action *); void (*cleanup)(struct tc_action *);
int (*lookup)(struct net *net, struct tc_action **a, u32 index, int (*lookup)(struct net *net, struct tc_action **a, u32 index,
......
...@@ -285,6 +285,8 @@ struct tcf_proto { ...@@ -285,6 +285,8 @@ struct tcf_proto {
/* Fast access part */ /* Fast access part */
struct tcf_proto __rcu *next; struct tcf_proto __rcu *next;
void __rcu *root; void __rcu *root;
/* called under RCU BH lock*/
int (*classify)(struct sk_buff *, int (*classify)(struct sk_buff *,
const struct tcf_proto *, const struct tcf_proto *,
struct tcf_result *); struct tcf_result *);
......
...@@ -561,15 +561,14 @@ static int tcf_csum(struct sk_buff *skb, const struct tc_action *a, ...@@ -561,15 +561,14 @@ static int tcf_csum(struct sk_buff *skb, const struct tc_action *a,
u32 update_flags; u32 update_flags;
int action; int action;
rcu_read_lock(); params = rcu_dereference_bh(p->params);
params = rcu_dereference(p->params);
tcf_lastuse_update(&p->tcf_tm); tcf_lastuse_update(&p->tcf_tm);
bstats_cpu_update(this_cpu_ptr(p->common.cpu_bstats), skb); bstats_cpu_update(this_cpu_ptr(p->common.cpu_bstats), skb);
action = READ_ONCE(p->tcf_action); action = READ_ONCE(p->tcf_action);
if (unlikely(action == TC_ACT_SHOT)) if (unlikely(action == TC_ACT_SHOT))
goto drop_stats; goto drop;
update_flags = params->update_flags; update_flags = params->update_flags;
switch (tc_skb_protocol(skb)) { switch (tc_skb_protocol(skb)) {
...@@ -583,16 +582,11 @@ static int tcf_csum(struct sk_buff *skb, const struct tc_action *a, ...@@ -583,16 +582,11 @@ static int tcf_csum(struct sk_buff *skb, const struct tc_action *a,
break; break;
} }
unlock:
rcu_read_unlock();
return action; return action;
drop: drop:
action = TC_ACT_SHOT;
drop_stats:
qstats_drop_inc(this_cpu_ptr(p->common.cpu_qstats)); qstats_drop_inc(this_cpu_ptr(p->common.cpu_qstats));
goto unlock; return TC_ACT_SHOT;
} }
static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind, static int tcf_csum_dump(struct sk_buff *skb, struct tc_action *a, int bind,
......
...@@ -820,14 +820,11 @@ static int tcf_ife_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -820,14 +820,11 @@ static int tcf_ife_act(struct sk_buff *skb, const struct tc_action *a,
struct tcf_ife_params *p; struct tcf_ife_params *p;
int ret; int ret;
rcu_read_lock(); p = rcu_dereference_bh(ife->params);
p = rcu_dereference(ife->params);
if (p->flags & IFE_ENCODE) { if (p->flags & IFE_ENCODE) {
ret = tcf_ife_encode(skb, a, res, p); ret = tcf_ife_encode(skb, a, res, p);
rcu_read_unlock();
return ret; return ret;
} }
rcu_read_unlock();
return tcf_ife_decode(skb, a, res); return tcf_ife_decode(skb, a, res);
} }
......
...@@ -181,11 +181,10 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, ...@@ -181,11 +181,10 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
tcf_lastuse_update(&m->tcf_tm); tcf_lastuse_update(&m->tcf_tm);
bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb); bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
rcu_read_lock();
m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit);
m_eaction = READ_ONCE(m->tcfm_eaction); m_eaction = READ_ONCE(m->tcfm_eaction);
retval = READ_ONCE(m->tcf_action); retval = READ_ONCE(m->tcf_action);
dev = rcu_dereference(m->tcfm_dev); dev = rcu_dereference_bh(m->tcfm_dev);
if (unlikely(!dev)) { if (unlikely(!dev)) {
pr_notice_once("tc mirred: target device is gone\n"); pr_notice_once("tc mirred: target device is gone\n");
goto out; goto out;
...@@ -236,7 +235,6 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, ...@@ -236,7 +235,6 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
if (tcf_mirred_is_act_redirect(m_eaction)) if (tcf_mirred_is_act_redirect(m_eaction))
retval = TC_ACT_SHOT; retval = TC_ACT_SHOT;
} }
rcu_read_unlock();
return retval; return retval;
} }
......
...@@ -140,8 +140,7 @@ static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -140,8 +140,7 @@ static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a,
bstats_cpu_update(this_cpu_ptr(s->common.cpu_bstats), skb); bstats_cpu_update(this_cpu_ptr(s->common.cpu_bstats), skb);
retval = READ_ONCE(s->tcf_action); retval = READ_ONCE(s->tcf_action);
rcu_read_lock(); psample_group = rcu_dereference_bh(s->psample_group);
psample_group = rcu_dereference(s->psample_group);
/* randomly sample packets according to rate */ /* randomly sample packets according to rate */
if (psample_group && (prandom_u32() % s->rate == 0)) { if (psample_group && (prandom_u32() % s->rate == 0)) {
...@@ -165,7 +164,6 @@ static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -165,7 +164,6 @@ static int tcf_sample_act(struct sk_buff *skb, const struct tc_action *a,
skb_pull(skb, skb->mac_len); skb_pull(skb, skb->mac_len);
} }
rcu_read_unlock();
return retval; return retval;
} }
......
...@@ -43,8 +43,7 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a, ...@@ -43,8 +43,7 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
tcf_lastuse_update(&d->tcf_tm); tcf_lastuse_update(&d->tcf_tm);
bstats_cpu_update(this_cpu_ptr(d->common.cpu_bstats), skb); bstats_cpu_update(this_cpu_ptr(d->common.cpu_bstats), skb);
rcu_read_lock(); params = rcu_dereference_bh(d->params);
params = rcu_dereference(d->params);
action = READ_ONCE(d->tcf_action); action = READ_ONCE(d->tcf_action);
if (params->flags & SKBEDIT_F_PRIORITY) if (params->flags & SKBEDIT_F_PRIORITY)
...@@ -77,14 +76,11 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a, ...@@ -77,14 +76,11 @@ static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
} }
if (params->flags & SKBEDIT_F_PTYPE) if (params->flags & SKBEDIT_F_PTYPE)
skb->pkt_type = params->ptype; skb->pkt_type = params->ptype;
unlock:
rcu_read_unlock();
return action; return action;
err: err:
qstats_drop_inc(this_cpu_ptr(d->common.cpu_qstats)); qstats_drop_inc(this_cpu_ptr(d->common.cpu_qstats));
action = TC_ACT_SHOT; return TC_ACT_SHOT;
goto unlock;
} }
static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = { static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
......
...@@ -41,20 +41,14 @@ static int tcf_skbmod_run(struct sk_buff *skb, const struct tc_action *a, ...@@ -41,20 +41,14 @@ static int tcf_skbmod_run(struct sk_buff *skb, const struct tc_action *a,
* then MAX_EDIT_LEN needs to change appropriately * then MAX_EDIT_LEN needs to change appropriately
*/ */
err = skb_ensure_writable(skb, MAX_EDIT_LEN); err = skb_ensure_writable(skb, MAX_EDIT_LEN);
if (unlikely(err)) { /* best policy is to drop on the floor */ if (unlikely(err)) /* best policy is to drop on the floor */
qstats_overlimit_inc(this_cpu_ptr(d->common.cpu_qstats)); goto drop;
return TC_ACT_SHOT;
}
rcu_read_lock();
action = READ_ONCE(d->tcf_action); action = READ_ONCE(d->tcf_action);
if (unlikely(action == TC_ACT_SHOT)) { if (unlikely(action == TC_ACT_SHOT))
qstats_overlimit_inc(this_cpu_ptr(d->common.cpu_qstats)); goto drop;
rcu_read_unlock();
return action;
}
p = rcu_dereference(d->skbmod_p); p = rcu_dereference_bh(d->skbmod_p);
flags = p->flags; flags = p->flags;
if (flags & SKBMOD_F_DMAC) if (flags & SKBMOD_F_DMAC)
ether_addr_copy(eth_hdr(skb)->h_dest, p->eth_dst); ether_addr_copy(eth_hdr(skb)->h_dest, p->eth_dst);
...@@ -62,7 +56,6 @@ static int tcf_skbmod_run(struct sk_buff *skb, const struct tc_action *a, ...@@ -62,7 +56,6 @@ static int tcf_skbmod_run(struct sk_buff *skb, const struct tc_action *a,
ether_addr_copy(eth_hdr(skb)->h_source, p->eth_src); ether_addr_copy(eth_hdr(skb)->h_source, p->eth_src);
if (flags & SKBMOD_F_ETYPE) if (flags & SKBMOD_F_ETYPE)
eth_hdr(skb)->h_proto = p->eth_type; eth_hdr(skb)->h_proto = p->eth_type;
rcu_read_unlock();
if (flags & SKBMOD_F_SWAPMAC) { if (flags & SKBMOD_F_SWAPMAC) {
u16 tmpaddr[ETH_ALEN / 2]; /* ether_addr_copy() requirement */ u16 tmpaddr[ETH_ALEN / 2]; /* ether_addr_copy() requirement */
...@@ -73,6 +66,10 @@ static int tcf_skbmod_run(struct sk_buff *skb, const struct tc_action *a, ...@@ -73,6 +66,10 @@ static int tcf_skbmod_run(struct sk_buff *skb, const struct tc_action *a,
} }
return action; return action;
drop:
qstats_overlimit_inc(this_cpu_ptr(d->common.cpu_qstats));
return TC_ACT_SHOT;
} }
static const struct nla_policy skbmod_policy[TCA_SKBMOD_MAX + 1] = { static const struct nla_policy skbmod_policy[TCA_SKBMOD_MAX + 1] = {
......
...@@ -31,9 +31,7 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -31,9 +31,7 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
struct tcf_tunnel_key_params *params; struct tcf_tunnel_key_params *params;
int action; int action;
rcu_read_lock(); params = rcu_dereference_bh(t->params);
params = rcu_dereference(t->params);
tcf_lastuse_update(&t->tcf_tm); tcf_lastuse_update(&t->tcf_tm);
bstats_cpu_update(this_cpu_ptr(t->common.cpu_bstats), skb); bstats_cpu_update(this_cpu_ptr(t->common.cpu_bstats), skb);
...@@ -53,8 +51,6 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a, ...@@ -53,8 +51,6 @@ static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a,
break; break;
} }
rcu_read_unlock();
return action; return action;
} }
......
...@@ -40,11 +40,9 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a, ...@@ -40,11 +40,9 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
if (skb_at_tc_ingress(skb)) if (skb_at_tc_ingress(skb))
skb_push_rcsum(skb, skb->mac_len); skb_push_rcsum(skb, skb->mac_len);
rcu_read_lock();
action = READ_ONCE(v->tcf_action); action = READ_ONCE(v->tcf_action);
p = rcu_dereference(v->vlan_p); p = rcu_dereference_bh(v->vlan_p);
switch (p->tcfv_action) { switch (p->tcfv_action) {
case TCA_VLAN_ACT_POP: case TCA_VLAN_ACT_POP:
...@@ -61,7 +59,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a, ...@@ -61,7 +59,7 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
case TCA_VLAN_ACT_MODIFY: case TCA_VLAN_ACT_MODIFY:
/* No-op if no vlan tag (either hw-accel or in-payload) */ /* No-op if no vlan tag (either hw-accel or in-payload) */
if (!skb_vlan_tagged(skb)) if (!skb_vlan_tagged(skb))
goto unlock; goto out;
/* extract existing tag (and guarantee no hw-accel tag) */ /* extract existing tag (and guarantee no hw-accel tag) */
if (skb_vlan_tag_present(skb)) { if (skb_vlan_tag_present(skb)) {
tci = skb_vlan_tag_get(skb); tci = skb_vlan_tag_get(skb);
...@@ -86,18 +84,15 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a, ...@@ -86,18 +84,15 @@ static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
BUG(); BUG();
} }
goto unlock; out:
drop:
action = TC_ACT_SHOT;
qstats_drop_inc(this_cpu_ptr(v->common.cpu_qstats));
unlock:
rcu_read_unlock();
if (skb_at_tc_ingress(skb)) if (skb_at_tc_ingress(skb))
skb_pull_rcsum(skb, skb->mac_len); skb_pull_rcsum(skb, skb->mac_len);
return action; return action;
drop:
qstats_drop_inc(this_cpu_ptr(v->common.cpu_qstats));
return TC_ACT_SHOT;
} }
static const struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = { static const struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment