Skip to content

Commit

Permalink
net: lwtunnel: disable BHs when required
Browse files Browse the repository at this point in the history
In lwtunnel_{output|xmit}(), dev_xmit_recursion() may be called in
preemptible scope for PREEMPT kernels. This patch disables BHs before
calling dev_xmit_recursion(). BHs are re-enabled only at the end, since
we must ensure the same CPU is used for both dev_xmit_recursion_inc()
and dev_xmit_recursion_dec() (and any other recursion levels in some
cases) in order to maintain valid per-cpu counters.

Reported-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Closes: https://lore.kernel.org/netdev/CAADnVQJFWn3dBFJtY+ci6oN1pDFL=TzCmNbRgey7MdYxt_AP2g@mail.gmail.com/
Reported-by: Eduard Zingerman <eddyz87@gmail.com>
Closes: https://lore.kernel.org/netdev/m2h62qwf34.fsf@gmail.com/
Fixes: 986ffb3 ("net: lwtunnel: fix recursion loops")
Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250416160716.8823-1-justin.iurman@uliege.be
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Justin Iurman authored and Paolo Abeni committed Apr 22, 2025
1 parent 9e8d101 commit c03a49f
Showing 1 changed file with 20 additions and 6 deletions.
26 changes: 20 additions & 6 deletions net/core/lwtunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
struct dst_entry *dst;
int ret;

local_bh_disable();

if (dev_xmit_recursion()) {
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
__func__);
Expand All @@ -348,8 +350,10 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
lwtstate = dst->lwtstate;

if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
lwtstate->type > LWTUNNEL_ENCAP_MAX)
return 0;
lwtstate->type > LWTUNNEL_ENCAP_MAX) {
ret = 0;
goto out;
}

ret = -EOPNOTSUPP;
rcu_read_lock();
Expand All @@ -364,11 +368,13 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
if (ret == -EOPNOTSUPP)
goto drop;

return ret;
goto out;

drop:
kfree_skb(skb);

out:
local_bh_enable();
return ret;
}
EXPORT_SYMBOL_GPL(lwtunnel_output);
Expand All @@ -380,6 +386,8 @@ int lwtunnel_xmit(struct sk_buff *skb)
struct dst_entry *dst;
int ret;

local_bh_disable();

if (dev_xmit_recursion()) {
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
__func__);
Expand All @@ -396,8 +404,10 @@ int lwtunnel_xmit(struct sk_buff *skb)
lwtstate = dst->lwtstate;

if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
lwtstate->type > LWTUNNEL_ENCAP_MAX)
return 0;
lwtstate->type > LWTUNNEL_ENCAP_MAX) {
ret = 0;
goto out;
}

ret = -EOPNOTSUPP;
rcu_read_lock();
Expand All @@ -412,11 +422,13 @@ int lwtunnel_xmit(struct sk_buff *skb)
if (ret == -EOPNOTSUPP)
goto drop;

return ret;
goto out;

drop:
kfree_skb(skb);

out:
local_bh_enable();
return ret;
}
EXPORT_SYMBOL_GPL(lwtunnel_xmit);
Expand All @@ -428,6 +440,8 @@ int lwtunnel_input(struct sk_buff *skb)
struct dst_entry *dst;
int ret;

DEBUG_NET_WARN_ON_ONCE(!in_softirq());

if (dev_xmit_recursion()) {
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
__func__);
Expand Down

0 comments on commit c03a49f

Please sign in to comment.