From: Kuniyuki Iwashima <kuniyu@google.com>
To: Andrew Lunn <andrew+netdev@lunn.ch>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>
Cc: Simon Horman <horms@kernel.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
Kuniyuki Iwashima <kuni1840@gmail.com>,
netdev@vger.kernel.org
Subject: [PATCH v4 net-next 06/15] neighbour: Store arp_tbl and nd_tbl in net->neigh_tables[].
Date: Thu, 13 Aug 2026 08:02:20 +0000 [thread overview]
Message-ID: <20260813080248.407680-7-kuniyu@google.com> (raw)
In-Reply-To: <20260813080248.407680-1-kuniyu@google.com>
We will remove RTNL for neigh_add() and neigh_delete(), but they
are still serialised by per-protocol neigh_table.lock.
We can avoid contention by converting neigh_tables[] to per-netns,
but arp_tbl and nd_tbl are directly used in many places.
As a prep, let's store &arp_tbl and &nd_tbl in net->neigh_tables[].
We will replace such users with arp_table(net) and nd_table(net)
and then allocate per-netns neigh_table.
Note that nd_table() still returns &nd_tbl in case disable_ipv6_mod
is 1 because some buggy drivers use nd_tbl without checking it.
proc_create_net() is guarded with CONFIG_PROC_FS because it
returns NULL when =n and setup_net() fails and panic()s. Also
a later patch moves neigh_sysctl_register() under the guard.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
v4: Add note about CONFIG_PROC_FS
---
include/net/arp.h | 6 +++++-
include/net/ndisc.h | 9 +++++++++
include/net/neighbour.h | 2 ++
include/net/net_namespace.h | 4 ++++
net/core/neighbour.c | 12 ++++++++++++
net/ipv4/arp.c | 23 +++++++++++++++++++++--
net/ipv6/ndisc.c | 12 +++++++++++-
7 files changed, 64 insertions(+), 4 deletions(-)
diff --git a/include/net/arp.h b/include/net/arp.h
index e8747e0713c7..f8d18b1f8b28 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -7,9 +7,13 @@
#include <linux/hash.h>
#include <net/neighbour.h>
-
extern struct neigh_table arp_tbl;
+static inline struct neigh_table *arp_table(struct net *net)
+{
+ return net->neigh_tables[NEIGH_ARP_TABLE];
+}
+
static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 *hash_rnd)
{
u32 key = *(const u32 *)pkey;
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 9e5379ad2d8e..8516c7ff6e92 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -67,6 +67,15 @@ struct prefix_info;
extern struct neigh_table nd_tbl;
+static inline struct neigh_table *nd_table(struct net *net)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ if (disable_ipv6_mod)
+ return &nd_tbl;
+#endif
+ return net->neigh_tables[NEIGH_ND_TABLE];
+}
+
struct nd_msg {
struct icmp6hdr icmph;
struct in6_addr target;
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 7847c29496ae..700d62605fab 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -339,6 +339,8 @@ static inline void neigh_confirm(struct neighbour *n)
}
}
+int neigh_table_register(struct net *net, struct neigh_table *tbl, int index);
+void neigh_table_unregister(struct net *net, int index);
void neigh_table_init(int index, struct neigh_table *tbl);
int neigh_table_clear(int index, struct neigh_table *tbl);
struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 501af1999fe8..f96a390ae536 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -39,6 +39,7 @@
#include <net/netns/mctp.h>
#include <net/netns/vsock.h>
#include <net/net_trackers.h>
+#include <net/neighbour_tables.h>
#include <linux/ns_common.h>
#include <linux/idr.h>
#include <linux/skbuff.h>
@@ -47,6 +48,7 @@
struct user_namespace;
struct proc_dir_entry;
+struct neigh_table;
struct net_device;
struct sock;
struct ctl_table_header;
@@ -103,6 +105,8 @@ struct net {
struct proc_dir_entry *proc_net;
struct proc_dir_entry *proc_net_stat;
+ struct neigh_table *neigh_tables[NEIGH_NR_TABLES];
+
#ifdef CONFIG_SYSCTL
struct ctl_table_set sysctls;
#endif
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index caa52bf64a2d..286acb7cd504 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1899,6 +1899,18 @@ int neigh_table_clear(int index, struct neigh_table *tbl)
return 0;
}
+int neigh_table_register(struct net *net, struct neigh_table *tbl, int index)
+{
+ net->neigh_tables[index] = tbl;
+
+ return 0;
+}
+
+void neigh_table_unregister(struct net *net, int index)
+{
+ net->neigh_tables[index] = NULL;
+}
+
static struct neigh_table *neigh_find_table(int family)
{
struct neigh_table *tbl = NULL;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index d409f606aec0..bad17d5aeafc 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1495,15 +1495,34 @@ static const struct seq_operations arp_seq_ops = {
static int __net_init arp_net_init(struct net *net)
{
+ int err;
+
+ err = neigh_table_register(net, &arp_tbl, NEIGH_ARP_TABLE);
+ if (err)
+ goto err;
+
+#ifdef CONFIG_PROC_FS
if (!proc_create_net("arp", 0444, net->proc_net, &arp_seq_ops,
- sizeof(struct neigh_seq_state)))
- return -ENOMEM;
+ sizeof(struct neigh_seq_state))) {
+ err = -ENOMEM;
+ goto err_proc_create;
+ }
+#endif
+
return 0;
+
+#ifdef CONFIG_PROC_FS
+err_proc_create:
+ neigh_table_unregister(net, NEIGH_ARP_TABLE);
+#endif
+err:
+ return err;
}
static void __net_exit arp_net_exit(struct net *net)
{
remove_proc_entry("arp", net->proc_net);
+ neigh_table_unregister(net, NEIGH_ARP_TABLE);
}
static struct pernet_operations arp_net_ops = {
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2ceb655c4229..7af1ba5084bd 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1972,12 +1972,16 @@ static int __net_init ndisc_net_init(struct net *net)
struct sock *sk;
int err;
+ err = neigh_table_register(net, &nd_tbl, NEIGH_ND_TABLE);
+ if (err)
+ goto err;
+
err = inet_ctl_sock_create(&sk, PF_INET6,
SOCK_RAW, IPPROTO_ICMPV6, net);
if (err < 0) {
net_err_ratelimited("NDISC: Failed to initialize the control socket (err %d)\n",
err);
- return err;
+ goto err_sock_create;
}
net->ipv6.ndisc_sk = sk;
@@ -1988,11 +1992,17 @@ static int __net_init ndisc_net_init(struct net *net)
inet6_clear_bit(MC6_LOOP, sk);
return 0;
+
+err_sock_create:
+ neigh_table_unregister(net, NEIGH_ND_TABLE);
+err:
+ return err;
}
static void __net_exit ndisc_net_exit(struct net *net)
{
inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
+ neigh_table_unregister(net, NEIGH_ND_TABLE);
}
static struct pernet_operations ndisc_net_ops = {
--
2.55.0.691.gc56d675ccc-goog
next prev parent reply other threads:[~2026-08-13 8:02 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-13 8:02 [PATCH v4 net-next 00/15] neighbour: Namespacify arp_tbl and nd_tbl Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 01/15] selftest: net: Deflake Periodic GC test in test_neigh.sh Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 02/15] neighbour: Remove __neigh_for_each_release() Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 03/15] neighbour: Remove lock dance for neigh_update_{gc,managed}_list() Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 04/15] neighbour: Remove unnecessary EXPORT_SYMBOL() Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 05/15] neighbour: Remove __rcu from neigh_tables[] Kuniyuki Iwashima
2026-08-13 8:02 ` Kuniyuki Iwashima [this message]
2026-08-13 8:02 ` [PATCH v4 net-next 07/15] neighbour: Remove neigh_tables[] Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 08/15] ipv4: Replace &arp_tbl with arp_table(net) Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 09/15] ipv6: Replace &nd_tbl with nd_table(net) Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 10/15] neighbour: Clean up neigh_table_init() and neigh_table_clear() Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 11/15] neighbour: Convert neigh_table.entries to refcount_t Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 12/15] neighbour: Namespacify neigh_tables Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 13/15] neighbour: Don't store net in struct pneigh_entry Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 14/15] neighbour: Remove unnecessary net_eq() Kuniyuki Iwashima
2026-08-13 8:02 ` [PATCH v4 net-next 15/15] selftest: net: Specify netns for ip ntable in test_neigh.sh Kuniyuki Iwashima
2026-08-13 15:32 ` [PATCH v4 net-next 00/15] neighbour: Namespacify arp_tbl and nd_tbl Nikolay Aleksandrov
2026-08-17 17:57 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260813080248.407680-7-kuniyu@google.com \
--to=kuniyu@google.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=kuni1840@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.