]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
neighbour: add support for NUD_PERMANENT proxy entries
authorNicolas Escande <nico.escande@gmail.com>
Tue, 17 Jun 2025 14:13:34 +0000 (16:13 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Aug 2025 16:30:37 +0000 (18:30 +0200)
[ Upstream commit c7d78566bbd30544a0618a6ffbc97bc0ddac7035 ]

As discussesd before in [0] proxy entries (which are more configuration
than runtime data) should stay when the link (carrier) goes does down.
This is what happens for regular neighbour entries.

So lets fix this by:
  - storing in proxy entries the fact that it was added as NUD_PERMANENT
  - not removing NUD_PERMANENT proxy entries when the carrier goes down
    (same as how it's done in neigh_flush_dev() for regular neigh entries)

[0]: https://lore.kernel.org/netdev/c584ef7e-6897-01f3-5b80-12b53f7b4bf4@kernel.org/

Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250617141334.3724863-1-nico.escande@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/neighbour.h
net/core/neighbour.c

index a44f262a73841517c4eea96f594e8a2d66658a8f..cb5f835a5d61b4f883282c647d37abb3c134d3c0 100644 (file)
@@ -180,6 +180,7 @@ struct pneigh_entry {
        netdevice_tracker       dev_tracker;
        u32                     flags;
        u8                      protocol;
+       bool                    permanent;
        u32                     key[];
 };
 
index 8082cc6be4fc1b73fc00d68b43bbb1ed2011cc3a..96786016dbb4ef89ceec3d73c2bc6dd2afe707c5 100644 (file)
@@ -55,7 +55,8 @@ static void __neigh_notify(struct neighbour *n, int type, int flags,
                           u32 pid);
 static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
 static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
-                                   struct net_device *dev);
+                                   struct net_device *dev,
+                                   bool skip_perm);
 
 #ifdef CONFIG_PROC_FS
 static const struct seq_operations neigh_stat_seq_ops;
@@ -444,7 +445,7 @@ static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
 {
        write_lock_bh(&tbl->lock);
        neigh_flush_dev(tbl, dev, skip_perm);
-       pneigh_ifdown_and_unlock(tbl, dev);
+       pneigh_ifdown_and_unlock(tbl, dev, skip_perm);
        pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL,
                           tbl->family);
        if (skb_queue_empty_lockless(&tbl->proxy_queue))
@@ -847,7 +848,8 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
 }
 
 static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
-                                   struct net_device *dev)
+                                   struct net_device *dev,
+                                   bool skip_perm)
 {
        struct pneigh_entry *n, **np, *freelist = NULL;
        u32 h;
@@ -855,12 +857,15 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
        for (h = 0; h <= PNEIGH_HASHMASK; h++) {
                np = &tbl->phash_buckets[h];
                while ((n = *np) != NULL) {
+                       if (skip_perm && n->permanent)
+                               goto skip;
                        if (!dev || n->dev == dev) {
                                *np = n->next;
                                n->next = freelist;
                                freelist = n;
                                continue;
                        }
+skip:
                        np = &n->next;
                }
        }
@@ -2041,6 +2046,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
                pn = pneigh_lookup(tbl, net, dst, dev, 1);
                if (pn) {
                        pn->flags = ndm_flags;
+                       pn->permanent = !!(ndm->ndm_state & NUD_PERMANENT);
                        if (protocol)
                                pn->protocol = protocol;
                        err = 0;