Re: [PATCH net] net: neighbour: Serialize proxy queue admission
From: Kuniyuki Iwashima
Date: Sat Sep 26 2026 - 15:45:38 EST
On Sat, Sep 26, 2026 at 10:37 AM Chengfeng Ye <nicoyip.dev@xxxxxxxxx> wrote:
>
> pneigh_enqueue() checks p->qlen before taking proxy_queue.lock, although
> both enqueueing and the timer and purge paths update it under that lock.
> The unlocked read races with those updates and allows concurrent proxy
> ARP or NDP requests to bypass the queue's admission limit.
>
> For example, CPU0 and CPU1 can both observe p->qlen == PROXY_QLEN before
> either takes the lock. CPU0 then locks and enqueues, raising the count to
> PROXY_QLEN + 1. CPU1 subsequently locks and enqueues using its stale
> admission decision, raising the count to PROXY_QLEN + 2. The extra queued
> packets consume memory until the timer or purge path removes them.
>
> With a temporary 20 ms delay before locking and a queue-length assertion,
> the kernel reported qlen=6 with PROXY_QLEN=4:
>
> WARNING: net/core/neighbour.c:1757 at pneigh_enqueue+0x4ee/0x650
Please do not include a local-only stack trace in the commit message.
A transient overshoot is not a problem.
You can already set PROXY_QLEN below the actual qlen anyway.
> Call Trace:
> <IRQ>
> arp_process+0x1846/0x2060
> __netif_receive_skb_core.constprop.0+0x1524/0x2bd0
> __netif_receive_skb_one_core+0xa9/0x1b0
> process_backlog+0x1e5/0x5e0
> __napi_poll+0x9c/0x540
> net_rx_action+0x988/0xfb0
> handle_softirqs+0x18d/0x5b0
> do_softirq+0x3b/0x60
> </IRQ>
>
> Move the existing lock acquisition before the admission check so that the
> check and increment are serialized with all queue-length updates. Unlock
> before freeing a rejected packet. Keep the existing > comparison so that
> serial admission behavior is unchanged.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Chengfeng Ye <nicoyip.dev@xxxxxxxxx>
> ---
> net/core/neighbour.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/net/core/neighbour.c b/net/core/neighbour.c
> index 7448320f7ad5..e35ce26b4f8a 100644
> --- a/net/core/neighbour.c
> +++ b/net/core/neighbour.c
> @@ -1721,7 +1721,9 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
> {
> unsigned long sched_next = neigh_proxy_delay(p);
>
> + spin_lock(&tbl->proxy_queue.lock);
> if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) {
> + spin_unlock(&tbl->proxy_queue.lock);
> kfree_skb(skb);
> return;
> }
> @@ -1729,7 +1731,6 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
> NEIGH_CB(skb)->sched_next = sched_next;
> NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
>
> - spin_lock(&tbl->proxy_queue.lock);
> if (timer_delete(&tbl->proxy_timer)) {
> if (time_before(tbl->proxy_timer.expires, sched_next))
> sched_next = tbl->proxy_timer.expires;
> --
> 2.43.0
>