]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: core: neighbour: Extract ARP queue processing to a helper function
authorPetr Machata <petrm@nvidia.com>
Wed, 21 Jan 2026 16:43:37 +0000 (17:43 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sun, 25 Jan 2026 22:57:37 +0000 (14:57 -0800)
In order to make manipulation with this bit of code clearer, extract it
to a helper function, neigh_update_process_arp_queue().

Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/8b0fa0abe2cf0e24484903f5436fe0ac64163057.1769012464.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/neighbour.c

index 66f4a652510649a57654c3818c7c6eab89fff217..b6cb127a5b8e18f4d30eb6b7ed887d2c782baeac 100644 (file)
@@ -1302,6 +1302,47 @@ static void neigh_update_hhs(struct neighbour *neigh)
        }
 }
 
+static void neigh_update_process_arp_queue(struct neighbour *neigh)
+       __releases(neigh->lock)
+       __acquires(neigh->lock)
+{
+       struct sk_buff *skb;
+
+       /* Again: avoid deadlock if something went wrong. */
+       while (neigh->nud_state & NUD_VALID &&
+              (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
+               struct dst_entry *dst = skb_dst(skb);
+               struct neighbour *n2, *n1 = neigh;
+
+               write_unlock_bh(&neigh->lock);
+
+               rcu_read_lock();
+
+               /* Why not just use 'neigh' as-is?  The problem is that
+                * things such as shaper, eql, and sch_teql can end up
+                * using alternative, different, neigh objects to output
+                * the packet in the output path.  So what we need to do
+                * here is re-lookup the top-level neigh in the path so
+                * we can reinject the packet there.
+                */
+               n2 = NULL;
+               if (dst &&
+                   READ_ONCE(dst->obsolete) != DST_OBSOLETE_DEAD) {
+                       n2 = dst_neigh_lookup_skb(dst, skb);
+                       if (n2)
+                               n1 = n2;
+               }
+               READ_ONCE(n1->output)(n1, skb);
+               if (n2)
+                       neigh_release(n2);
+               rcu_read_unlock();
+
+               write_lock_bh(&neigh->lock);
+       }
+       __skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
+}
+
 /* Generic update routine.
    -- lladdr is new lladdr or NULL, if it is not supplied.
    -- new    is new state.
@@ -1461,43 +1502,10 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
                neigh_connect(neigh);
        else
                neigh_suspect(neigh);
-       if (!(old & NUD_VALID)) {
-               struct sk_buff *skb;
-
-               /* Again: avoid dead loop if something went wrong */
-
-               while (neigh->nud_state & NUD_VALID &&
-                      (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
-                       struct dst_entry *dst = skb_dst(skb);
-                       struct neighbour *n2, *n1 = neigh;
-                       write_unlock_bh(&neigh->lock);
 
-                       rcu_read_lock();
+       if (!(old & NUD_VALID))
+               neigh_update_process_arp_queue(neigh);
 
-                       /* Why not just use 'neigh' as-is?  The problem is that
-                        * things such as shaper, eql, and sch_teql can end up
-                        * using alternative, different, neigh objects to output
-                        * the packet in the output path.  So what we need to do
-                        * here is re-lookup the top-level neigh in the path so
-                        * we can reinject the packet there.
-                        */
-                       n2 = NULL;
-                       if (dst &&
-                           READ_ONCE(dst->obsolete) != DST_OBSOLETE_DEAD) {
-                               n2 = dst_neigh_lookup_skb(dst, skb);
-                               if (n2)
-                                       n1 = n2;
-                       }
-                       READ_ONCE(n1->output)(n1, skb);
-                       if (n2)
-                               neigh_release(n2);
-                       rcu_read_unlock();
-
-                       write_lock_bh(&neigh->lock);
-               }
-               __skb_queue_purge(&neigh->arp_queue);
-               neigh->arp_queue_len_bytes = 0;
-       }
 out:
        if (update_isrouter)
                neigh_update_is_router(neigh, flags, &notify);