Skip to content

Commit c03a49f

Browse files
IurmanJPaolo Abeni
authored andcommitted
net: lwtunnel: disable BHs when required
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>
1 parent 9e8d101 commit c03a49f

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

net/core/lwtunnel.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
333333
struct dst_entry *dst;
334334
int ret;
335335

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

350352
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
351-
lwtstate->type > LWTUNNEL_ENCAP_MAX)
352-
return 0;
353+
lwtstate->type > LWTUNNEL_ENCAP_MAX) {
354+
ret = 0;
355+
goto out;
356+
}
353357

354358
ret = -EOPNOTSUPP;
355359
rcu_read_lock();
@@ -364,11 +368,13 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
364368
if (ret == -EOPNOTSUPP)
365369
goto drop;
366370

367-
return ret;
371+
goto out;
368372

369373
drop:
370374
kfree_skb(skb);
371375

376+
out:
377+
local_bh_enable();
372378
return ret;
373379
}
374380
EXPORT_SYMBOL_GPL(lwtunnel_output);
@@ -380,6 +386,8 @@ int lwtunnel_xmit(struct sk_buff *skb)
380386
struct dst_entry *dst;
381387
int ret;
382388

389+
local_bh_disable();
390+
383391
if (dev_xmit_recursion()) {
384392
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
385393
__func__);
@@ -396,8 +404,10 @@ int lwtunnel_xmit(struct sk_buff *skb)
396404
lwtstate = dst->lwtstate;
397405

398406
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
399-
lwtstate->type > LWTUNNEL_ENCAP_MAX)
400-
return 0;
407+
lwtstate->type > LWTUNNEL_ENCAP_MAX) {
408+
ret = 0;
409+
goto out;
410+
}
401411

402412
ret = -EOPNOTSUPP;
403413
rcu_read_lock();
@@ -412,11 +422,13 @@ int lwtunnel_xmit(struct sk_buff *skb)
412422
if (ret == -EOPNOTSUPP)
413423
goto drop;
414424

415-
return ret;
425+
goto out;
416426

417427
drop:
418428
kfree_skb(skb);
419429

430+
out:
431+
local_bh_enable();
420432
return ret;
421433
}
422434
EXPORT_SYMBOL_GPL(lwtunnel_xmit);
@@ -428,6 +440,8 @@ int lwtunnel_input(struct sk_buff *skb)
428440
struct dst_entry *dst;
429441
int ret;
430442

443+
DEBUG_NET_WARN_ON_ONCE(!in_softirq());
444+
431445
if (dev_xmit_recursion()) {
432446
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
433447
__func__);

0 commit comments

Comments
 (0)