]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
neighbour: Update pneigh_entry in pneigh_create().
authorKuniyuki Iwashima <kuniyu@google.com>
Wed, 16 Jul 2025 22:08:20 +0000 (22:08 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 17 Jul 2025 23:25:22 +0000 (16:25 -0700)
neigh_add() updates pneigh_entry() found or created by pneigh_create().

This update is serialised by RTNL, but we will remove it.

Let's move the update part to pneigh_create() and make it return errno
instead of a pointer of pneigh_entry.

Now, the pneigh code is RTNL free.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250716221221.442239-16-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/neighbour.h
net/core/neighbour.c
net/ipv4/arp.c

index f333f9ebc42594c8292bf036f5cb31e3de7f17bc..4a30bd458c5a921f316668a5d7cc42cd20ea7e57 100644 (file)
@@ -382,8 +382,9 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
                    struct sk_buff *skb);
 struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net,
                                   const void *key, struct net_device *dev);
-struct pneigh_entry *pneigh_create(struct neigh_table *tbl, struct net *net,
-                                  const void *key, struct net_device *dev);
+int pneigh_create(struct neigh_table *tbl, struct net *net, const void *key,
+                 struct net_device *dev, u32 flags, u8 protocol,
+                 bool permanent);
 int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key,
                  struct net_device *dev);
 
index d312b6323ff207943dc5f2257ea9919e5bfa53e1..4316ca3d987290e06dd3b3dc1dc7c6be4dd510e9 100644 (file)
@@ -747,24 +747,27 @@ struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
 }
 EXPORT_IPV6_MOD(pneigh_lookup);
 
-struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
-                                  struct net *net, const void *pkey,
-                                  struct net_device *dev)
+int pneigh_create(struct neigh_table *tbl, struct net *net,
+                 const void *pkey, struct net_device *dev,
+                 u32 flags, u8 protocol, bool permanent)
 {
        struct pneigh_entry *n;
        unsigned int key_len;
        u32 hash_val;
+       int err = 0;
 
        mutex_lock(&tbl->phash_lock);
 
        n = pneigh_lookup(tbl, net, pkey, dev);
        if (n)
-               goto out;
+               goto update;
 
        key_len = tbl->key_len;
        n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
-       if (!n)
+       if (!n) {
+               err = -ENOBUFS;
                goto out;
+       }
 
        write_pnet(&n->net, net);
        memcpy(n->key, pkey, key_len);
@@ -774,16 +777,20 @@ struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
        if (tbl->pconstructor && tbl->pconstructor(n)) {
                netdev_put(dev, &n->dev_tracker);
                kfree(n);
-               n = NULL;
+               err = -ENOBUFS;
                goto out;
        }
 
        hash_val = pneigh_hash(pkey, key_len);
        n->next = tbl->phash_buckets[hash_val];
        rcu_assign_pointer(tbl->phash_buckets[hash_val], n);
+update:
+       WRITE_ONCE(n->flags, flags);
+       n->permanent = permanent;
+       WRITE_ONCE(n->protocol, protocol);
 out:
        mutex_unlock(&tbl->phash_lock);
-       return n;
+       return err;
 }
 
 static void pneigh_destroy(struct rcu_head *rcu)
@@ -2015,22 +2022,13 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
        if (tb[NDA_PROTOCOL])
                protocol = nla_get_u8(tb[NDA_PROTOCOL]);
        if (ndm_flags & NTF_PROXY) {
-               struct pneigh_entry *pn;
-
                if (ndm_flags & (NTF_MANAGED | NTF_EXT_VALIDATED)) {
                        NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination");
                        goto out;
                }
 
-               err = -ENOBUFS;
-               pn = pneigh_create(tbl, net, dst, dev);
-               if (pn) {
-                       WRITE_ONCE(pn->flags, ndm_flags);
-                       pn->permanent = !!(ndm->ndm_state & NUD_PERMANENT);
-                       if (protocol)
-                               WRITE_ONCE(pn->protocol, protocol);
-                       err = 0;
-               }
+               err = pneigh_create(tbl, net, dst, dev, ndm_flags, protocol,
+                                   !!(ndm->ndm_state & NUD_PERMANENT));
                goto out;
        }
 
index d93b5735b0ba406d712ca526cfe1ff85ebf961cc..5cfc1c9396732171b79ce0aac2b0ee11ddfcbd05 100644 (file)
@@ -1089,9 +1089,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
        if (mask) {
                __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
 
-               if (!pneigh_create(&arp_tbl, net, &ip, dev))
-                       return -ENOBUFS;
-               return 0;
+               return pneigh_create(&arp_tbl, net, &ip, dev, 0, 0, false);
        }
 
        return arp_req_set_proxy(net, dev, 1);