* [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends.
@ 2026-10-03 21:23 Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 1/9] ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup() Kuniyuki Iwashima
` (11 more replies)
0 siblings, 12 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
syzbot reported that ip6_finish_output2() could pass tbl and dev
from different netns to neigh_create().
When namespacifying neigh_table, I chose to resolve neigh_table
in callers to minimise changes, but it turned out to be error-prone.
This series adds IPv4/IPv6-specific helpers for neigh_lookup()
and neigh_create() that always fetch the netns from dev to fix
the problem.
Along the way, the confusing and now mostly redundant helpers
__neigh_lookup() and __neigh_lookup_errno() are converted and
removed.
Changes:
v2:
* Add Patch 9
* Patch 6 & 7: Convert __teql_resolve()
v1: https://lore.kernel.org/netdev/20260930200326.718459-1-kuniyu@google.com/
Kuniyuki Iwashima (9):
ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup().
ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup().
ipv4: Add wrappers for neigh_lookup() and neigh_create().
ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create().
mlxsw: spectrum: Resolve neigh_table right before neigh_lookup().
ipv6: Use ipv6_neigh_lookup() and friends.
ipv4: Use ipv4_neigh_lookup() and friends.
neighbour: Remove __neigh_lookup() and __neigh_lookup_errno().
neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create().
.../marvell/prestera/prestera_router.c | 14 ++--
.../mellanox/mlx5/core/en/tc_tun_encap.c | 14 ++--
.../mellanox/mlx5/core/en_accel/ipsec.c | 6 +-
.../ethernet/mellanox/mlxsw/spectrum_router.c | 77 +++++++++++--------
.../ethernet/mellanox/mlxsw/spectrum_span.c | 42 ++++++----
.../netronome/nfp/flower/tunnel_conf.c | 8 +-
drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +-
drivers/net/ethernet/sfc/tc_counters.c | 11 +--
drivers/net/vrf.c | 4 +-
drivers/net/vxlan/vxlan_core.c | 14 +---
include/net/arp.h | 16 ++++
include/net/ip6_route.h | 6 +-
include/net/ndisc.h | 31 ++++++--
include/net/neighbour.h | 24 ------
net/bridge/br_arp_nd_proxy.c | 4 +-
net/core/neighbour.c | 11 ++-
net/ieee802154/6lowpan/tx.c | 3 +-
net/ipv4/arp.c | 26 ++++---
net/ipv4/fib_semantics.c | 5 +-
net/ipv4/route.c | 18 ++---
net/ipv6/ip6_output.c | 2 +-
net/ipv6/ndisc.c | 48 +++++++-----
net/ipv6/route.c | 23 +++---
net/sched/sch_teql.c | 15 +++-
24 files changed, 234 insertions(+), 190 deletions(-)
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 1/9] ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 2/9] ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup() Kuniyuki Iwashima
` (10 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
Later, we will add ipv4_neigh_lookup() as a wrapper for
neigh_lookup(arp_table(net), ...).
The existing ipv4_neigh_lookup() is more like ip6_dst_neigh_lookup().
Let's rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv4/route.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index d7da2f1acbb5..50c842617e45 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -146,9 +146,9 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)
return NULL;
}
-static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
- struct sk_buff *skb,
- const void *daddr);
+static struct neighbour *ipv4_dst_neigh_lookup(const struct dst_entry *dst,
+ struct sk_buff *skb,
+ const void *daddr);
static void ipv4_confirm_neigh(const struct dst_entry *dst, const void *daddr);
static struct dst_ops ipv4_dst_ops = {
@@ -163,7 +163,7 @@ static struct dst_ops ipv4_dst_ops = {
.update_pmtu = ip_rt_update_pmtu,
.redirect = ip_do_redirect,
.local_out = __ip_local_out,
- .neigh_lookup = ipv4_neigh_lookup,
+ .neigh_lookup = ipv4_dst_neigh_lookup,
.confirm_neigh = ipv4_confirm_neigh,
};
@@ -409,9 +409,9 @@ void rt_cache_flush(struct net *net)
rt_genid_bump_ipv4(net);
}
-static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
- struct sk_buff *skb,
- const void *daddr)
+static struct neighbour *ipv4_dst_neigh_lookup(const struct dst_entry *dst,
+ struct sk_buff *skb,
+ const void *daddr)
{
const struct rtable *rt = container_of(dst, struct rtable, dst);
struct net_device *dev;
@@ -2910,7 +2910,7 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
static struct dst_ops ipv4_dst_blackhole_ops = {
.family = AF_INET,
.default_advmss = ipv4_default_advmss,
- .neigh_lookup = ipv4_neigh_lookup,
+ .neigh_lookup = ipv4_dst_neigh_lookup,
.check = dst_blackhole_check,
.cow_metrics = dst_blackhole_cow_metrics,
.update_pmtu = dst_blackhole_update_pmtu,
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 2/9] ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 1/9] ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup() Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 3/9] ipv4: Add wrappers for neigh_lookup() and neigh_create() Kuniyuki Iwashima
` (9 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
Later, we will add ipv6_neigh_lookup() as a wrapper for
neigh_lookup(nd_table(net), ...).
The existing ip6_neigh_lookup() is called from ip6_dst_neigh_lookup()
with a gateway address.
Let's rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/net/ip6_route.h | 6 +++---
net/ipv6/ndisc.c | 12 ++++++------
net/ipv6/route.c | 12 ++++++------
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 0f9b7a260d25..5a21ed4b6e1c 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -430,7 +430,7 @@ u32 ip6_mtu_from_fib6(const struct fib6_result *res,
const struct in6_addr *daddr,
const struct in6_addr *saddr);
-struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
- struct net_device *dev, struct sk_buff *skb,
- const void *daddr);
+struct neighbour *__ip6_dst_neigh_lookup(const struct in6_addr *gw,
+ struct net_device *dev, struct sk_buff *skb,
+ const void *daddr);
#endif
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 12d85d7f8234..e1cbffaa0ad0 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1359,9 +1359,9 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
/* routes added from RAs do not use nexthop objects */
rt = rt6_get_dflt_router(net, &ipv6_hdr(skb)->saddr, skb->dev);
if (rt) {
- neigh = ip6_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,
- rt->fib6_nh->fib_nh_dev, NULL,
- &ipv6_hdr(skb)->saddr);
+ neigh = __ip6_dst_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,
+ rt->fib6_nh->fib_nh_dev, NULL,
+ &ipv6_hdr(skb)->saddr);
if (!neigh) {
net_err_ratelimited("RA: %s got default router without neighbour\n",
__func__);
@@ -1395,9 +1395,9 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
return reason;
}
- neigh = ip6_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,
- rt->fib6_nh->fib_nh_dev, NULL,
- &ipv6_hdr(skb)->saddr);
+ neigh = __ip6_dst_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,
+ rt->fib6_nh->fib_nh_dev, NULL,
+ &ipv6_hdr(skb)->saddr);
if (!neigh) {
net_err_ratelimited("RA: %s got default router without neighbour\n",
__func__);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a76869ff87cd..8baac4d85251 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -206,10 +206,10 @@ static inline const void *choose_neigh_daddr(const struct in6_addr *p,
return daddr;
}
-struct neighbour *ip6_neigh_lookup(const struct in6_addr *gw,
- struct net_device *dev,
- struct sk_buff *skb,
- const void *daddr)
+struct neighbour *__ip6_dst_neigh_lookup(const struct in6_addr *gw,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ const void *daddr)
{
struct neighbour *n;
@@ -228,8 +228,8 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst,
{
const struct rt6_info *rt = dst_rt6_info(dst);
- return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any),
- dst_dev(dst), skb, daddr);
+ return __ip6_dst_neigh_lookup(rt6_nexthop(rt, &in6addr_any),
+ dst_dev(dst), skb, daddr);
}
static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 3/9] ipv4: Add wrappers for neigh_lookup() and neigh_create().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 1/9] ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 2/9] ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup() Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 4/9] ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create() Kuniyuki Iwashima
` (8 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
neigh_lookup() accepts struct neigh_table *tbl and struct
net_device *dev, and both of them must exist in the same
netns.
It is error-prone to require callers to fetch a netns and
get neigh_table, which might belong to a different netns
than dev_net(dev).
Let's add IPv4-specific wrappers for neigh_lookup() and
neigh_create() that always fetch netns from dev.
Note that we do not add wrappers for __neigh_lookup() and
__neigh_lookup_errno(), which we will remove later.
__neigh_lookup_errno() is a simple combo of neigh_lookup()
and neigh_create(). __neigh_lookup() is almost the same
but converts errno from neigh_create() to NULL.
So both names are confusing.
For IPv4, __neigh_lookup_errno() is only used in arp_req_set()
and is not worth a new wrapper. Instead, it should be inlined.
arp_process() uses __neigh_lookup(create=0) but it should
simply be neigh_lookup(), and then __neigh_lookup(create=1)
is only used in arp_process(), so this should be inlined too.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/net/arp.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/include/net/arp.h b/include/net/arp.h
index e932def63d62..329a5456987a 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -51,6 +51,22 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32
return n;
}
+static inline struct neighbour *ipv4_neigh_lookup(struct net_device *dev,
+ const void *pkey)
+{
+ struct neigh_table *tbl = arp_table(dev_net(dev));
+
+ return neigh_lookup(tbl, pkey, dev);
+}
+
+static inline struct neighbour *ipv4_neigh_create(struct net_device *dev,
+ const void *pkey)
+{
+ struct neigh_table *tbl = arp_table(dev_net(dev));
+
+ return neigh_create(tbl, pkey, dev);
+}
+
static inline void __ipv4_confirm_neigh(struct net_device *dev, u32 key)
{
struct neighbour *n;
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 4/9] ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (2 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 3/9] ipv4: Add wrappers for neigh_lookup() and neigh_create() Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 5/9] mlxsw: spectrum: Resolve neigh_table right before neigh_lookup() Kuniyuki Iwashima
` (7 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
neigh_lookup() accepts struct neigh_table *tbl and struct
net_device *dev, and both of them must exist in the same
netns.
It is error-prone to require callers to fetch a netns and
get neigh_table, which might belong to a different netns
than dev_net(dev).
Let's add IPv6-specific wrappers for neigh_lookup() and
(__)?neigh_create() that always fetch netns from dev.
Similar to IPv4, we do not add wrappers for __neigh_lookup()
since 3 out of 4 users call it with create=1, which should be
simply written as neigh_lookup() and neigh_create().
IPv6 has 3 callers of __neigh_create(want_ref=false), so
ipv6_neigh_create_noref() is also added.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/net/ndisc.h | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 96e3bb6e83af..2fce6fccf55a 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -381,6 +381,30 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
return n;
}
+static inline struct neighbour *ipv6_neigh_lookup(struct net_device *dev,
+ const void *pkey)
+{
+ struct neigh_table *tbl = nd_table(dev_net(dev));
+
+ return neigh_lookup(tbl, pkey, dev);
+}
+
+static inline struct neighbour *ipv6_neigh_create(struct net_device *dev,
+ const void *pkey)
+{
+ struct neigh_table *tbl = nd_table(dev_net(dev));
+
+ return neigh_create(tbl, pkey, dev);
+}
+
+static inline struct neighbour *ipv6_neigh_create_noref(struct net_device *dev,
+ const void *pkey)
+{
+ struct neigh_table *tbl = nd_table(dev_net(dev));
+
+ return __neigh_create(tbl, pkey, dev, false);
+}
+
static inline void __ipv6_confirm_neigh(struct net_device *dev,
const void *pkey)
{
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 5/9] mlxsw: spectrum: Resolve neigh_table right before neigh_lookup().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (3 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 4/9] ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create() Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends Kuniyuki Iwashima
` (6 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev,
Petr Machata
We will replace neigh_lookup() and neigh_create() with
IPv4/IPv6-specific helpers.
mlxsw has two paths where neigh_table is fetched in advance
and passed down to a function which calls neigh_lookup() and
neigh_create().
To keep the changes simple, let's prepare them beforehand
by delaying the neigh_table resolution until right before
neigh_lookup().
struct mlxsw_sp_nexthop caches neigh_tbl, so it is replaced with
family, and a new helper, mlxsw_sp_nexthop_neigh_lookup(),
resolves neigh_table and calls neigh_lookup() and neigh_create().
Similarly, mlxsw_sp_span_entry_gretap[46]_parms() now pass family
to mlxsw_sp_span_dmac() to resolve neigh_table there just before
neigh_lookup() and neigh_create().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
Cc: Petr Machata <petrm@nvidia.com>
---
.../ethernet/mellanox/mlxsw/spectrum_router.c | 65 ++++++++++++-------
.../ethernet/mellanox/mlxsw/spectrum_span.c | 31 +++++----
2 files changed, 58 insertions(+), 38 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index f4a435885ba4..ba8a7a44ce9e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3072,9 +3072,9 @@ struct mlxsw_sp_nexthop {
* this nexthop belongs to
*/
struct rhash_head ht_node;
- struct neigh_table *neigh_tbl;
struct mlxsw_sp_nexthop_key key;
unsigned char gw_addr[sizeof(struct in6_addr)];
+ int family;
int ifindex;
int nh_weight;
int norm_nh_weight;
@@ -4300,28 +4300,49 @@ static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
nh->update = 1;
}
+static struct neighbour *
+mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
+{
+ struct neigh_table *tbl;
+ struct net_device *dev;
+ struct neighbour *n;
+ struct net *net;
+
+ dev = mlxsw_sp_nexthop_dev(nh);
+ net = dev_net(dev);
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (nh->family == AF_INET6)
+ tbl = nd_table(net);
+ else
+#endif
+ tbl = arp_table(net);
+
+ n = neigh_lookup(tbl, &nh->gw_addr, dev);
+ if (!n) {
+ n = neigh_create(tbl, &nh->gw_addr, dev);
+ if (!IS_ERR(n))
+ neigh_event_send(n, NULL);
+ }
+
+ return n;
+}
+
static int
mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
struct neighbour *n, *old_n = neigh_entry->key.n;
struct mlxsw_sp_nexthop *nh;
- struct net_device *dev;
bool entry_connected;
u8 nud_state, dead;
int err;
nh = list_first_entry(&neigh_entry->nexthop_list,
struct mlxsw_sp_nexthop, neigh_list_node);
- dev = mlxsw_sp_nexthop_dev(nh);
-
- n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, dev);
- if (!n) {
- n = neigh_create(nh->neigh_tbl, &nh->gw_addr, dev);
- if (IS_ERR(n))
- return PTR_ERR(n);
- neigh_event_send(n, NULL);
- }
+ n = mlxsw_sp_nexthop_neigh_lookup(nh);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
mlxsw_sp_neigh_entry_remove(mlxsw_sp, neigh_entry);
neigh_entry->key.n = n;
@@ -4402,7 +4423,6 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh)
{
struct mlxsw_sp_neigh_entry *neigh_entry;
- struct net_device *dev;
struct neighbour *n;
u8 nud_state, dead;
int err;
@@ -4412,20 +4432,16 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
if (!nh->nhgi->gateway || nh->neigh_entry)
return 0;
- dev = mlxsw_sp_nexthop_dev(nh);
/* Take a reference of neigh here ensuring that neigh would
* not be destructed before the nexthop entry is finished.
* The reference is taken either in neigh_lookup() or
* in neigh_create() in case n is not found.
*/
- n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, dev);
- if (!n) {
- n = neigh_create(nh->neigh_tbl, &nh->gw_addr, dev);
- if (IS_ERR(n))
- return PTR_ERR(n);
- neigh_event_send(n, NULL);
- }
+ n = mlxsw_sp_nexthop_neigh_lookup(nh);
+ if (IS_ERR(n))
+ return PTR_ERR(n);
+
neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
if (!neigh_entry) {
neigh_entry = mlxsw_sp_neigh_entry_create(mlxsw_sp, n);
@@ -4630,7 +4646,7 @@ static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp,
nh->nh_weight = 1;
#endif
memcpy(&nh->gw_addr, &fib_nh->fib_nh_gw4, sizeof(fib_nh->fib_nh_gw4));
- nh->neigh_tbl = arp_table(mlxsw_sp_net(mlxsw_sp));
+ nh->family = AF_INET;
err = mlxsw_sp_nexthop_insert(mlxsw_sp, nh);
if (err)
return err;
@@ -5120,7 +5136,6 @@ mlxsw_sp_nexthop_obj_init(struct mlxsw_sp *mlxsw_sp,
struct nh_notifier_single_info *nh_obj, int weight)
{
struct net_device *dev = nh_obj->dev;
- struct net *net = dev_net(dev);
int err;
nh->nhgi = nh_grp->nhgi;
@@ -5129,12 +5144,12 @@ mlxsw_sp_nexthop_obj_init(struct mlxsw_sp *mlxsw_sp,
switch (nh_obj->gw_family) {
case AF_INET:
memcpy(&nh->gw_addr, &nh_obj->ipv4, sizeof(nh_obj->ipv4));
- nh->neigh_tbl = arp_table(net);
+ nh->family = AF_INET;
break;
case AF_INET6:
memcpy(&nh->gw_addr, &nh_obj->ipv6, sizeof(nh_obj->ipv6));
#if IS_ENABLED(CONFIG_IPV6)
- nh->neigh_tbl = nd_table(net);
+ nh->family = AF_INET6;
#endif
break;
}
@@ -6990,7 +7005,7 @@ static int mlxsw_sp_nexthop6_init(struct mlxsw_sp *mlxsw_sp,
nh->nh_weight = rt->fib6_nh->fib_nh_weight;
memcpy(&nh->gw_addr, &rt->fib6_nh->fib_nh_gw6, sizeof(nh->gw_addr));
#if IS_ENABLED(CONFIG_IPV6)
- nh->neigh_tbl = nd_table(mlxsw_sp_net(mlxsw_sp));
+ nh->family = AF_INET6;
#endif
err = mlxsw_sp_nexthop_counter_enable(mlxsw_sp, nh);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index 1cd8347c274d..d34d2040177b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -224,14 +224,24 @@ struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = {
.deconfigure = mlxsw_sp_span_entry_phys_deconfigure,
};
-static int mlxsw_sp_span_dmac(struct neigh_table *tbl,
+static int mlxsw_sp_span_dmac(int family,
const void *pkey,
struct net_device *dev,
unsigned char dmac[ETH_ALEN])
{
- struct neighbour *neigh = neigh_lookup(tbl, pkey, dev);
+ struct net *net = dev_net(dev);
+ struct neigh_table *tbl;
+ struct neighbour *neigh;
int err = 0;
+#if IS_ENABLED(CONFIG_IPV6_GRE)
+ if (family == AF_INET6)
+ tbl = nd_table(net);
+ else
+#endif
+ tbl = arp_table(net);
+
+ neigh = neigh_lookup(tbl, pkey, dev);
if (!neigh) {
neigh = neigh_create(tbl, pkey, dev);
if (IS_ERR(neigh))
@@ -355,8 +365,7 @@ mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *edev,
union mlxsw_sp_l3addr saddr,
union mlxsw_sp_l3addr daddr,
union mlxsw_sp_l3addr gw,
- __u8 ttl,
- struct neigh_table *tbl,
+ __u8 ttl, int family,
struct mlxsw_sp_span_parms *sparmsp)
{
unsigned char dmac[ETH_ALEN];
@@ -365,7 +374,7 @@ mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *edev,
if (mlxsw_sp_l3addr_is_zero(gw))
gw = daddr;
- if (!edev || mlxsw_sp_span_dmac(tbl, &gw, edev, dmac))
+ if (!edev || mlxsw_sp_span_dmac(family, &gw, edev, dmac))
goto unoffloadable;
if (is_vlan_dev(edev))
@@ -456,7 +465,6 @@ mlxsw_sp_span_entry_gretap4_parms(struct mlxsw_sp *mlxsw_sp,
bool inherit_tos = tparm.iph.tos & 0x1;
bool inherit_ttl = !tparm.iph.ttl;
union mlxsw_sp_l3addr gw = daddr;
- struct neigh_table *tbl = NULL;
struct net_device *l3edev;
if (!(to_dev->flags & IFF_UP) ||
@@ -470,11 +478,10 @@ mlxsw_sp_span_entry_gretap4_parms(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_span_entry_unoffloadable(sparmsp);
l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4);
- if (l3edev)
- tbl = arp_table(dev_net(l3edev));
+
return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
tparm.iph.ttl,
- tbl, sparmsp);
+ AF_INET, sparmsp);
}
static int
@@ -564,7 +571,6 @@ mlxsw_sp_span_entry_gretap6_parms(struct mlxsw_sp *mlxsw_sp,
union mlxsw_sp_l3addr daddr = { .addr6 = tparm.raddr };
bool inherit_ttl = !tparm.hop_limit;
union mlxsw_sp_l3addr gw = daddr;
- struct neigh_table *tbl = NULL;
struct net_device *l3edev;
if (!(to_dev->flags & IFF_UP) ||
@@ -578,11 +584,10 @@ mlxsw_sp_span_entry_gretap6_parms(struct mlxsw_sp *mlxsw_sp,
return mlxsw_sp_span_entry_unoffloadable(sparmsp);
l3edev = mlxsw_sp_span_gretap6_route(to_dev, &saddr.addr6, &gw.addr6);
- if (l3edev)
- tbl = nd_table(dev_net(l3edev));
+
return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
tparm.hop_limit,
- tbl, sparmsp);
+ AF_INET6, sparmsp);
}
static int
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends.
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (4 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 5/9] mlxsw: spectrum: Resolve neigh_table right before neigh_lookup() Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-06 17:53 ` Fernando Fernandez Mancera
2026-10-03 21:23 ` [PATCH v2 net-next 7/9] ipv4: Use ipv4_neigh_lookup() " Kuniyuki Iwashima
` (5 subsequent siblings)
11 siblings, 1 reply; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev,
syzbot+5a8857f0b4a0a7b12c62, Saeed Mahameed, Leon Romanovsky,
Tariq Toukan, Mark Bloch, Petr Machata, Edward Cree,
Nikolay Aleksandrov, Alexander Aring, Stefan Schmidt,
Miquel Raynal
syzbot reported the splat below in neigh_mark_dead() [0]
where tbl->lock was not held while neigh_ifdown() should
have acquired one.
This only happens when a neigh_table accidentally has a
neighbour from a different netns.
In ip6_finish_output2(), the net argument is the caller's and
does not always match dev_net(dev) fetched from dst. (e.g. xfrm)
It is error-prone to require callers to fetch netns and
neigh_table and pass it with dev to neigh_lookup(), etc.
Let's replace neigh_lookup() and friends with IPv6 helpers.
Note that __neigh_lookup() is split into ipv6_neigh_lookup()
and ipv6_neigh_create().
[0]:
debug_locks && !(lock_is_held(&(&n->tbl->lock)->dep_map) != 0)
WARNING: net/core/neighbour.c:154 at neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154, CPU#0: syz.0.857/9765
Modules linked in:
CPU: 0 UID: 0 PID: 9765 Comm: syz.0.857 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
RIP: 0010:neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154
Code: e8 03 42 80 3c 28 00 74 08 48 89 df e8 ee 9a 80 f8 4c 89 33 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc e8 86 95 10 f8 90 <0f> 0b 90 e9 8f fd ff ff 48 c7 c1 80 9a 7a 90 80 e1 07 80 c1 03 38
RSP: 0018:ffffc90003726600 EFLAGS: 00010287
RAX: ffffffff89b7467a RBX: ffff888022e86000 RCX: 0000000000080000
RDX: ffffc900047fa000 RSI: 0000000000003e08 RDI: 0000000000003e09
RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000004
R10: dffffc0000000000 R11: fffff520006e4cb8 R12: ffff888022e8613c
R13: dffffc0000000000 R14: ffff888022e86020 R15: ffff888022e86000
FS: 00007f9c30f046c0(0000) GS:ffff888124cc6000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000076c56000 CR4: 00000000003526f0
Call Trace:
<TASK>
neigh_flush_one+0x27c/0x5a0 net/core/neighbour.c:388
neigh_flush_dev net/core/neighbour.c:432 [inline]
__neigh_ifdown+0x1fb/0xc70 net/core/neighbour.c:465
neigh_ifdown+0x1f/0x30 net/core/neighbour.c:487
rt6_disable_ip+0x751/0x7e0 net/ipv6/route.c:5058
addrconf_ifdown+0x155/0x1ad0 net/ipv6/addrconf.c:3892
addrconf_notify+0x1bc/0x1050 net/ipv6/addrconf.c:-1
notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85
call_netdevice_notifiers_mtu net/core/dev.c:2350 [inline]
netif_set_mtu_ext+0x5ac/0x830 net/core/dev.c:9963
do_setlink+0xa81/0x47a0 net/core/rtnetlink.c:3247
rtnl_setlink+0x578/0x820 net/core/rtnetlink.c:3623
rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7159
netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572
netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline]
netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361
netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916
sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800
__sock_sendmsg net/socket.c:815 [inline]
sock_write_iter+0x2de/0x3e0 net/socket.c:1266
do_iter_readv_writev+0x612/0x8c0 fs/read_write.c:-1
vfs_writev+0x343/0x990 fs/read_write.c:1058
do_writev+0x154/0x2e0 fs/read_write.c:1104
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f9c2ff9e159
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f9c30f04028 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
RAX: ffffffffffffffda RBX: 00007f9c30225fa0 RCX: 00007f9c2ff9e159
RDX: 0000000000000001 RSI: 00002000000003c0 RDI: 0000000000000004
RBP: 00007f9c3003506b R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f9c30226038 R14: 00007f9c30225fa0 R15: 00007ffed3c74808
</TASK>
Fixes: df5f4f372de5 ("ipv6: Replace &nd_tbl with nd_table(net).")
Reported-by: syzbot+5a8857f0b4a0a7b12c62@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6abd69a9.80e1c6cc.22483f.0005.GAE@google.com/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
v2: Convert __teql_resolve()
Cc: Saeed Mahameed <saeedm@nvidia.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Tariq Toukan <tariqt@nvidia.com>
Cc: Mark Bloch <mbloch@nvidia.com>
Cc: Petr Machata <petrm@nvidia.com>
Cc: Edward Cree <ecree.xilinx@gmail.com>
Cc: Nikolay Aleksandrov <razor@blackwall.org>
Cc: Alexander Aring <alex.aring@gmail.com>
Cc: Stefan Schmidt <stefan@datenfreihafen.org>
Cc: Miquel Raynal <miquel.raynal@bootlin.com>
---
.../mellanox/mlx5/core/en/tc_tun_encap.c | 13 +++----
.../ethernet/mellanox/mlxsw/spectrum_router.c | 29 ++++++++-------
.../ethernet/mellanox/mlxsw/spectrum_span.c | 24 ++++++++-----
.../netronome/nfp/flower/tunnel_conf.c | 4 +--
drivers/net/ethernet/sfc/tc_counters.c | 5 ++-
drivers/net/vrf.c | 4 +--
drivers/net/vxlan/vxlan_core.c | 6 ++--
include/net/ndisc.h | 7 ++--
net/bridge/br_arp_nd_proxy.c | 2 +-
net/ieee802154/6lowpan/tx.c | 3 +-
net/ipv4/fib_semantics.c | 2 +-
net/ipv6/ip6_output.c | 2 +-
net/ipv6/ndisc.c | 36 ++++++++++++-------
net/ipv6/route.c | 11 +++---
net/sched/sch_teql.c | 12 ++++++-
15 files changed, 90 insertions(+), 70 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
index 67c12ca19d59..fe0258375ef6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
@@ -439,21 +439,18 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
if (neigh_used) {
struct net_device *dev = READ_ONCE(nhe->neigh_dev);
struct net *net = dev_net(dev);
- struct neigh_table *tbl;
nhe->reported_lastuse = jiffies;
+ /* find the relevant neigh according to the cached device and
+ * dst ip pair
+ */
#if IS_ENABLED(CONFIG_IPV6)
if (m_neigh->family != AF_INET)
- tbl = nd_table(net);
+ n = ipv6_neigh_lookup(dev, &m_neigh->dst_ip);
else
#endif
- tbl = arp_table(net);
-
- /* find the relevant neigh according to the cached device and
- * dst ip pair
- */
- n = neigh_lookup(tbl, &m_neigh->dst_ip, dev);
+ n = neigh_lookup(arp_table(net), &m_neigh->dst_ip, dev);
if (!n)
return;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index ba8a7a44ce9e..1f4753213b9c 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -2449,8 +2449,6 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
char *rauhtd_pl,
int rec_index)
{
- struct net *net = mlxsw_sp_net(mlxsw_sp);
- struct neigh_table *tbl;
struct net_device *dev;
struct neighbour *n;
struct in6_addr dip;
@@ -2464,9 +2462,8 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
return;
}
- tbl = nd_table(net);
dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
- n = neigh_lookup(tbl, &dip, dev);
+ n = ipv6_neigh_lookup(dev, &dip);
if (!n)
return;
@@ -4312,17 +4309,23 @@ mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
net = dev_net(dev);
#if IS_ENABLED(CONFIG_IPV6)
- if (nh->family == AF_INET6)
- tbl = nd_table(net);
- else
+ if (nh->family == AF_INET6) {
+ n = ipv6_neigh_lookup(dev, &nh->gw_addr);
+ if (!n) {
+ n = ipv6_neigh_create(dev, &nh->gw_addr);
+ if (!IS_ERR(n))
+ neigh_event_send(n, NULL);
+ }
+ } else
#endif
+ {
tbl = arp_table(net);
-
- n = neigh_lookup(tbl, &nh->gw_addr, dev);
- if (!n) {
- n = neigh_create(tbl, &nh->gw_addr, dev);
- if (!IS_ERR(n))
- neigh_event_send(n, NULL);
+ n = neigh_lookup(tbl, &nh->gw_addr, dev);
+ if (!n) {
+ n = neigh_create(tbl, &nh->gw_addr, dev);
+ if (!IS_ERR(n))
+ neigh_event_send(n, NULL);
+ }
}
return n;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index d34d2040177b..79947f68b10d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -235,17 +235,23 @@ static int mlxsw_sp_span_dmac(int family,
int err = 0;
#if IS_ENABLED(CONFIG_IPV6_GRE)
- if (family == AF_INET6)
- tbl = nd_table(net);
- else
+ if (family == AF_INET6) {
+ neigh = ipv6_neigh_lookup(dev, pkey);
+ if (!neigh) {
+ neigh = ipv6_neigh_create(dev, pkey);
+ if (IS_ERR(neigh))
+ return PTR_ERR(neigh);
+ }
+ } else
#endif
+ {
tbl = arp_table(net);
-
- neigh = neigh_lookup(tbl, pkey, dev);
- if (!neigh) {
- neigh = neigh_create(tbl, pkey, dev);
- if (IS_ERR(neigh))
- return PTR_ERR(neigh);
+ neigh = neigh_lookup(tbl, pkey, dev);
+ if (!neigh) {
+ neigh = neigh_create(tbl, pkey, dev);
+ if (IS_ERR(neigh))
+ return PTR_ERR(neigh);
+ }
}
neigh_event_send(neigh, NULL);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index d650d33e3709..27d80ec8e895 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -253,7 +253,6 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
#if IS_ENABLED(CONFIG_IPV6)
struct nfp_tun_active_tuns_v6 *payload;
struct net_device *netdev;
- struct neigh_table *tbl;
int count, i, pay_len;
struct neighbour *n;
void *ipv6_add;
@@ -280,8 +279,7 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
if (!netdev)
continue;
- tbl = nd_table(dev_net(netdev));
- n = neigh_lookup(tbl, ipv6_add, netdev);
+ n = ipv6_neigh_lookup(netdev, ipv6_add);
if (!n)
continue;
diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c
index 793a562fc1f7..ae6cc6b93864 100644
--- a/drivers/net/ethernet/sfc/tc_counters.c
+++ b/drivers/net/ethernet/sfc/tc_counters.c
@@ -116,9 +116,8 @@ static void efx_tc_counter_work(struct work_struct *work)
encap->neigh->egdev);
else
#if IS_ENABLED(CONFIG_IPV6)
- n = neigh_lookup(nd_table(net),
- &encap->neigh->dst_ip6,
- encap->neigh->egdev);
+ n = ipv6_neigh_lookup(encap->neigh->egdev,
+ &encap->neigh->dst_ip6);
#else
n = NULL;
#endif
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 320f3584a43b..79d433f49f80 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -614,9 +614,9 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
rcu_read_lock();
nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr);
- neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
+ neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
if (unlikely(!neigh))
- neigh = __neigh_create(nd_table(net), nexthop, dst->dev, false);
+ neigh = ipv6_neigh_create_noref(dev, nexthop);
if (!IS_ERR(neigh)) {
sock_confirm_neigh(skb, neigh);
ret = neigh_output(neigh, skb, false);
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 27b0b6567d52..513779c07621 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2091,8 +2091,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb,
ipv6_addr_is_multicast(&msg->target))
goto out;
- n = neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev);
-
+ n = ipv6_neigh_lookup(dev, &msg->target);
if (n) {
struct vxlan_rdst *rdst = NULL;
u8 ha[ETH_ALEN] __aligned(2);
@@ -2189,9 +2188,8 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb,
if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
return false;
- tbl = nd_table(dev_net(dev));
pip6 = ipv6_hdr(skb);
- n = neigh_lookup(tbl, &pip6->daddr, dev);
+ n = ipv6_neigh_lookup(dev, &pip6->daddr);
if (!n && (cfg->flags & VXLAN_F_L3MISS)) {
union vxlan_addr ipa = {
.sin6.sin6_addr = pip6->daddr,
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 2fce6fccf55a..91898a2475e7 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -423,11 +423,8 @@ static inline struct neighbour *ip_neigh_gw6(struct net_device *dev,
struct neighbour *neigh;
neigh = __ipv6_neigh_lookup_noref(dev, addr);
- if (unlikely(!neigh)) {
- struct neigh_table *tbl = nd_table(dev_net(dev));
-
- neigh = __neigh_create(tbl, addr, dev, false);
- }
+ if (unlikely(!neigh))
+ neigh = ipv6_neigh_create_noref(dev, addr);
return neigh;
#else
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index ba4a63840b21..c23b99517cd5 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -487,7 +487,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
return;
}
- n = neigh_lookup(nd_table(dev_net(vlandev)), &msg->target, vlandev);
+ n = ipv6_neigh_lookup(vlandev, &msg->target);
if (n) {
struct net_bridge_fdb_entry *f;
u8 ha[ETH_ALEN] __aligned(2);
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index 4f511476b992..b261daedc290 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -58,9 +58,8 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
info->daddr.mode = IEEE802154_ADDR_SHORT;
} else {
__le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
- struct neigh_table *tbl = nd_table(dev_net(ldev));
- n = neigh_lookup(tbl, &hdr->daddr, ldev);
+ n = ipv6_neigh_lookup(ldev, &hdr->daddr);
if (n) {
llneigh = lowpan_802154_neigh(neighbour_priv(n));
read_lock_bh(&n->lock);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e3bcc25229b0..a98c7670d2ce 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -617,7 +617,7 @@ static int fib_detect_death(struct fib_info *fi, int order,
if (likely(nhc->nhc_gw_family == AF_INET))
n = neigh_lookup(arp_table(net), &nhc->nhc_gw.ipv4, nhc->nhc_dev);
else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6)
- n = neigh_lookup(nd_table(net), &nhc->nhc_gw.ipv6, nhc->nhc_dev);
+ n = ipv6_neigh_lookup(nhc->nhc_dev, &nhc->nhc_gw.ipv6);
else
n = NULL;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 10146a57b69e..25fe0ba98b1a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -127,7 +127,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
if (IS_ERR_OR_NULL(neigh)) {
if (unlikely(!neigh))
- neigh = __neigh_create(nd_table(net), nexthop, dev, false);
+ neigh = ipv6_neigh_create_noref(dev, nexthop);
if (IS_ERR(neigh)) {
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index e1cbffaa0ad0..0ed1a619372b 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -947,8 +947,12 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
* update / create cache entry
* for the source address
*/
- neigh = __neigh_lookup(tbl, saddr, dev,
- !inc || lladdr || !dev->addr_len);
+ neigh = ipv6_neigh_lookup(dev, saddr);
+ if (!neigh && (!inc || lladdr || !dev->addr_len)) {
+ neigh = ipv6_neigh_create(dev, saddr);
+ if (IS_ERR(neigh))
+ neigh = NULL;
+ }
if (neigh)
ndisc_update(dev, neigh, lladdr, NUD_STALE,
NEIGH_UPDATE_F_WEAK_OVERRIDE|
@@ -998,7 +1002,6 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
struct net *net = dev_net(dev);
struct ndisc_options ndopts;
struct inet6_ifaddr *ifp;
- struct neigh_table *tbl;
struct neighbour *neigh;
struct inet6_dev *idev;
u8 *lladdr = NULL;
@@ -1063,8 +1066,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
return reason;
}
- tbl = nd_table(net);
- neigh = neigh_lookup(tbl, &msg->target, dev);
+ neigh = ipv6_neigh_lookup(dev, &msg->target);
/* RFC 9131 updates original Neighbour Discovery RFC 4861.
* NAs with Target LL Address option can now create a STALE neighbor
@@ -1093,7 +1095,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
return reason;
}
if (!neigh)
- neigh = neigh_create(tbl, &msg->target, dev);
+ neigh = ipv6_neigh_create(dev, &msg->target);
new_state = NUD_STALE;
}
@@ -1108,7 +1110,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
READ_ONCE(net->ipv6.devconf_all->forwarding) &&
READ_ONCE(net->ipv6.devconf_all->proxy_ndp) &&
- pneigh_lookup(tbl, &msg->target, dev)) {
+ pneigh_lookup(nd_table(dev_net(dev)), &msg->target, dev)) {
/* XXX: idev->cnf.proxy_ndp */
goto out;
}
@@ -1141,7 +1143,6 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
struct net_device *dev = skb->dev;
struct ndisc_options ndopts;
- struct neigh_table *tbl;
struct neighbour *neigh;
struct inet6_dev *idev;
u8 *lladdr = NULL;
@@ -1177,8 +1178,12 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
goto out;
}
- tbl = nd_table(dev_net(dev));
- neigh = __neigh_lookup(tbl, saddr, dev, 1);
+ neigh = ipv6_neigh_lookup(dev, saddr);
+ if (!neigh) {
+ neigh = ipv6_neigh_create(dev, saddr);
+ if (IS_ERR(neigh))
+ goto out;
+ }
if (neigh) {
ndisc_update(dev, neigh, lladdr, NUD_STALE,
NEIGH_UPDATE_F_WEAK_OVERRIDE|
@@ -1478,9 +1483,14 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
* Process options.
*/
- if (!neigh)
- neigh = __neigh_lookup(nd_table(net), &ipv6_hdr(skb)->saddr,
- skb->dev, 1);
+ if (!neigh) {
+ neigh = ipv6_neigh_lookup(skb->dev, &ipv6_hdr(skb)->saddr);
+ if (!neigh) {
+ neigh = ipv6_neigh_create(skb->dev, &ipv6_hdr(skb)->saddr);
+ if (IS_ERR(neigh))
+ neigh = NULL;
+ }
+ }
if (neigh) {
u8 *lladdr = NULL;
if (ndopts.nd_opts_src_lladdr) {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8baac4d85251..ea9f0a4c34f9 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -218,7 +218,7 @@ struct neighbour *__ip6_dst_neigh_lookup(const struct in6_addr *gw,
if (n)
return n;
- n = neigh_create(nd_table(dev_net(dev)), daddr, dev);
+ n = ipv6_neigh_create(dev, daddr);
return IS_ERR(n) ? NULL : n;
}
@@ -4277,9 +4277,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
*/
dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
- neigh = __neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev, 1);
- if (!neigh)
- return;
+ neigh = ipv6_neigh_lookup(dev, &msg->target);
+ if (!neigh) {
+ neigh = ipv6_neigh_create(dev, &msg->target);
+ if (IS_ERR(neigh))
+ return;
+ }
/*
* We have finally decided to accept it.
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 409ce50cc0db..19ccf1a55988 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -16,6 +16,7 @@
#include <linux/skbuff.h>
#include <linux/moduleparam.h>
#include <net/dst.h>
+#include <net/ndisc.h>
#include <net/neighbour.h>
#include <net/pkt_sched.h>
@@ -257,7 +258,16 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
if (dst->dev != dev) {
struct neighbour *mn;
- mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (n->tbl->family == AF_INET6) {
+ mn = ipv6_neigh_lookup(dev, n->primary_key);
+ if (!mn)
+ mn = ipv6_neigh_create(dev, n->primary_key);
+ } else
+#endif
+ {
+ mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
+ }
neigh_release(n);
if (IS_ERR(mn))
return PTR_ERR(mn);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 7/9] ipv4: Use ipv4_neigh_lookup() and friends.
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (5 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 8/9] neighbour: Remove __neigh_lookup() and __neigh_lookup_errno() Kuniyuki Iwashima
` (4 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev,
Elad Nachman, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Boris Pismenny, Petr Machata, Jiri Pirko, Edward Cree,
Nikolay Aleksandrov
It is error-prone to require callers to fetch netns and
neigh_table and pass it with dev to neigh_lookup(), etc.
Let's replace neigh_lookup() and friends with IPv4 helpers.
Note that __neigh_lookup(create=false) is replaced with
ipv4_neigh_lookup() and __neigh_lookup(create=true) and
__neigh_lookup_errno() are split into ipv4_neigh_lookup()
and ipv4_neigh_create().
Fixes: 2430df635a59 ("ipv4: Replace &arp_tbl with arp_table(net).")
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
v2: Convert __teql_resolve()
Cc: Elad Nachman <enachman@marvell.com>
Cc: Saeed Mahameed <saeedm@nvidia.com>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Tariq Toukan <tariqt@nvidia.com>
Cc: Mark Bloch <mbloch@nvidia.com>
Cc: Boris Pismenny <borisp@nvidia.com>
Cc: Petr Machata <petrm@nvidia.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Cc: Edward Cree <ecree.xilinx@gmail.com>
Cc: Nikolay Aleksandrov <razor@blackwall.org>
---
.../marvell/prestera/prestera_router.c | 14 ++++------
.../mellanox/mlx5/core/en/tc_tun_encap.c | 3 +--
.../mellanox/mlx5/core/en_accel/ipsec.c | 6 ++---
.../ethernet/mellanox/mlxsw/spectrum_router.c | 13 +++-------
.../ethernet/mellanox/mlxsw/spectrum_span.c | 7 ++---
.../netronome/nfp/flower/tunnel_conf.c | 4 +--
drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +-
drivers/net/ethernet/sfc/tc_counters.c | 6 ++---
drivers/net/vxlan/vxlan_core.c | 8 ++----
net/bridge/br_arp_nd_proxy.c | 2 +-
net/ipv4/arp.c | 26 ++++++++++++-------
net/ipv4/fib_semantics.c | 3 +--
net/ipv4/route.c | 2 +-
net/sched/sch_teql.c | 5 +++-
14 files changed, 42 insertions(+), 59 deletions(-)
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_router.c b/drivers/net/ethernet/marvell/prestera/prestera_router.c
index ba45b61b09bb..44c9c1fa3189 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_router.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_router.c
@@ -683,8 +683,7 @@ __prestera_k_arb_n_offload_set(struct prestera_switch *sw,
{
struct neighbour *n;
- n = neigh_lookup(arp_table(&init_net), &nc->key.addr.u.ipv4,
- nc->key.dev);
+ n = ipv4_neigh_lookup(nc->key.dev, &nc->key.addr.u.ipv4);
if (!n)
return;
@@ -790,7 +789,7 @@ __prestera_k_arb_nc_kern_n_fetch(struct prestera_switch *sw,
int err;
memset(&nc->nh_neigh_info, 0, sizeof(nc->nh_neigh_info));
- n = neigh_lookup(arp_table(&init_net), &nc->key.addr.u.ipv4, nc->key.dev);
+ n = ipv4_neigh_lookup(nc->key.dev, &nc->key.addr.u.ipv4);
if (!n)
goto out;
@@ -1052,13 +1051,10 @@ static void __prestera_k_arb_hw_state_upd(struct prestera_switch *sw,
#endif /* PRESTERA_IMPLICITY_RESOLVE_DEAD_NEIGH */
if (nc->key.addr.v == PRESTERA_IPV4) {
- struct neigh_table *tbl = arp_table(&init_net);
-
- n = neigh_lookup(tbl, &nc->key.addr.u.ipv4,
- nc->key.dev);
+ n = ipv4_neigh_lookup(nc->key.dev, &nc->key.addr.u.ipv4);
if (!n)
- n = neigh_create(tbl, &nc->key.addr.u.ipv4,
- nc->key.dev);
+ n = ipv4_neigh_create(nc->key.dev,
+ &nc->key.addr.u.ipv4);
} else {
n = NULL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
index fe0258375ef6..5e40107efa26 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
@@ -438,7 +438,6 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
if (neigh_used) {
struct net_device *dev = READ_ONCE(nhe->neigh_dev);
- struct net *net = dev_net(dev);
nhe->reported_lastuse = jiffies;
@@ -450,7 +449,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
n = ipv6_neigh_lookup(dev, &m_neigh->dst_ip);
else
#endif
- n = neigh_lookup(arp_table(net), &m_neigh->dst_ip, dev);
+ n = ipv4_neigh_lookup(dev, &m_neigh->dst_ip);
if (!n)
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 37a8ddee3ea1..16edd3263aed 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -262,7 +262,6 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
struct net_device *netdev = sa_entry->dev;
struct xfrm_state *x = sa_entry->x;
struct dst_entry *rt_dst_entry;
- struct neigh_table *tbl;
struct flowi4 fl4 = {};
struct flowi6 fl6 = {};
struct neighbour *n;
@@ -365,10 +364,9 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
return;
neigh:
- tbl = arp_table(dev_net(netdev));
- n = neigh_lookup(tbl, pkey, netdev);
+ n = ipv4_neigh_lookup(netdev, pkey);
if (!n) {
- n = neigh_create(tbl, pkey, netdev);
+ n = ipv4_neigh_create(netdev, pkey);
if (IS_ERR(n))
return;
neigh_event_send(n, NULL);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 1f4753213b9c..07d22257b703 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -2415,8 +2415,6 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
int ent_index)
{
u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
- struct net *net = mlxsw_sp_net(mlxsw_sp);
- struct neigh_table *tbl;
struct net_device *dev;
struct neighbour *n;
__be32 dipn;
@@ -2432,10 +2430,9 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
return;
}
- tbl = arp_table(net);
dipn = htonl(dip);
dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
- n = neigh_lookup(tbl, &dipn, dev);
+ n = ipv4_neigh_lookup(dev, &dipn);
if (!n)
return;
@@ -4300,13 +4297,10 @@ static void __mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp_nexthop *nh,
static struct neighbour *
mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
{
- struct neigh_table *tbl;
struct net_device *dev;
struct neighbour *n;
- struct net *net;
dev = mlxsw_sp_nexthop_dev(nh);
- net = dev_net(dev);
#if IS_ENABLED(CONFIG_IPV6)
if (nh->family == AF_INET6) {
@@ -4319,10 +4313,9 @@ mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
} else
#endif
{
- tbl = arp_table(net);
- n = neigh_lookup(tbl, &nh->gw_addr, dev);
+ n = ipv4_neigh_lookup(dev, &nh->gw_addr);
if (!n) {
- n = neigh_create(tbl, &nh->gw_addr, dev);
+ n = ipv4_neigh_create(dev, &nh->gw_addr);
if (!IS_ERR(n))
neigh_event_send(n, NULL);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index 79947f68b10d..0b84a25e2ea8 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -229,8 +229,6 @@ static int mlxsw_sp_span_dmac(int family,
struct net_device *dev,
unsigned char dmac[ETH_ALEN])
{
- struct net *net = dev_net(dev);
- struct neigh_table *tbl;
struct neighbour *neigh;
int err = 0;
@@ -245,10 +243,9 @@ static int mlxsw_sp_span_dmac(int family,
} else
#endif
{
- tbl = arp_table(net);
- neigh = neigh_lookup(tbl, pkey, dev);
+ neigh = ipv4_neigh_lookup(dev, pkey);
if (!neigh) {
- neigh = neigh_create(tbl, pkey, dev);
+ neigh = ipv4_neigh_create(dev, pkey);
if (IS_ERR(neigh))
return PTR_ERR(neigh);
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index 27d80ec8e895..3b47e9fe64e1 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -209,7 +209,6 @@ void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
{
struct nfp_tun_active_tuns *payload;
struct net_device *netdev;
- struct neigh_table *tbl;
int count, i, pay_len;
struct neighbour *n;
__be32 ipv4_addr;
@@ -236,8 +235,7 @@ void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
if (!netdev)
continue;
- tbl = arp_table(dev_net(netdev));
- n = neigh_lookup(tbl, &ipv4_addr, netdev);
+ n = ipv4_neigh_lookup(netdev, &ipv4_addr);
if (!n)
continue;
diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c
index ead8b447b89c..ace69a1d5275 100644
--- a/drivers/net/ethernet/rocker/rocker_ofdpa.c
+++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c
@@ -1336,7 +1336,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port,
int err = 0;
if (!n) {
- n = neigh_create(arp_table(&init_net), &ip_addr, dev);
+ n = ipv4_neigh_create(dev, &ip_addr);
if (IS_ERR(n))
return PTR_ERR(n);
}
diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c
index ae6cc6b93864..fcb2be6abb20 100644
--- a/drivers/net/ethernet/sfc/tc_counters.c
+++ b/drivers/net/ethernet/sfc/tc_counters.c
@@ -91,7 +91,6 @@ static void efx_tc_counter_work(struct work_struct *work)
struct efx_tc_action_set *act;
unsigned long touched;
struct neighbour *n;
- struct net *net;
spin_lock_bh(&cnt->lock);
touched = READ_ONCE(cnt->touched);
@@ -106,14 +105,13 @@ static void efx_tc_counter_work(struct work_struct *work)
continue;
encap->neigh->used = touched;
- net = encap->neigh->net;
/* We have passed traffic using this ARP entry, so
* indicate to the ARP cache that it's still active
*/
if (encap->neigh->dst_ip)
- n = neigh_lookup(arp_table(net), &encap->neigh->dst_ip,
- encap->neigh->egdev);
+ n = ipv4_neigh_lookup(encap->neigh->egdev,
+ &encap->neigh->dst_ip);
else
#if IS_ENABLED(CONFIG_IPV6)
n = ipv6_neigh_lookup(encap->neigh->egdev,
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 513779c07621..35bd92f5e460 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1877,7 +1877,6 @@ static int vxlan_err_lookup(struct sock *sk, struct sk_buff *skb)
static int arp_reduce(struct net_device *dev, struct sk_buff *skb,
const struct vxlan_config *cfg, __be32 vni)
{
- struct neigh_table *tbl = arp_table(dev_net(dev));
struct vxlan_dev *vxlan = netdev_priv(dev);
struct neighbour *n;
struct arphdr *parp;
@@ -1914,8 +1913,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb,
ipv4_is_multicast(tip))
goto out;
- n = neigh_lookup(tbl, &tip, dev);
-
+ n = ipv4_neigh_lookup(dev, &tip);
if (n) {
struct vxlan_rdst *rdst = NULL;
u8 ha[ETH_ALEN] __aligned(2);
@@ -2145,7 +2143,6 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb,
static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb,
const struct vxlan_config *cfg)
{
- struct neigh_table *tbl;
struct neighbour *n;
if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
@@ -2160,9 +2157,8 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb,
if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
return false;
- tbl = arp_table(dev_net(dev));
pip = ip_hdr(skb);
- n = neigh_lookup(tbl, &pip->daddr, dev);
+ n = ipv4_neigh_lookup(dev, &pip->daddr);
if (!n && (cfg->flags & VXLAN_F_L3MISS)) {
union vxlan_addr ipa = {
.sin.sin_addr.s_addr = pip->daddr,
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index c23b99517cd5..2123344a5677 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -210,7 +210,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
return;
}
- n = neigh_lookup(arp_table(dev_net(vlandev)), &tip, vlandev);
+ n = ipv4_neigh_lookup(vlandev, &tip);
if (n) {
struct net_bridge_fdb_entry *f;
u8 ha[ETH_ALEN] __aligned(2);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 95f3359d0f92..1ca4ced280ae 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -892,7 +892,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
/* Update our ARP tables */
- n = __neigh_lookup(tbl, &sip, dev, 0);
+ n = ipv4_neigh_lookup(dev, &sip);
addr_type = -1;
if (n || arp_accept(in_dev, sip)) {
@@ -911,9 +911,14 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
(addr_type == RTN_UNICAST ||
(addr_type < 0 &&
/* postpone calculation to as late as possible */
- inet_addr_type_dev_table(net, dev, sip) ==
- RTN_UNICAST)))))
- n = __neigh_lookup(tbl, &sip, dev, 1);
+ inet_addr_type_dev_table(net, dev, sip) == RTN_UNICAST))))) {
+ n = ipv4_neigh_lookup(dev, &sip);
+ if (!n) {
+ n = ipv4_neigh_create(dev, &sip);
+ if (IS_ERR(n))
+ n = NULL;
+ }
+ }
}
if (n) {
@@ -1102,7 +1107,6 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
static int arp_req_set(struct net *net, struct arpreq *r)
{
- struct neigh_table *tbl = arp_table(net);
struct neighbour *neigh;
struct net_device *dev;
__be32 ip;
@@ -1138,7 +1142,9 @@ static int arp_req_set(struct net *net, struct arpreq *r)
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
- neigh = __neigh_lookup_errno(tbl, &ip, dev);
+ neigh = ipv4_neigh_lookup(dev, &ip);
+ if (!neigh)
+ neigh = ipv4_neigh_create(dev, &ip);
err = PTR_ERR(neigh);
if (!IS_ERR(neigh)) {
unsigned int state = NUD_STALE;
@@ -1174,7 +1180,6 @@ static unsigned int arp_state_to_flags(struct neighbour *neigh)
static int arp_req_get(struct net *net, struct arpreq *r)
{
__be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
- struct neigh_table *tbl = arp_table(net);
struct neighbour *neigh;
struct net_device *dev;
@@ -1185,7 +1190,7 @@ static int arp_req_get(struct net *net, struct arpreq *r)
if (IS_ERR(dev))
return PTR_ERR(dev);
- neigh = neigh_lookup(tbl, &ip, dev);
+ neigh = ipv4_neigh_lookup(dev, &ip);
if (!neigh)
return -ENXIO;
@@ -1210,12 +1215,13 @@ static int arp_req_get(struct net *net, struct arpreq *r)
int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
{
- struct neigh_table *tbl = arp_table(dev_net(dev));
struct neighbour *neigh;
int err = -ENXIO;
- neigh = neigh_lookup(tbl, &ip, dev);
+ neigh = ipv4_neigh_lookup(dev, &ip);
if (neigh) {
+ struct neigh_table *tbl = neigh->tbl;
+
if ((READ_ONCE(neigh->nud_state) & NUD_VALID) && !force) {
neigh_release(neigh);
return 0;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index a98c7670d2ce..235c51a6f8e5 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -610,12 +610,11 @@ static int fib_detect_death(struct fib_info *fi, int order,
int dflt)
{
const struct fib_nh_common *nhc = fib_info_nhc(fi, 0);
- struct net *net = fi->fib_net;
int state = NUD_NONE;
struct neighbour *n;
if (likely(nhc->nhc_gw_family == AF_INET))
- n = neigh_lookup(arp_table(net), &nhc->nhc_gw.ipv4, nhc->nhc_dev);
+ n = ipv4_neigh_lookup(nhc->nhc_dev, &nhc->nhc_gw.ipv4);
else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6)
n = ipv6_neigh_lookup(nhc->nhc_dev, &nhc->nhc_gw.ipv6);
else
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 50c842617e45..18b588dfbea7 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -817,7 +817,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
n = __ipv4_neigh_lookup(rt->dst.dev, (__force u32)new_gw);
if (!n)
- n = neigh_create(arp_table(net), &new_gw, rt->dst.dev);
+ n = ipv4_neigh_create(rt->dst.dev, &new_gw);
if (!IS_ERR(n)) {
if (!(READ_ONCE(n->nud_state) & NUD_VALID)) {
neigh_event_send(n, NULL);
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 19ccf1a55988..e9cb7d408ca0 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/moduleparam.h>
+#include <net/arp.h>
#include <net/dst.h>
#include <net/ndisc.h>
#include <net/neighbour.h>
@@ -266,7 +267,9 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
} else
#endif
{
- mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
+ mn = ipv4_neigh_lookup(dev, n->primary_key);
+ if (!mn)
+ mn = ipv4_neigh_create(dev, n->primary_key);
}
neigh_release(n);
if (IS_ERR(mn))
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 8/9] neighbour: Remove __neigh_lookup() and __neigh_lookup_errno().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (6 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 7/9] ipv4: Use ipv4_neigh_lookup() " Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 9/9] neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create() Kuniyuki Iwashima
` (3 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
Both __neigh_lookup() and __neigh_lookup_errno() not only
look up but also create a new neighbour entry.
The names were misleading and there was __neigh_lookup(..., 0),
which should have been simply written as neigh_lookup().
Now, __neigh_lookup() has only 1 user left.
Let's convert the last user to neigh_lookup() and neigh_create()
and remove __neigh_lookup() and __neigh_lookup_errno().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/net/neighbour.h | 24 ------------------------
net/core/neighbour.c | 9 +++++++--
2 files changed, 7 insertions(+), 26 deletions(-)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index ed9d9ae6d3a6..79a5a548a129 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -554,30 +554,6 @@ static inline int neigh_output(struct neighbour *n, struct sk_buff *skb,
return READ_ONCE(n->output)(n, skb);
}
-static inline struct neighbour *
-__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
-{
- struct neighbour *n = neigh_lookup(tbl, pkey, dev);
-
- if (n || !creat)
- return n;
-
- n = neigh_create(tbl, pkey, dev);
- return IS_ERR(n) ? NULL : n;
-}
-
-static inline struct neighbour *
-__neigh_lookup_errno(struct neigh_table *tbl, const void *pkey,
- struct net_device *dev)
-{
- struct neighbour *n = neigh_lookup(tbl, pkey, dev);
-
- if (n)
- return n;
-
- return neigh_create(tbl, pkey, dev);
-}
-
struct neighbour_cb {
unsigned long sched_next;
unsigned int flags;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 6ed8eb075146..0d883c043956 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1569,8 +1569,13 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
u8 *lladdr, void *saddr,
struct net_device *dev)
{
- struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
- lladdr || !dev->addr_len);
+ struct neighbour *neigh = neigh_lookup(tbl, saddr, dev);
+
+ if (!neigh && (lladdr || !dev->addr_len)) {
+ neigh = neigh_create(tbl, saddr, dev);
+ if (IS_ERR(neigh))
+ neigh = NULL;
+ }
if (neigh)
neigh_update(neigh, lladdr, NUD_STALE,
NEIGH_UPDATE_F_OVERRIDE, 0);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 net-next 9/9] neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create().
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (7 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 8/9] neighbour: Remove __neigh_lookup() and __neigh_lookup_errno() Kuniyuki Iwashima
@ 2026-10-03 21:23 ` Kuniyuki Iwashima
2026-10-06 20:39 ` [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Fernando Fernandez Mancera
` (2 subsequent siblings)
11 siblings, 0 replies; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-03 21:23 UTC (permalink / raw)
To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev,
netdev-bot+sashiko
Sashiko reported that if ___neigh_create() is called outside of
RCU, it could create a new entry for dev in a different netns
while __dev_change_net_namespace() is running concurrently:
creator
ipv6_neigh_create(dev, ...)
tbl = nd_table(dev_net(dev)) <- old netns
<preempted>
__dev_change_net_namespace()
NETDEV_UNREGISTER
rcu_barrier()
dev_net_set(dev, new_net)
NETDEV_REGISTER <- new in6_dev
creator resumes
neigh_create(old_tbl, ...)
ndisc_constructor()
in6_dev_get(dev) <- new in6_dev, live parms
Let's check n->parms->tbl under tbl->lock.
Fixes: cda2962b6e2b ("neighbour: Namespacify neigh_tables.")
Reported-by: netdev-bot+sashiko@kernel.org
Closes: https://lore.kernel.org/netdev/179090663305.434549.17214258093385242325@kernel.org/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/core/neighbour.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0d883c043956..90335895b415 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -690,7 +690,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey,
hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
- if (n->parms->dead) {
+ if (n->parms->dead || n->parms->tbl != tbl) {
rc = ERR_PTR(-EINVAL);
goto out_tbl_unlock;
}
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends.
2026-10-03 21:23 ` [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends Kuniyuki Iwashima
@ 2026-10-06 17:53 ` Fernando Fernandez Mancera
2026-10-06 18:01 ` Kuniyuki Iwashima
0 siblings, 1 reply; 18+ messages in thread
From: Fernando Fernandez Mancera @ 2026-10-06 17:53 UTC (permalink / raw)
To: Kuniyuki Iwashima, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, netdev,
syzbot+5a8857f0b4a0a7b12c62, Saeed Mahameed, Leon Romanovsky,
Tariq Toukan, Mark Bloch, Petr Machata, Edward Cree,
Nikolay Aleksandrov, Alexander Aring, Stefan Schmidt,
Miquel Raynal
On 10/3/26 11:23 PM, Kuniyuki Iwashima wrote:
> syzbot reported the splat below in neigh_mark_dead() [0]
> where tbl->lock was not held while neigh_ifdown() should
> have acquired one.
>
> This only happens when a neigh_table accidentally has a
> neighbour from a different netns.
>
> In ip6_finish_output2(), the net argument is the caller's and
> does not always match dev_net(dev) fetched from dst. (e.g. xfrm)
>
> It is error-prone to require callers to fetch netns and
> neigh_table and pass it with dev to neigh_lookup(), etc.
>
> Let's replace neigh_lookup() and friends with IPv6 helpers.
>
> Note that __neigh_lookup() is split into ipv6_neigh_lookup()
> and ipv6_neigh_create().
>
> [0]:
> debug_locks && !(lock_is_held(&(&n->tbl->lock)->dep_map) != 0)
> WARNING: net/core/neighbour.c:154 at neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154, CPU#0: syz.0.857/9765
> Modules linked in:
> CPU: 0 UID: 0 PID: 9765 Comm: syz.0.857 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
> RIP: 0010:neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154
> Code: e8 03 42 80 3c 28 00 74 08 48 89 df e8 ee 9a 80 f8 4c 89 33 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc e8 86 95 10 f8 90 <0f> 0b 90 e9 8f fd ff ff 48 c7 c1 80 9a 7a 90 80 e1 07 80 c1 03 38
> RSP: 0018:ffffc90003726600 EFLAGS: 00010287
> RAX: ffffffff89b7467a RBX: ffff888022e86000 RCX: 0000000000080000
> RDX: ffffc900047fa000 RSI: 0000000000003e08 RDI: 0000000000003e09
> RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000004
> R10: dffffc0000000000 R11: fffff520006e4cb8 R12: ffff888022e8613c
> R13: dffffc0000000000 R14: ffff888022e86020 R15: ffff888022e86000
> FS: 00007f9c30f046c0(0000) GS:ffff888124cc6000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000000000000000 CR3: 0000000076c56000 CR4: 00000000003526f0
> Call Trace:
> <TASK>
> neigh_flush_one+0x27c/0x5a0 net/core/neighbour.c:388
> neigh_flush_dev net/core/neighbour.c:432 [inline]
> __neigh_ifdown+0x1fb/0xc70 net/core/neighbour.c:465
> neigh_ifdown+0x1f/0x30 net/core/neighbour.c:487
> rt6_disable_ip+0x751/0x7e0 net/ipv6/route.c:5058
> addrconf_ifdown+0x155/0x1ad0 net/ipv6/addrconf.c:3892
> addrconf_notify+0x1bc/0x1050 net/ipv6/addrconf.c:-1
> notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85
> call_netdevice_notifiers_mtu net/core/dev.c:2350 [inline]
> netif_set_mtu_ext+0x5ac/0x830 net/core/dev.c:9963
> do_setlink+0xa81/0x47a0 net/core/rtnetlink.c:3247
> rtnl_setlink+0x578/0x820 net/core/rtnetlink.c:3623
> rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7159
> netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572
> netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline]
> netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361
> netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916
> sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800
> __sock_sendmsg net/socket.c:815 [inline]
> sock_write_iter+0x2de/0x3e0 net/socket.c:1266
> do_iter_readv_writev+0x612/0x8c0 fs/read_write.c:-1
> vfs_writev+0x343/0x990 fs/read_write.c:1058
> do_writev+0x154/0x2e0 fs/read_write.c:1104
> do_syscall_x64 arch/x86/emlxsw_sp_ul_rif_getntry/syscall_64.c:61 [inline]
> do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7f9c2ff9e159
> Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
> RSP: 002b:00007f9c30f04028 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
> RAX: ffffffffffffffda RBX: 00007f9c30225fa0 RCX: 00007f9c2ff9e159
> RDX: 0000000000000001 RSI: 00002000000003c0 RDI: 0000000000000004
> RBP: 00007f9c3003506b R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> R13: 00007f9c30226038 R14: 00007f9c30225fa0 R15: 00007ffed3c74808
> </TASK>
>
> Fixes: df5f4f372de5 ("ipv6: Replace &nd_tbl with nd_table(net).")
> Reported-by: syzbot+5a8857f0b4a0a7b12c62@syzkaller.appspotmail.com
> Closes: https://lore.kernel.org/netdev/6abd69a9.80e1c6cc.22483f.0005.GAE@google.com/
> Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
> ---
> v2: Convert __teql_resolve()
>
> Cc: Saeed Mahameed <saeedm@nvidia.com>
> Cc: Leon Romanovsky <leon@kernel.org>
> Cc: Tariq Toukan <tariqt@nvidia.com>
> Cc: Mark Bloch <mbloch@nvidia.com>
> Cc: Petr Machata <petrm@nvidia.com>
> Cc: Edward Cree <ecree.xilinx@gmail.com>
> Cc: Nikolay Aleksandrov <razor@blackwall.org>
> Cc: Alexander Aring <alex.aring@gmail.com>
> Cc: Stefan Schmidt <stefan@datenfreihafen.org>
> Cc: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> .../mellanox/mlx5/core/en/tc_tun_encap.c | 13 +++----
> .../ethernet/mellanox/mlxsw/spectrum_router.c | 29 ++++++++-------
> .../ethernet/mellanox/mlxsw/spectrum_span.c | 24 ++++++++-----
> .../netronome/nfp/flower/tunnel_conf.c | 4 +--
> drivers/net/ethernet/sfc/tc_counters.c | 5 ++-
> drivers/net/vrf.c | 4 +--
> drivers/net/vxlan/vxlan_core.c | 6 ++--
> include/net/ndisc.h | 7 ++--
> net/bridge/br_arp_nd_proxy.c | 2 +-
> net/ieee802154/6lowpan/tx.c | 3 +-
> net/ipv4/fib_semantics.c | 2 +-
> net/ipv6/ip6_output.c | 2 +-
> net/ipv6/ndisc.c | 36 ++++++++++++-------
> net/ipv6/route.c | 11 +++---
> net/sched/sch_teql.c | 12 ++++++-
> 15 files changed, 90 insertions(+), 70 deletions(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
> index 67c12ca19d59..fe0258375ef6 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
> @@ -439,21 +439,18 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
> if (neigh_used) {
> struct net_device *dev = READ_ONCE(nhe->neigh_dev);
> struct net *net = dev_net(dev);
> - struct neigh_table *tbl;
>
> nhe->reported_lastuse = jiffies;
>
> + /* find the relevant neigh according to the cached device and
> + * dst ip pair
> + */
> #if IS_ENABLED(CONFIG_IPV6)
> if (m_neigh->family != AF_INET)
> - tbl = nd_table(net);
> + n = ipv6_neigh_lookup(dev, &m_neigh->dst_ip);
> else
> #endif
> - tbl = arp_table(net);
> -
> - /* find the relevant neigh according to the cached device and
> - * dst ip pair
> - */
> - n = neigh_lookup(tbl, &m_neigh->dst_ip, dev);
> + n = neigh_lookup(arp_table(net), &m_neigh->dst_ip, dev);
> if (!n)
> return;
>
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
> index ba8a7a44ce9e..1f4753213b9c 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
> @@ -2449,8 +2449,6 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
> char *rauhtd_pl,
> int rec_index)
> {
> - struct net *net = mlxsw_sp_net(mlxsw_sp);
> - struct neigh_table *tbl;
> struct net_device *dev;
> struct neighbour *n;
> struct in6_addr dip;
> @@ -2464,9 +2462,8 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
> return;
> }
>
> - tbl = nd_table(net);
> dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
> - n = neigh_lookup(tbl, &dip, dev);
> + n = ipv6_neigh_lookup(dev, &dip);
Hi Kuniyuki,
I have checked Sashiko's feedback [0] and I think it is right.
mlxsw_sp_router_ul_rif_get() can be called with a NULL mlxsw_sp_crif
pointer which then would call mlxsw_sp_ul_rif_create() and there during
the alloc a rif with a NULL crif is created making this feedback being
correct.
I think a simple NULL check here for dev should be enough.
[0]
https://sashiko.dev/#/message/20261003212336.1304988-7-kuniyu%40google.com
Thanks!
> if (!n)
> return;
>
> @@ -4312,17 +4309,23 @@ mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
> net = dev_net(dev);
>
> #if IS_ENABLED(CONFIG_IPV6)
> - if (nh->family == AF_INET6)
> - tbl = nd_table(net);
> - else
> + if (nh->family == AF_INET6) {
> + n = ipv6_neigh_lookup(dev, &nh->gw_addr);
> + if (!n) {
> + n = ipv6_neigh_create(dev, &nh->gw_addr);
> + if (!IS_ERR(n))
> + neigh_event_send(n, NULL);
> + }
> + } else
> #endif
> + {
> tbl = arp_table(net);
> -
> - n = neigh_lookup(tbl, &nh->gw_addr, dev);
> - if (!n) {
> - n = neigh_create(tbl, &nh->gw_addr, dev);
> - if (!IS_ERR(n))
> - neigh_event_send(n, NULL);
> + n = neigh_lookup(tbl, &nh->gw_addr, dev);
> + if (!n) {
> + n = neigh_create(tbl, &nh->gw_addr, dev);
> + if (!IS_ERR(n))
> + neigh_event_send(n, NULL);
> + }
> }
>
> return n;
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
> index d34d2040177b..79947f68b10d 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
> @@ -235,17 +235,23 @@ static int mlxsw_sp_span_dmac(int family,
> int err = 0;
>
> #if IS_ENABLED(CONFIG_IPV6_GRE)
> - if (family == AF_INET6)
> - tbl = nd_table(net);
> - else
> + if (family == AF_INET6) {
> + neigh = ipv6_neigh_lookup(dev, pkey);
> + if (!neigh) {
> + neigh = ipv6_neigh_create(dev, pkey);
> + if (IS_ERR(neigh))
> + return PTR_ERR(neigh);
> + }
> + } else
> #endif
> + {
> tbl = arp_table(net);
> -
> - neigh = neigh_lookup(tbl, pkey, dev);
> - if (!neigh) {
> - neigh = neigh_create(tbl, pkey, dev);
> - if (IS_ERR(neigh))
> - return PTR_ERR(neigh);
> + neigh = neigh_lookup(tbl, pkey, dev);
> + if (!neigh) {
> + neigh = neigh_create(tbl, pkey, dev);
> + if (IS_ERR(neigh))
> + return PTR_ERR(neigh);
> + }
> }
>
> neigh_event_send(neigh, NULL);
> diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
> index d650d33e3709..27d80ec8e895 100644
> --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
> +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
> @@ -253,7 +253,6 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
> #if IS_ENABLED(CONFIG_IPV6)
> struct nfp_tun_active_tuns_v6 *payload;
> struct net_device *netdev;
> - struct neigh_table *tbl;
> int count, i, pay_len;
> struct neighbour *n;
> void *ipv6_add;
> @@ -280,8 +279,7 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
> if (!netdev)
> continue;
>
> - tbl = nd_table(dev_net(netdev));
> - n = neigh_lookup(tbl, ipv6_add, netdev);
> + n = ipv6_neigh_lookup(netdev, ipv6_add);
> if (!n)
> continue;
>
> diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c
> index 793a562fc1f7..ae6cc6b93864 100644
> --- a/drivers/net/ethernet/sfc/tc_counters.c
> +++ b/drivers/net/ethernet/sfc/tc_counters.c
> @@ -116,9 +116,8 @@ static void efx_tc_counter_work(struct work_struct *work)
> encap->neigh->egdev);
> else
> #if IS_ENABLED(CONFIG_IPV6)
> - n = neigh_lookup(nd_table(net),
> - &encap->neigh->dst_ip6,
> - encap->neigh->egdev);
> + n = ipv6_neigh_lookup(encap->neigh->egdev,
> + &encap->neigh->dst_ip6);
> #else
> n = NULL;
> #endif
> diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
> index 320f3584a43b..79d433f49f80 100644
> --- a/drivers/net/vrf.c
> +++ b/drivers/net/vrf.c
> @@ -614,9 +614,9 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
>
> rcu_read_lock();
> nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr);
> - neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
> + neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
> if (unlikely(!neigh))
> - neigh = __neigh_create(nd_table(net), nexthop, dst->dev, false);
> + neigh = ipv6_neigh_create_noref(dev, nexthop);
> if (!IS_ERR(neigh)) {
> sock_confirm_neigh(skb, neigh);
> ret = neigh_output(neigh, skb, false);
> diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> index 27b0b6567d52..513779c07621 100644
> --- a/drivers/net/vxlan/vxlan_core.c
> +++ b/drivers/net/vxlan/vxlan_core.c
> @@ -2091,8 +2091,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb,
> ipv6_addr_is_multicast(&msg->target))
> goto out;
>
> - n = neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev);
> -
> + n = ipv6_neigh_lookup(dev, &msg->target);
> if (n) {
> struct vxlan_rdst *rdst = NULL;
> u8 ha[ETH_ALEN] __aligned(2);
> @@ -2189,9 +2188,8 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb,
> if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
> return false;
>
> - tbl = nd_table(dev_net(dev));
> pip6 = ipv6_hdr(skb);
> - n = neigh_lookup(tbl, &pip6->daddr, dev);
> + n = ipv6_neigh_lookup(dev, &pip6->daddr);
> if (!n && (cfg->flags & VXLAN_F_L3MISS)) {
> union vxlan_addr ipa = {
> .sin6.sin6_addr = pip6->daddr,
> diff --git a/include/net/ndisc.h b/include/net/ndisc.h
> index 2fce6fccf55a..91898a2475e7 100644
> --- a/include/net/ndisc.h
> +++ b/include/net/ndisc.h
> @@ -423,11 +423,8 @@ static inline struct neighbour *ip_neigh_gw6(struct net_device *dev,
> struct neighbour *neigh;
>
> neigh = __ipv6_neigh_lookup_noref(dev, addr);
> - if (unlikely(!neigh)) {
> - struct neigh_table *tbl = nd_table(dev_net(dev));
> -
> - neigh = __neigh_create(tbl, addr, dev, false);
> - }
> + if (unlikely(!neigh))
> + neigh = ipv6_neigh_create_noref(dev, addr);
>
> return neigh;
> #else
> diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
> index ba4a63840b21..c23b99517cd5 100644
> --- a/net/bridge/br_arp_nd_proxy.c
> +++ b/net/bridge/br_arp_nd_proxy.c
> @@ -487,7 +487,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
> return;
> }
>
> - n = neigh_lookup(nd_table(dev_net(vlandev)), &msg->target, vlandev);
> + n = ipv6_neigh_lookup(vlandev, &msg->target);
> if (n) {
> struct net_bridge_fdb_entry *f;
> u8 ha[ETH_ALEN] __aligned(2);
> diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
> index 4f511476b992..b261daedc290 100644
> --- a/net/ieee802154/6lowpan/tx.c
> +++ b/net/ieee802154/6lowpan/tx.c
> @@ -58,9 +58,8 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
> info->daddr.mode = IEEE802154_ADDR_SHORT;
> } else {
> __le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
> - struct neigh_table *tbl = nd_table(dev_net(ldev));
>
> - n = neigh_lookup(tbl, &hdr->daddr, ldev);
> + n = ipv6_neigh_lookup(ldev, &hdr->daddr);
> if (n) {
> llneigh = lowpan_802154_neigh(neighbour_priv(n));
> read_lock_bh(&n->lock);
> diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
> index e3bcc25229b0..a98c7670d2ce 100644
> --- a/net/ipv4/fib_semantics.c
> +++ b/net/ipv4/fib_semantics.c
> @@ -617,7 +617,7 @@ static int fib_detect_death(struct fib_info *fi, int order,
> if (likely(nhc->nhc_gw_family == AF_INET))
> n = neigh_lookup(arp_table(net), &nhc->nhc_gw.ipv4, nhc->nhc_dev);
> else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6)
> - n = neigh_lookup(nd_table(net), &nhc->nhc_gw.ipv6, nhc->nhc_dev);
> + n = ipv6_neigh_lookup(nhc->nhc_dev, &nhc->nhc_gw.ipv6);
> else
> n = NULL;
>
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 10146a57b69e..25fe0ba98b1a 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -127,7 +127,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
>
> if (IS_ERR_OR_NULL(neigh)) {
> if (unlikely(!neigh))
> - neigh = __neigh_create(nd_table(net), nexthop, dev, false);
> + neigh = ipv6_neigh_create_noref(dev, nexthop);
> if (IS_ERR(neigh)) {
> IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
> kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> index e1cbffaa0ad0..0ed1a619372b 100644
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -947,8 +947,12 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
> * update / create cache entry
> * for the source address
> */
> - neigh = __neigh_lookup(tbl, saddr, dev,
> - !inc || lladdr || !dev->addr_len);
> + neigh = ipv6_neigh_lookup(dev, saddr);
> + if (!neigh && (!inc || lladdr || !dev->addr_len)) {
> + neigh = ipv6_neigh_create(dev, saddr);
> + if (IS_ERR(neigh))
> + neigh = NULL;
> + }
> if (neigh)
> ndisc_update(dev, neigh, lladdr, NUD_STALE,
> NEIGH_UPDATE_F_WEAK_OVERRIDE|
> @@ -998,7 +1002,6 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> struct net *net = dev_net(dev);
> struct ndisc_options ndopts;
> struct inet6_ifaddr *ifp;
> - struct neigh_table *tbl;
> struct neighbour *neigh;
> struct inet6_dev *idev;
> u8 *lladdr = NULL;
> @@ -1063,8 +1066,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> return reason;
> }
>
> - tbl = nd_table(net);
> - neigh = neigh_lookup(tbl, &msg->target, dev);
> + neigh = ipv6_neigh_lookup(dev, &msg->target);
>
> /* RFC 9131 updates original Neighbour Discovery RFC 4861.
> * NAs with Target LL Address option can now create a STALE neighbor
> @@ -1093,7 +1095,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> return reason;
> }
> if (!neigh)
> - neigh = neigh_create(tbl, &msg->target, dev);
> + neigh = ipv6_neigh_create(dev, &msg->target);
> new_state = NUD_STALE;
> }
>
> @@ -1108,7 +1110,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
> READ_ONCE(net->ipv6.devconf_all->forwarding) &&
> READ_ONCE(net->ipv6.devconf_all->proxy_ndp) &&
> - pneigh_lookup(tbl, &msg->target, dev)) {
> + pneigh_lookup(nd_table(dev_net(dev)), &msg->target, dev)) {
> /* XXX: idev->cnf.proxy_ndp */
> goto out;
> }
> @@ -1141,7 +1143,6 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
> unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
> struct net_device *dev = skb->dev;
> struct ndisc_options ndopts;
> - struct neigh_table *tbl;
> struct neighbour *neigh;
> struct inet6_dev *idev;
> u8 *lladdr = NULL;
> @@ -1177,8 +1178,12 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
> goto out;
> }
>
> - tbl = nd_table(dev_net(dev));
> - neigh = __neigh_lookup(tbl, saddr, dev, 1);
> + neigh = ipv6_neigh_lookup(dev, saddr);
> + if (!neigh) {
> + neigh = ipv6_neigh_create(dev, saddr);
> + if (IS_ERR(neigh))
> + goto out;
> + }
> if (neigh) {
> ndisc_update(dev, neigh, lladdr, NUD_STALE,
> NEIGH_UPDATE_F_WEAK_OVERRIDE|
> @@ -1478,9 +1483,14 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
> * Process options.
> */
>
> - if (!neigh)
> - neigh = __neigh_lookup(nd_table(net), &ipv6_hdr(skb)->saddr,
> - skb->dev, 1);
> + if (!neigh) {
> + neigh = ipv6_neigh_lookup(skb->dev, &ipv6_hdr(skb)->saddr);
> + if (!neigh) {
> + neigh = ipv6_neigh_create(skb->dev, &ipv6_hdr(skb)->saddr);
> + if (IS_ERR(neigh))
> + neigh = NULL;
> + }
> + }
> if (neigh) {
> u8 *lladdr = NULL;
> if (ndopts.nd_opts_src_lladdr) {
> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> index 8baac4d85251..ea9f0a4c34f9 100644
> --- a/net/ipv6/route.c
> +++ b/net/ipv6/route.c
> @@ -218,7 +218,7 @@ struct neighbour *__ip6_dst_neigh_lookup(const struct in6_addr *gw,
> if (n)
> return n;
>
> - n = neigh_create(nd_table(dev_net(dev)), daddr, dev);
> + n = ipv6_neigh_create(dev, daddr);
> return IS_ERR(n) ? NULL : n;
> }
>
> @@ -4277,9 +4277,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
> */
> dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
>
> - neigh = __neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev, 1);
> - if (!neigh)
> - return;
> + neigh = ipv6_neigh_lookup(dev, &msg->target);
> + if (!neigh) {
> + neigh = ipv6_neigh_create(dev, &msg->target);
> + if (IS_ERR(neigh))
> + return;
> + }
>
> /*
> * We have finally decided to accept it.
> diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
> index 409ce50cc0db..19ccf1a55988 100644
> --- a/net/sched/sch_teql.c
> +++ b/net/sched/sch_teql.c
> @@ -16,6 +16,7 @@
> #include <linux/skbuff.h>
> #include <linux/moduleparam.h>
> #include <net/dst.h>
> +#include <net/ndisc.h>
> #include <net/neighbour.h>
> #include <net/pkt_sched.h>
>
> @@ -257,7 +258,16 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
> if (dst->dev != dev) {
> struct neighbour *mn;
>
> - mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
> +#if IS_ENABLED(CONFIG_IPV6)
> + if (n->tbl->family == AF_INET6) {
> + mn = ipv6_neigh_lookup(dev, n->primary_key);
> + if (!mn)
> + mn = ipv6_neigh_create(dev, n->primary_key);
> + } else
> +#endif
> + {
> + mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
> + }
> neigh_release(n);
> if (IS_ERR(mn))
> return PTR_ERR(mn);
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends.
2026-10-06 17:53 ` Fernando Fernandez Mancera
@ 2026-10-06 18:01 ` Kuniyuki Iwashima
2026-10-06 20:34 ` Fernando Fernandez Mancera
0 siblings, 1 reply; 18+ messages in thread
From: Kuniyuki Iwashima @ 2026-10-06 18:01 UTC (permalink / raw)
To: Fernando Fernandez Mancera
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel, Simon Horman,
Kuniyuki Iwashima, netdev, syzbot+5a8857f0b4a0a7b12c62,
Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Mark Bloch,
Petr Machata, Edward Cree, Nikolay Aleksandrov, Alexander Aring,
Stefan Schmidt, Miquel Raynal
On Tue, Oct 6, 2026 at 10:53 AM Fernando Fernandez Mancera
<fmancera@suse.de> wrote:
>
> On 10/3/26 11:23 PM, Kuniyuki Iwashima wrote:
> > syzbot reported the splat below in neigh_mark_dead() [0]
> > where tbl->lock was not held while neigh_ifdown() should
> > have acquired one.
> >
> > This only happens when a neigh_table accidentally has a
> > neighbour from a different netns.
> >
> > In ip6_finish_output2(), the net argument is the caller's and
> > does not always match dev_net(dev) fetched from dst. (e.g. xfrm)
> >
> > It is error-prone to require callers to fetch netns and
> > neigh_table and pass it with dev to neigh_lookup(), etc.
> >
> > Let's replace neigh_lookup() and friends with IPv6 helpers.
> >
> > Note that __neigh_lookup() is split into ipv6_neigh_lookup()
> > and ipv6_neigh_create().
> >
> > [0]:
> > debug_locks && !(lock_is_held(&(&n->tbl->lock)->dep_map) != 0)
> > WARNING: net/core/neighbour.c:154 at neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154, CPU#0: syz.0.857/9765
> > Modules linked in:
> > CPU: 0 UID: 0 PID: 9765 Comm: syz.0.857 Not tainted syzkaller #0 PREEMPT(full)
> > Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
> > RIP: 0010:neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154
> > Code: e8 03 42 80 3c 28 00 74 08 48 89 df e8 ee 9a 80 f8 4c 89 33 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc e8 86 95 10 f8 90 <0f> 0b 90 e9 8f fd ff ff 48 c7 c1 80 9a 7a 90 80 e1 07 80 c1 03 38
> > RSP: 0018:ffffc90003726600 EFLAGS: 00010287
> > RAX: ffffffff89b7467a RBX: ffff888022e86000 RCX: 0000000000080000
> > RDX: ffffc900047fa000 RSI: 0000000000003e08 RDI: 0000000000003e09
> > RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000004
> > R10: dffffc0000000000 R11: fffff520006e4cb8 R12: ffff888022e8613c
> > R13: dffffc0000000000 R14: ffff888022e86020 R15: ffff888022e86000
> > FS: 00007f9c30f046c0(0000) GS:ffff888124cc6000(0000) knlGS:0000000000000000
> > CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > CR2: 0000000000000000 CR3: 0000000076c56000 CR4: 00000000003526f0
> > Call Trace:
> > <TASK>
> > neigh_flush_one+0x27c/0x5a0 net/core/neighbour.c:388
> > neigh_flush_dev net/core/neighbour.c:432 [inline]
> > __neigh_ifdown+0x1fb/0xc70 net/core/neighbour.c:465
> > neigh_ifdown+0x1f/0x30 net/core/neighbour.c:487
> > rt6_disable_ip+0x751/0x7e0 net/ipv6/route.c:5058
> > addrconf_ifdown+0x155/0x1ad0 net/ipv6/addrconf.c:3892
> > addrconf_notify+0x1bc/0x1050 net/ipv6/addrconf.c:-1
> > notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85
> > call_netdevice_notifiers_mtu net/core/dev.c:2350 [inline]
> > netif_set_mtu_ext+0x5ac/0x830 net/core/dev.c:9963
> > do_setlink+0xa81/0x47a0 net/core/rtnetlink.c:3247
> > rtnl_setlink+0x578/0x820 net/core/rtnetlink.c:3623
> > rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7159
> > netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572
> > netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline]
> > netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361
> > netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916
> > sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800
> > __sock_sendmsg net/socket.c:815 [inline]
> > sock_write_iter+0x2de/0x3e0 net/socket.c:1266
> > do_iter_readv_writev+0x612/0x8c0 fs/read_write.c:-1
> > vfs_writev+0x343/0x990 fs/read_write.c:1058
> > do_writev+0x154/0x2e0 fs/read_write.c:1104
> > do_syscall_x64 arch/x86/emlxsw_sp_ul_rif_getntry/syscall_64.c:61 [inline]
> > do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
> > entry_SYSCALL_64_after_hwframe+0x77/0x7f
> > RIP: 0033:0x7f9c2ff9e159
> > Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
> > RSP: 002b:00007f9c30f04028 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
> > RAX: ffffffffffffffda RBX: 00007f9c30225fa0 RCX: 00007f9c2ff9e159
> > RDX: 0000000000000001 RSI: 00002000000003c0 RDI: 0000000000000004
> > RBP: 00007f9c3003506b R08: 0000000000000000 R09: 0000000000000000
> > R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> > R13: 00007f9c30226038 R14: 00007f9c30225fa0 R15: 00007ffed3c74808
> > </TASK>
> >
> > Fixes: df5f4f372de5 ("ipv6: Replace &nd_tbl with nd_table(net).")
> > Reported-by: syzbot+5a8857f0b4a0a7b12c62@syzkaller.appspotmail.com
> > Closes: https://lore.kernel.org/netdev/6abd69a9.80e1c6cc.22483f.0005.GAE@google.com/
> > Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
> > ---
> > v2: Convert __teql_resolve()
> >
> > Cc: Saeed Mahameed <saeedm@nvidia.com>
> > Cc: Leon Romanovsky <leon@kernel.org>
> > Cc: Tariq Toukan <tariqt@nvidia.com>
> > Cc: Mark Bloch <mbloch@nvidia.com>
> > Cc: Petr Machata <petrm@nvidia.com>
> > Cc: Edward Cree <ecree.xilinx@gmail.com>
> > Cc: Nikolay Aleksandrov <razor@blackwall.org>
> > Cc: Alexander Aring <alex.aring@gmail.com>
> > Cc: Stefan Schmidt <stefan@datenfreihafen.org>
> > Cc: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> > .../mellanox/mlx5/core/en/tc_tun_encap.c | 13 +++----
> > .../ethernet/mellanox/mlxsw/spectrum_router.c | 29 ++++++++-------
> > .../ethernet/mellanox/mlxsw/spectrum_span.c | 24 ++++++++-----
> > .../netronome/nfp/flower/tunnel_conf.c | 4 +--
> > drivers/net/ethernet/sfc/tc_counters.c | 5 ++-
> > drivers/net/vrf.c | 4 +--
> > drivers/net/vxlan/vxlan_core.c | 6 ++--
> > include/net/ndisc.h | 7 ++--
> > net/bridge/br_arp_nd_proxy.c | 2 +-
> > net/ieee802154/6lowpan/tx.c | 3 +-
> > net/ipv4/fib_semantics.c | 2 +-
> > net/ipv6/ip6_output.c | 2 +-
> > net/ipv6/ndisc.c | 36 ++++++++++++-------
> > net/ipv6/route.c | 11 +++---
> > net/sched/sch_teql.c | 12 ++++++-
> > 15 files changed, 90 insertions(+), 70 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
> > index 67c12ca19d59..fe0258375ef6 100644
> > --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
> > +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
> > @@ -439,21 +439,18 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
> > if (neigh_used) {
> > struct net_device *dev = READ_ONCE(nhe->neigh_dev);
> > struct net *net = dev_net(dev);
> > - struct neigh_table *tbl;
> >
> > nhe->reported_lastuse = jiffies;
> >
> > + /* find the relevant neigh according to the cached device and
> > + * dst ip pair
> > + */
> > #if IS_ENABLED(CONFIG_IPV6)
> > if (m_neigh->family != AF_INET)
> > - tbl = nd_table(net);
> > + n = ipv6_neigh_lookup(dev, &m_neigh->dst_ip);
> > else
> > #endif
> > - tbl = arp_table(net);
> > -
> > - /* find the relevant neigh according to the cached device and
> > - * dst ip pair
> > - */
> > - n = neigh_lookup(tbl, &m_neigh->dst_ip, dev);
> > + n = neigh_lookup(arp_table(net), &m_neigh->dst_ip, dev);
> > if (!n)
> > return;
> >
> > diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
> > index ba8a7a44ce9e..1f4753213b9c 100644
> > --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
> > +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
> > @@ -2449,8 +2449,6 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
> > char *rauhtd_pl,
> > int rec_index)
> > {
> > - struct net *net = mlxsw_sp_net(mlxsw_sp);
> > - struct neigh_table *tbl;
> > struct net_device *dev;
> > struct neighbour *n;
> > struct in6_addr dip;
> > @@ -2464,9 +2462,8 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
> > return;
> > }
> >
> > - tbl = nd_table(net);
> > dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
> > - n = neigh_lookup(tbl, &dip, dev);
> > + n = ipv6_neigh_lookup(dev, &dip);
>
>
> Hi Kuniyuki,
>
> I have checked Sashiko's feedback [0] and I think it is right.
I think this is false-positive.
This was pointed out in v1 too, but I did not add NULL check to avoid
defensive programming.
Hardware only reports neighbour activity via RAUHTD for entries programmed
into RAUHT by mlxsw_sp_neigh_entry_update(). Those entries are created only
in mlxsw_sp_neigh_entry_create(), which resolves the RIF via
mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev) where n->dev is always non-NULL.
Thus, underlay and loopback RIFs (where mlxsw_sp_rif_dev() is NULL) never
have neighbour entries programmed in hardware.
Also, when a RIF is destroyed in mlxsw_sp_rif_destroy(), all of its
RAUHT entries are synchronously removed from hardware in
mlxsw_sp_neigh_rif_gone_sync() and router->rifs[rif] is cleared under
router->lock (the same lock held during the RAUHTD dump) before the RIF
index can be reused.
>
> mlxsw_sp_router_ul_rif_get() can be called with a NULL mlxsw_sp_crif
> pointer which then would call mlxsw_sp_ul_rif_create() and there during
> the alloc a rif with a NULL crif is created making this feedback being
> correct.
>
> I think a simple NULL check here for dev should be enough.
>
> [0]
> https://sashiko.dev/#/message/20261003212336.1304988-7-kuniyu%40google.com
NIPA's Sashiko is pretty better than Gemini 3.1 these days.
I hope our instance support Gemini 4 soon :)
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261003212336.1304988-1-kuniyu%40google.com
>
> Thanks!
>
> > if (!n)
> > return;
> >
> > @@ -4312,17 +4309,23 @@ mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
> > net = dev_net(dev);
> >
> > #if IS_ENABLED(CONFIG_IPV6)
> > - if (nh->family == AF_INET6)
> > - tbl = nd_table(net);
> > - else
> > + if (nh->family == AF_INET6) {
> > + n = ipv6_neigh_lookup(dev, &nh->gw_addr);
> > + if (!n) {
> > + n = ipv6_neigh_create(dev, &nh->gw_addr);
> > + if (!IS_ERR(n))
> > + neigh_event_send(n, NULL);
> > + }
> > + } else
> > #endif
> > + {
> > tbl = arp_table(net);
> > -
> > - n = neigh_lookup(tbl, &nh->gw_addr, dev);
> > - if (!n) {
> > - n = neigh_create(tbl, &nh->gw_addr, dev);
> > - if (!IS_ERR(n))
> > - neigh_event_send(n, NULL);
> > + n = neigh_lookup(tbl, &nh->gw_addr, dev);
> > + if (!n) {
> > + n = neigh_create(tbl, &nh->gw_addr, dev);
> > + if (!IS_ERR(n))
> > + neigh_event_send(n, NULL);
> > + }
> > }
> >
> > return n;
> > diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
> > index d34d2040177b..79947f68b10d 100644
> > --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
> > +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
> > @@ -235,17 +235,23 @@ static int mlxsw_sp_span_dmac(int family,
> > int err = 0;
> >
> > #if IS_ENABLED(CONFIG_IPV6_GRE)
> > - if (family == AF_INET6)
> > - tbl = nd_table(net);
> > - else
> > + if (family == AF_INET6) {
> > + neigh = ipv6_neigh_lookup(dev, pkey);
> > + if (!neigh) {
> > + neigh = ipv6_neigh_create(dev, pkey);
> > + if (IS_ERR(neigh))
> > + return PTR_ERR(neigh);
> > + }
> > + } else
> > #endif
> > + {
> > tbl = arp_table(net);
> > -
> > - neigh = neigh_lookup(tbl, pkey, dev);
> > - if (!neigh) {
> > - neigh = neigh_create(tbl, pkey, dev);
> > - if (IS_ERR(neigh))
> > - return PTR_ERR(neigh);
> > + neigh = neigh_lookup(tbl, pkey, dev);
> > + if (!neigh) {
> > + neigh = neigh_create(tbl, pkey, dev);
> > + if (IS_ERR(neigh))
> > + return PTR_ERR(neigh);
> > + }
> > }
> >
> > neigh_event_send(neigh, NULL);
> > diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
> > index d650d33e3709..27d80ec8e895 100644
> > --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
> > +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
> > @@ -253,7 +253,6 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
> > #if IS_ENABLED(CONFIG_IPV6)
> > struct nfp_tun_active_tuns_v6 *payload;
> > struct net_device *netdev;
> > - struct neigh_table *tbl;
> > int count, i, pay_len;
> > struct neighbour *n;
> > void *ipv6_add;
> > @@ -280,8 +279,7 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
> > if (!netdev)
> > continue;
> >
> > - tbl = nd_table(dev_net(netdev));
> > - n = neigh_lookup(tbl, ipv6_add, netdev);
> > + n = ipv6_neigh_lookup(netdev, ipv6_add);
> > if (!n)
> > continue;
> >
> > diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c
> > index 793a562fc1f7..ae6cc6b93864 100644
> > --- a/drivers/net/ethernet/sfc/tc_counters.c
> > +++ b/drivers/net/ethernet/sfc/tc_counters.c
> > @@ -116,9 +116,8 @@ static void efx_tc_counter_work(struct work_struct *work)
> > encap->neigh->egdev);
> > else
> > #if IS_ENABLED(CONFIG_IPV6)
> > - n = neigh_lookup(nd_table(net),
> > - &encap->neigh->dst_ip6,
> > - encap->neigh->egdev);
> > + n = ipv6_neigh_lookup(encap->neigh->egdev,
> > + &encap->neigh->dst_ip6);
> > #else
> > n = NULL;
> > #endif
> > diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
> > index 320f3584a43b..79d433f49f80 100644
> > --- a/drivers/net/vrf.c
> > +++ b/drivers/net/vrf.c
> > @@ -614,9 +614,9 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
> >
> > rcu_read_lock();
> > nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr);
> > - neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
> > + neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
> > if (unlikely(!neigh))
> > - neigh = __neigh_create(nd_table(net), nexthop, dst->dev, false);
> > + neigh = ipv6_neigh_create_noref(dev, nexthop);
> > if (!IS_ERR(neigh)) {
> > sock_confirm_neigh(skb, neigh);
> > ret = neigh_output(neigh, skb, false);
> > diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> > index 27b0b6567d52..513779c07621 100644
> > --- a/drivers/net/vxlan/vxlan_core.c
> > +++ b/drivers/net/vxlan/vxlan_core.c
> > @@ -2091,8 +2091,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb,
> > ipv6_addr_is_multicast(&msg->target))
> > goto out;
> >
> > - n = neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev);
> > -
> > + n = ipv6_neigh_lookup(dev, &msg->target);
> > if (n) {
> > struct vxlan_rdst *rdst = NULL;
> > u8 ha[ETH_ALEN] __aligned(2);
> > @@ -2189,9 +2188,8 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb,
> > if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
> > return false;
> >
> > - tbl = nd_table(dev_net(dev));
> > pip6 = ipv6_hdr(skb);
> > - n = neigh_lookup(tbl, &pip6->daddr, dev);
> > + n = ipv6_neigh_lookup(dev, &pip6->daddr);
> > if (!n && (cfg->flags & VXLAN_F_L3MISS)) {
> > union vxlan_addr ipa = {
> > .sin6.sin6_addr = pip6->daddr,
> > diff --git a/include/net/ndisc.h b/include/net/ndisc.h
> > index 2fce6fccf55a..91898a2475e7 100644
> > --- a/include/net/ndisc.h
> > +++ b/include/net/ndisc.h
> > @@ -423,11 +423,8 @@ static inline struct neighbour *ip_neigh_gw6(struct net_device *dev,
> > struct neighbour *neigh;
> >
> > neigh = __ipv6_neigh_lookup_noref(dev, addr);
> > - if (unlikely(!neigh)) {
> > - struct neigh_table *tbl = nd_table(dev_net(dev));
> > -
> > - neigh = __neigh_create(tbl, addr, dev, false);
> > - }
> > + if (unlikely(!neigh))
> > + neigh = ipv6_neigh_create_noref(dev, addr);
> >
> > return neigh;
> > #else
> > diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
> > index ba4a63840b21..c23b99517cd5 100644
> > --- a/net/bridge/br_arp_nd_proxy.c
> > +++ b/net/bridge/br_arp_nd_proxy.c
> > @@ -487,7 +487,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
> > return;
> > }
> >
> > - n = neigh_lookup(nd_table(dev_net(vlandev)), &msg->target, vlandev);
> > + n = ipv6_neigh_lookup(vlandev, &msg->target);
> > if (n) {
> > struct net_bridge_fdb_entry *f;
> > u8 ha[ETH_ALEN] __aligned(2);
> > diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
> > index 4f511476b992..b261daedc290 100644
> > --- a/net/ieee802154/6lowpan/tx.c
> > +++ b/net/ieee802154/6lowpan/tx.c
> > @@ -58,9 +58,8 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
> > info->daddr.mode = IEEE802154_ADDR_SHORT;
> > } else {
> > __le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
> > - struct neigh_table *tbl = nd_table(dev_net(ldev));
> >
> > - n = neigh_lookup(tbl, &hdr->daddr, ldev);
> > + n = ipv6_neigh_lookup(ldev, &hdr->daddr);
> > if (n) {
> > llneigh = lowpan_802154_neigh(neighbour_priv(n));
> > read_lock_bh(&n->lock);
> > diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
> > index e3bcc25229b0..a98c7670d2ce 100644
> > --- a/net/ipv4/fib_semantics.c
> > +++ b/net/ipv4/fib_semantics.c
> > @@ -617,7 +617,7 @@ static int fib_detect_death(struct fib_info *fi, int order,
> > if (likely(nhc->nhc_gw_family == AF_INET))
> > n = neigh_lookup(arp_table(net), &nhc->nhc_gw.ipv4, nhc->nhc_dev);
> > else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6)
> > - n = neigh_lookup(nd_table(net), &nhc->nhc_gw.ipv6, nhc->nhc_dev);
> > + n = ipv6_neigh_lookup(nhc->nhc_dev, &nhc->nhc_gw.ipv6);
> > else
> > n = NULL;
> >
> > diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> > index 10146a57b69e..25fe0ba98b1a 100644
> > --- a/net/ipv6/ip6_output.c
> > +++ b/net/ipv6/ip6_output.c
> > @@ -127,7 +127,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
> >
> > if (IS_ERR_OR_NULL(neigh)) {
> > if (unlikely(!neigh))
> > - neigh = __neigh_create(nd_table(net), nexthop, dev, false);
> > + neigh = ipv6_neigh_create_noref(dev, nexthop);
> > if (IS_ERR(neigh)) {
> > IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
> > kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
> > diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> > index e1cbffaa0ad0..0ed1a619372b 100644
> > --- a/net/ipv6/ndisc.c
> > +++ b/net/ipv6/ndisc.c
> > @@ -947,8 +947,12 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
> > * update / create cache entry
> > * for the source address
> > */
> > - neigh = __neigh_lookup(tbl, saddr, dev,
> > - !inc || lladdr || !dev->addr_len);
> > + neigh = ipv6_neigh_lookup(dev, saddr);
> > + if (!neigh && (!inc || lladdr || !dev->addr_len)) {
> > + neigh = ipv6_neigh_create(dev, saddr);
> > + if (IS_ERR(neigh))
> > + neigh = NULL;
> > + }
> > if (neigh)
> > ndisc_update(dev, neigh, lladdr, NUD_STALE,
> > NEIGH_UPDATE_F_WEAK_OVERRIDE|
> > @@ -998,7 +1002,6 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> > struct net *net = dev_net(dev);
> > struct ndisc_options ndopts;
> > struct inet6_ifaddr *ifp;
> > - struct neigh_table *tbl;
> > struct neighbour *neigh;
> > struct inet6_dev *idev;
> > u8 *lladdr = NULL;
> > @@ -1063,8 +1066,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> > return reason;
> > }
> >
> > - tbl = nd_table(net);
> > - neigh = neigh_lookup(tbl, &msg->target, dev);
> > + neigh = ipv6_neigh_lookup(dev, &msg->target);
> >
> > /* RFC 9131 updates original Neighbour Discovery RFC 4861.
> > * NAs with Target LL Address option can now create a STALE neighbor
> > @@ -1093,7 +1095,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> > return reason;
> > }
> > if (!neigh)
> > - neigh = neigh_create(tbl, &msg->target, dev);
> > + neigh = ipv6_neigh_create(dev, &msg->target);
> > new_state = NUD_STALE;
> > }
> >
> > @@ -1108,7 +1110,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
> > if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
> > READ_ONCE(net->ipv6.devconf_all->forwarding) &&
> > READ_ONCE(net->ipv6.devconf_all->proxy_ndp) &&
> > - pneigh_lookup(tbl, &msg->target, dev)) {
> > + pneigh_lookup(nd_table(dev_net(dev)), &msg->target, dev)) {
> > /* XXX: idev->cnf.proxy_ndp */
> > goto out;
> > }
> > @@ -1141,7 +1143,6 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
> > unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
> > struct net_device *dev = skb->dev;
> > struct ndisc_options ndopts;
> > - struct neigh_table *tbl;
> > struct neighbour *neigh;
> > struct inet6_dev *idev;
> > u8 *lladdr = NULL;
> > @@ -1177,8 +1178,12 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
> > goto out;
> > }
> >
> > - tbl = nd_table(dev_net(dev));
> > - neigh = __neigh_lookup(tbl, saddr, dev, 1);
> > + neigh = ipv6_neigh_lookup(dev, saddr);
> > + if (!neigh) {
> > + neigh = ipv6_neigh_create(dev, saddr);
> > + if (IS_ERR(neigh))
> > + goto out;
> > + }
> > if (neigh) {
> > ndisc_update(dev, neigh, lladdr, NUD_STALE,
> > NEIGH_UPDATE_F_WEAK_OVERRIDE|
> > @@ -1478,9 +1483,14 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
> > * Process options.
> > */
> >
> > - if (!neigh)
> > - neigh = __neigh_lookup(nd_table(net), &ipv6_hdr(skb)->saddr,
> > - skb->dev, 1);
> > + if (!neigh) {
> > + neigh = ipv6_neigh_lookup(skb->dev, &ipv6_hdr(skb)->saddr);
> > + if (!neigh) {
> > + neigh = ipv6_neigh_create(skb->dev, &ipv6_hdr(skb)->saddr);
> > + if (IS_ERR(neigh))
> > + neigh = NULL;
> > + }
> > + }
> > if (neigh) {
> > u8 *lladdr = NULL;
> > if (ndopts.nd_opts_src_lladdr) {
> > diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> > index 8baac4d85251..ea9f0a4c34f9 100644
> > --- a/net/ipv6/route.c
> > +++ b/net/ipv6/route.c
> > @@ -218,7 +218,7 @@ struct neighbour *__ip6_dst_neigh_lookup(const struct in6_addr *gw,
> > if (n)
> > return n;
> >
> > - n = neigh_create(nd_table(dev_net(dev)), daddr, dev);
> > + n = ipv6_neigh_create(dev, daddr);
> > return IS_ERR(n) ? NULL : n;
> > }
> >
> > @@ -4277,9 +4277,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
> > */
> > dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
> >
> > - neigh = __neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev, 1);
> > - if (!neigh)
> > - return;
> > + neigh = ipv6_neigh_lookup(dev, &msg->target);
> > + if (!neigh) {
> > + neigh = ipv6_neigh_create(dev, &msg->target);
> > + if (IS_ERR(neigh))
> > + return;
> > + }
> >
> > /*
> > * We have finally decided to accept it.
> > diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
> > index 409ce50cc0db..19ccf1a55988 100644
> > --- a/net/sched/sch_teql.c
> > +++ b/net/sched/sch_teql.c
> > @@ -16,6 +16,7 @@
> > #include <linux/skbuff.h>
> > #include <linux/moduleparam.h>
> > #include <net/dst.h>
> > +#include <net/ndisc.h>
> > #include <net/neighbour.h>
> > #include <net/pkt_sched.h>
> >
> > @@ -257,7 +258,16 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
> > if (dst->dev != dev) {
> > struct neighbour *mn;
> >
> > - mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
> > +#if IS_ENABLED(CONFIG_IPV6)
> > + if (n->tbl->family == AF_INET6) {
> > + mn = ipv6_neigh_lookup(dev, n->primary_key);
> > + if (!mn)
> > + mn = ipv6_neigh_create(dev, n->primary_key);
> > + } else
> > +#endif
> > + {
> > + mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
> > + }
> > neigh_release(n);
> > if (IS_ERR(mn))
> > return PTR_ERR(mn);
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends.
2026-10-06 18:01 ` Kuniyuki Iwashima
@ 2026-10-06 20:34 ` Fernando Fernandez Mancera
0 siblings, 0 replies; 18+ messages in thread
From: Fernando Fernandez Mancera @ 2026-10-06 20:34 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Ahern, Ido Schimmel, Simon Horman,
Kuniyuki Iwashima, netdev, syzbot+5a8857f0b4a0a7b12c62,
Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Mark Bloch,
Petr Machata, Edward Cree, Nikolay Aleksandrov, Alexander Aring,
Stefan Schmidt, Miquel Raynal
On 10/6/26 8:01 PM, Kuniyuki Iwashima wrote:
> On Tue, Oct 6, 2026 at 10:53 AM Fernando Fernandez Mancera
> <fmancera@suse.de> wrote:
>>
>> On 10/3/26 11:23 PM, Kuniyuki Iwashima wrote:
>>> syzbot reported the splat below in neigh_mark_dead() [0]
>>> where tbl->lock was not held while neigh_ifdown() should
>>> have acquired one.
>>>
>>> This only happens when a neigh_table accidentally has a
>>> neighbour from a different netns.
>>>
>>> In ip6_finish_output2(), the net argument is the caller's and
>>> does not always match dev_net(dev) fetched from dst. (e.g. xfrm)
>>>
>>> It is error-prone to require callers to fetch netns and
>>> neigh_table and pass it with dev to neigh_lookup(), etc.
>>>
>>> Let's replace neigh_lookup() and friends with IPv6 helpers.
>>>
>>> Note that __neigh_lookup() is split into ipv6_neigh_lookup()
>>> and ipv6_neigh_create().
>>>
>>> [0]:
>>> debug_locks && !(lock_is_held(&(&n->tbl->lock)->dep_map) != 0)
>>> WARNING: net/core/neighbour.c:154 at neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154, CPU#0: syz.0.857/9765
>>> Modules linked in:
>>> CPU: 0 UID: 0 PID: 9765 Comm: syz.0.857 Not tainted syzkaller #0 PREEMPT(full)
>>> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
>>> RIP: 0010:neigh_mark_dead+0x2fb/0x340 net/core/neighbour.c:154
>>> Code: e8 03 42 80 3c 28 00 74 08 48 89 df e8 ee 9a 80 f8 4c 89 33 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc e8 86 95 10 f8 90 <0f> 0b 90 e9 8f fd ff ff 48 c7 c1 80 9a 7a 90 80 e1 07 80 c1 03 38
>>> RSP: 0018:ffffc90003726600 EFLAGS: 00010287
>>> RAX: ffffffff89b7467a RBX: ffff888022e86000 RCX: 0000000000080000
>>> RDX: ffffc900047fa000 RSI: 0000000000003e08 RDI: 0000000000003e09
>>> RBP: 0000000000000000 R08: 0000000000000003 R09: 0000000000000004
>>> R10: dffffc0000000000 R11: fffff520006e4cb8 R12: ffff888022e8613c
>>> R13: dffffc0000000000 R14: ffff888022e86020 R15: ffff888022e86000
>>> FS: 00007f9c30f046c0(0000) GS:ffff888124cc6000(0000) knlGS:0000000000000000
>>> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>> CR2: 0000000000000000 CR3: 0000000076c56000 CR4: 00000000003526f0
>>> Call Trace:
>>> <TASK>
>>> neigh_flush_one+0x27c/0x5a0 net/core/neighbour.c:388
>>> neigh_flush_dev net/core/neighbour.c:432 [inline]
>>> __neigh_ifdown+0x1fb/0xc70 net/core/neighbour.c:465
>>> neigh_ifdown+0x1f/0x30 net/core/neighbour.c:487
>>> rt6_disable_ip+0x751/0x7e0 net/ipv6/route.c:5058
>>> addrconf_ifdown+0x155/0x1ad0 net/ipv6/addrconf.c:3892
>>> addrconf_notify+0x1bc/0x1050 net/ipv6/addrconf.c:-1
>>> notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85
>>> call_netdevice_notifiers_mtu net/core/dev.c:2350 [inline]
>>> netif_set_mtu_ext+0x5ac/0x830 net/core/dev.c:9963
>>> do_setlink+0xa81/0x47a0 net/core/rtnetlink.c:3247
>>> rtnl_setlink+0x578/0x820 net/core/rtnetlink.c:3623
>>> rtnetlink_rcv_msg+0x802/0xc00 net/core/rtnetlink.c:7159
>>> netlink_rcv_skb+0x226/0x4a0 net/netlink/af_netlink.c:2572
>>> netlink_unicast_kernel net/netlink/af_netlink.c:1335 [inline]
>>> netlink_unicast+0x7bd/0x940 net/netlink/af_netlink.c:1361
>>> netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1916
>>> sock_sendmsg_nosec+0x13a/0x180 net/socket.c:800
>>> __sock_sendmsg net/socket.c:815 [inline]
>>> sock_write_iter+0x2de/0x3e0 net/socket.c:1266
>>> do_iter_readv_writev+0x612/0x8c0 fs/read_write.c:-1
>>> vfs_writev+0x343/0x990 fs/read_write.c:1058
>>> do_writev+0x154/0x2e0 fs/read_write.c:1104
>>> do_syscall_x64 arch/x86/emlxsw_sp_ul_rif_getntry/syscall_64.c:61 [inline]
>>> do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
>>> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>>> RIP: 0033:0x7f9c2ff9e159
>>> Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
>>> RSP: 002b:00007f9c30f04028 EFLAGS: 00000246 ORIG_RAX: 0000000000000014
>>> RAX: ffffffffffffffda RBX: 00007f9c30225fa0 RCX: 00007f9c2ff9e159
>>> RDX: 0000000000000001 RSI: 00002000000003c0 RDI: 0000000000000004
>>> RBP: 00007f9c3003506b R08: 0000000000000000 R09: 0000000000000000
>>> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
>>> R13: 00007f9c30226038 R14: 00007f9c30225fa0 R15: 00007ffed3c74808
>>> </TASK>
>>>
>>> Fixes: df5f4f372de5 ("ipv6: Replace &nd_tbl with nd_table(net).")
>>> Reported-by: syzbot+5a8857f0b4a0a7b12c62@syzkaller.appspotmail.com
>>> Closes: https://lore.kernel.org/netdev/6abd69a9.80e1c6cc.22483f.0005.GAE@google.com/
>>> Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
>>> ---
>>> v2: Convert __teql_resolve()
>>>
>>> Cc: Saeed Mahameed <saeedm@nvidia.com>
>>> Cc: Leon Romanovsky <leon@kernel.org>
>>> Cc: Tariq Toukan <tariqt@nvidia.com>
>>> Cc: Mark Bloch <mbloch@nvidia.com>
>>> Cc: Petr Machata <petrm@nvidia.com>
>>> Cc: Edward Cree <ecree.xilinx@gmail.com>
>>> Cc: Nikolay Aleksandrov <razor@blackwall.org>
>>> Cc: Alexander Aring <alex.aring@gmail.com>
>>> Cc: Stefan Schmidt <stefan@datenfreihafen.org>
>>> Cc: Miquel Raynal <miquel.raynal@bootlin.com>
>>> ---
>>> .../mellanox/mlx5/core/en/tc_tun_encap.c | 13 +++----
>>> .../ethernet/mellanox/mlxsw/spectrum_router.c | 29 ++++++++-------
>>> .../ethernet/mellanox/mlxsw/spectrum_span.c | 24 ++++++++-----
>>> .../netronome/nfp/flower/tunnel_conf.c | 4 +--
>>> drivers/net/ethernet/sfc/tc_counters.c | 5 ++-
>>> drivers/net/vrf.c | 4 +--
>>> drivers/net/vxlan/vxlan_core.c | 6 ++--
>>> include/net/ndisc.h | 7 ++--
>>> net/bridge/br_arp_nd_proxy.c | 2 +-
>>> net/ieee802154/6lowpan/tx.c | 3 +-
>>> net/ipv4/fib_semantics.c | 2 +-
>>> net/ipv6/ip6_output.c | 2 +-
>>> net/ipv6/ndisc.c | 36 ++++++++++++-------
>>> net/ipv6/route.c | 11 +++---
>>> net/sched/sch_teql.c | 12 ++++++-
>>> 15 files changed, 90 insertions(+), 70 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
>>> index 67c12ca19d59..fe0258375ef6 100644
>>> --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
>>> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
>>> @@ -439,21 +439,18 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
>>> if (neigh_used) {
>>> struct net_device *dev = READ_ONCE(nhe->neigh_dev);
>>> struct net *net = dev_net(dev);
>>> - struct neigh_table *tbl;
>>>
>>> nhe->reported_lastuse = jiffies;
>>>
>>> + /* find the relevant neigh according to the cached device and
>>> + * dst ip pair
>>> + */
>>> #if IS_ENABLED(CONFIG_IPV6)
>>> if (m_neigh->family != AF_INET)
>>> - tbl = nd_table(net);
>>> + n = ipv6_neigh_lookup(dev, &m_neigh->dst_ip);
>>> else
>>> #endif
>>> - tbl = arp_table(net);
>>> -
>>> - /* find the relevant neigh according to the cached device and
>>> - * dst ip pair
>>> - */
>>> - n = neigh_lookup(tbl, &m_neigh->dst_ip, dev);
>>> + n = neigh_lookup(arp_table(net), &m_neigh->dst_ip, dev);
>>> if (!n)
>>> return;
>>>
>>> diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
>>> index ba8a7a44ce9e..1f4753213b9c 100644
>>> --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
>>> +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
>>> @@ -2449,8 +2449,6 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
>>> char *rauhtd_pl,
>>> int rec_index)
>>> {
>>> - struct net *net = mlxsw_sp_net(mlxsw_sp);
>>> - struct neigh_table *tbl;
>>> struct net_device *dev;
>>> struct neighbour *n;
>>> struct in6_addr dip;
>>> @@ -2464,9 +2462,8 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp,
>>> return;
>>> }
>>>
>>> - tbl = nd_table(net);
>>> dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]);
>>> - n = neigh_lookup(tbl, &dip, dev);
>>> + n = ipv6_neigh_lookup(dev, &dip);
>>
>>
>> Hi Kuniyuki,
>>
>> I have checked Sashiko's feedback [0] and I think it is right.
>
> I think this is false-positive.
>
> This was pointed out in v1 too, but I did not add NULL check to avoid
> defensive programming.
>
> Hardware only reports neighbour activity via RAUHTD for entries programmed
> into RAUHT by mlxsw_sp_neigh_entry_update(). Those entries are created only
> in mlxsw_sp_neigh_entry_create(), which resolves the RIF via
> mlxsw_sp_rif_find_by_dev(mlxsw_sp, n->dev) where n->dev is always non-NULL.
> Thus, underlay and loopback RIFs (where mlxsw_sp_rif_dev() is NULL) never
> have neighbour entries programmed in hardware.
>
> Also, when a RIF is destroyed in mlxsw_sp_rif_destroy(), all of its
> RAUHT entries are synchronously removed from hardware in
> mlxsw_sp_neigh_rif_gone_sync() and router->rifs[rif] is cleared under
> router->lock (the same lock held during the RAUHTD dump) before the RIF
> index can be reused.
>
Sorry I missed the mlxsw_sp_rif_find_by_dev() call. You are right here.
Thanks a lot for explaining!
>
>>
>> mlxsw_sp_router_ul_rif_get() can be called with a NULL mlxsw_sp_crif
>> pointer which then would call mlxsw_sp_ul_rif_create() and there during
>> the alloc a rif with a NULL crif is created making this feedback being
>> correct.
>>
>> I think a simple NULL check here for dev should be enough.
>>
>> [0]
>> https://sashiko.dev/#/message/20261003212336.1304988-7-kuniyu%40google.com
>
> NIPA's Sashiko is pretty better than Gemini 3.1 these days.
> I hope our instance support Gemini 4 soon :)
> https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261003212336.1304988-1-kuniyu%40google.com
>
>
>>
>> Thanks!
>>
>>> if (!n)
>>> return;
>>>
>>> @@ -4312,17 +4309,23 @@ mlxsw_sp_nexthop_neigh_lookup(struct mlxsw_sp_nexthop *nh)
>>> net = dev_net(dev);
>>>
>>> #if IS_ENABLED(CONFIG_IPV6)
>>> - if (nh->family == AF_INET6)
>>> - tbl = nd_table(net);
>>> - else
>>> + if (nh->family == AF_INET6) {
>>> + n = ipv6_neigh_lookup(dev, &nh->gw_addr);
>>> + if (!n) {
>>> + n = ipv6_neigh_create(dev, &nh->gw_addr);
>>> + if (!IS_ERR(n))
>>> + neigh_event_send(n, NULL);
>>> + }
>>> + } else
>>> #endif
>>> + {
>>> tbl = arp_table(net);
>>> -
>>> - n = neigh_lookup(tbl, &nh->gw_addr, dev);
>>> - if (!n) {
>>> - n = neigh_create(tbl, &nh->gw_addr, dev);
>>> - if (!IS_ERR(n))
>>> - neigh_event_send(n, NULL);
>>> + n = neigh_lookup(tbl, &nh->gw_addr, dev);
>>> + if (!n) {
>>> + n = neigh_create(tbl, &nh->gw_addr, dev);
>>> + if (!IS_ERR(n))
>>> + neigh_event_send(n, NULL);
>>> + }
>>> }
>>>
>>> return n;
>>> diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
>>> index d34d2040177b..79947f68b10d 100644
>>> --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
>>> +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
>>> @@ -235,17 +235,23 @@ static int mlxsw_sp_span_dmac(int family,
>>> int err = 0;
>>>
>>> #if IS_ENABLED(CONFIG_IPV6_GRE)
>>> - if (family == AF_INET6)
>>> - tbl = nd_table(net);
>>> - else
>>> + if (family == AF_INET6) {
>>> + neigh = ipv6_neigh_lookup(dev, pkey);
>>> + if (!neigh) {
>>> + neigh = ipv6_neigh_create(dev, pkey);
>>> + if (IS_ERR(neigh))
>>> + return PTR_ERR(neigh);
>>> + }
>>> + } else
>>> #endif
>>> + {
>>> tbl = arp_table(net);
>>> -
>>> - neigh = neigh_lookup(tbl, pkey, dev);
>>> - if (!neigh) {
>>> - neigh = neigh_create(tbl, pkey, dev);
>>> - if (IS_ERR(neigh))
>>> - return PTR_ERR(neigh);
>>> + neigh = neigh_lookup(tbl, pkey, dev);
>>> + if (!neigh) {
>>> + neigh = neigh_create(tbl, pkey, dev);
>>> + if (IS_ERR(neigh))
>>> + return PTR_ERR(neigh);
>>> + }
>>> }
>>>
>>> neigh_event_send(neigh, NULL);
>>> diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
>>> index d650d33e3709..27d80ec8e895 100644
>>> --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
>>> +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
>>> @@ -253,7 +253,6 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
>>> #if IS_ENABLED(CONFIG_IPV6)
>>> struct nfp_tun_active_tuns_v6 *payload;
>>> struct net_device *netdev;
>>> - struct neigh_table *tbl;
>>> int count, i, pay_len;
>>> struct neighbour *n;
>>> void *ipv6_add;
>>> @@ -280,8 +279,7 @@ void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
>>> if (!netdev)
>>> continue;
>>>
>>> - tbl = nd_table(dev_net(netdev));
>>> - n = neigh_lookup(tbl, ipv6_add, netdev);
>>> + n = ipv6_neigh_lookup(netdev, ipv6_add);
>>> if (!n)
>>> continue;
>>>
>>> diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c
>>> index 793a562fc1f7..ae6cc6b93864 100644
>>> --- a/drivers/net/ethernet/sfc/tc_counters.c
>>> +++ b/drivers/net/ethernet/sfc/tc_counters.c
>>> @@ -116,9 +116,8 @@ static void efx_tc_counter_work(struct work_struct *work)
>>> encap->neigh->egdev);
>>> else
>>> #if IS_ENABLED(CONFIG_IPV6)
>>> - n = neigh_lookup(nd_table(net),
>>> - &encap->neigh->dst_ip6,
>>> - encap->neigh->egdev);
>>> + n = ipv6_neigh_lookup(encap->neigh->egdev,
>>> + &encap->neigh->dst_ip6);
>>> #else
>>> n = NULL;
>>> #endif
>>> diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
>>> index 320f3584a43b..79d433f49f80 100644
>>> --- a/drivers/net/vrf.c
>>> +++ b/drivers/net/vrf.c
>>> @@ -614,9 +614,9 @@ static int vrf_finish_output6(struct net *net, struct sock *sk,
>>>
>>> rcu_read_lock();
>>> nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr);
>>> - neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
>>> + neigh = __ipv6_neigh_lookup_noref(dev, nexthop);
>>> if (unlikely(!neigh))
>>> - neigh = __neigh_create(nd_table(net), nexthop, dst->dev, false);
>>> + neigh = ipv6_neigh_create_noref(dev, nexthop);
>>> if (!IS_ERR(neigh)) {
>>> sock_confirm_neigh(skb, neigh);
>>> ret = neigh_output(neigh, skb, false);
>>> diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
>>> index 27b0b6567d52..513779c07621 100644
>>> --- a/drivers/net/vxlan/vxlan_core.c
>>> +++ b/drivers/net/vxlan/vxlan_core.c
>>> @@ -2091,8 +2091,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb,
>>> ipv6_addr_is_multicast(&msg->target))
>>> goto out;
>>>
>>> - n = neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev);
>>> -
>>> + n = ipv6_neigh_lookup(dev, &msg->target);
>>> if (n) {
>>> struct vxlan_rdst *rdst = NULL;
>>> u8 ha[ETH_ALEN] __aligned(2);
>>> @@ -2189,9 +2188,8 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb,
>>> if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
>>> return false;
>>>
>>> - tbl = nd_table(dev_net(dev));
>>> pip6 = ipv6_hdr(skb);
>>> - n = neigh_lookup(tbl, &pip6->daddr, dev);
>>> + n = ipv6_neigh_lookup(dev, &pip6->daddr);
>>> if (!n && (cfg->flags & VXLAN_F_L3MISS)) {
>>> union vxlan_addr ipa = {
>>> .sin6.sin6_addr = pip6->daddr,
>>> diff --git a/include/net/ndisc.h b/include/net/ndisc.h
>>> index 2fce6fccf55a..91898a2475e7 100644
>>> --- a/include/net/ndisc.h
>>> +++ b/include/net/ndisc.h
>>> @@ -423,11 +423,8 @@ static inline struct neighbour *ip_neigh_gw6(struct net_device *dev,
>>> struct neighbour *neigh;
>>>
>>> neigh = __ipv6_neigh_lookup_noref(dev, addr);
>>> - if (unlikely(!neigh)) {
>>> - struct neigh_table *tbl = nd_table(dev_net(dev));
>>> -
>>> - neigh = __neigh_create(tbl, addr, dev, false);
>>> - }
>>> + if (unlikely(!neigh))
>>> + neigh = ipv6_neigh_create_noref(dev, addr);
>>>
>>> return neigh;
>>> #else
>>> diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
>>> index ba4a63840b21..c23b99517cd5 100644
>>> --- a/net/bridge/br_arp_nd_proxy.c
>>> +++ b/net/bridge/br_arp_nd_proxy.c
>>> @@ -487,7 +487,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
>>> return;
>>> }
>>>
>>> - n = neigh_lookup(nd_table(dev_net(vlandev)), &msg->target, vlandev);
>>> + n = ipv6_neigh_lookup(vlandev, &msg->target);
>>> if (n) {
>>> struct net_bridge_fdb_entry *f;
>>> u8 ha[ETH_ALEN] __aligned(2);
>>> diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
>>> index 4f511476b992..b261daedc290 100644
>>> --- a/net/ieee802154/6lowpan/tx.c
>>> +++ b/net/ieee802154/6lowpan/tx.c
>>> @@ -58,9 +58,8 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
>>> info->daddr.mode = IEEE802154_ADDR_SHORT;
>>> } else {
>>> __le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
>>> - struct neigh_table *tbl = nd_table(dev_net(ldev));
>>>
>>> - n = neigh_lookup(tbl, &hdr->daddr, ldev);
>>> + n = ipv6_neigh_lookup(ldev, &hdr->daddr);
>>> if (n) {
>>> llneigh = lowpan_802154_neigh(neighbour_priv(n));
>>> read_lock_bh(&n->lock);
>>> diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
>>> index e3bcc25229b0..a98c7670d2ce 100644
>>> --- a/net/ipv4/fib_semantics.c
>>> +++ b/net/ipv4/fib_semantics.c
>>> @@ -617,7 +617,7 @@ static int fib_detect_death(struct fib_info *fi, int order,
>>> if (likely(nhc->nhc_gw_family == AF_INET))
>>> n = neigh_lookup(arp_table(net), &nhc->nhc_gw.ipv4, nhc->nhc_dev);
>>> else if (IS_ENABLED(CONFIG_IPV6) && nhc->nhc_gw_family == AF_INET6)
>>> - n = neigh_lookup(nd_table(net), &nhc->nhc_gw.ipv6, nhc->nhc_dev);
>>> + n = ipv6_neigh_lookup(nhc->nhc_dev, &nhc->nhc_gw.ipv6);
>>> else
>>> n = NULL;
>>>
>>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>>> index 10146a57b69e..25fe0ba98b1a 100644
>>> --- a/net/ipv6/ip6_output.c
>>> +++ b/net/ipv6/ip6_output.c
>>> @@ -127,7 +127,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
>>>
>>> if (IS_ERR_OR_NULL(neigh)) {
>>> if (unlikely(!neigh))
>>> - neigh = __neigh_create(nd_table(net), nexthop, dev, false);
>>> + neigh = ipv6_neigh_create_noref(dev, nexthop);
>>> if (IS_ERR(neigh)) {
>>> IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTNOROUTES);
>>> kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
>>> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
>>> index e1cbffaa0ad0..0ed1a619372b 100644
>>> --- a/net/ipv6/ndisc.c
>>> +++ b/net/ipv6/ndisc.c
>>> @@ -947,8 +947,12 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
>>> * update / create cache entry
>>> * for the source address
>>> */
>>> - neigh = __neigh_lookup(tbl, saddr, dev,
>>> - !inc || lladdr || !dev->addr_len);
>>> + neigh = ipv6_neigh_lookup(dev, saddr);
>>> + if (!neigh && (!inc || lladdr || !dev->addr_len)) {
>>> + neigh = ipv6_neigh_create(dev, saddr);
>>> + if (IS_ERR(neigh))
>>> + neigh = NULL;
>>> + }
>>> if (neigh)
>>> ndisc_update(dev, neigh, lladdr, NUD_STALE,
>>> NEIGH_UPDATE_F_WEAK_OVERRIDE|
>>> @@ -998,7 +1002,6 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
>>> struct net *net = dev_net(dev);
>>> struct ndisc_options ndopts;
>>> struct inet6_ifaddr *ifp;
>>> - struct neigh_table *tbl;
>>> struct neighbour *neigh;
>>> struct inet6_dev *idev;
>>> u8 *lladdr = NULL;
>>> @@ -1063,8 +1066,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
>>> return reason;
>>> }
>>>
>>> - tbl = nd_table(net);
>>> - neigh = neigh_lookup(tbl, &msg->target, dev);
>>> + neigh = ipv6_neigh_lookup(dev, &msg->target);
>>>
>>> /* RFC 9131 updates original Neighbour Discovery RFC 4861.
>>> * NAs with Target LL Address option can now create a STALE neighbor
>>> @@ -1093,7 +1095,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
>>> return reason;
>>> }
>>> if (!neigh)
>>> - neigh = neigh_create(tbl, &msg->target, dev);
>>> + neigh = ipv6_neigh_create(dev, &msg->target);
>>> new_state = NUD_STALE;
>>> }
>>>
>>> @@ -1108,7 +1110,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
>>> if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
>>> READ_ONCE(net->ipv6.devconf_all->forwarding) &&
>>> READ_ONCE(net->ipv6.devconf_all->proxy_ndp) &&
>>> - pneigh_lookup(tbl, &msg->target, dev)) {
>>> + pneigh_lookup(nd_table(dev_net(dev)), &msg->target, dev)) {
>>> /* XXX: idev->cnf.proxy_ndp */
>>> goto out;
>>> }
>>> @@ -1141,7 +1143,6 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
>>> unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
>>> struct net_device *dev = skb->dev;
>>> struct ndisc_options ndopts;
>>> - struct neigh_table *tbl;
>>> struct neighbour *neigh;
>>> struct inet6_dev *idev;
>>> u8 *lladdr = NULL;
>>> @@ -1177,8 +1178,12 @@ static enum skb_drop_reason ndisc_recv_rs(struct sk_buff *skb)
>>> goto out;
>>> }
>>>
>>> - tbl = nd_table(dev_net(dev));
>>> - neigh = __neigh_lookup(tbl, saddr, dev, 1);
>>> + neigh = ipv6_neigh_lookup(dev, saddr);
>>> + if (!neigh) {
>>> + neigh = ipv6_neigh_create(dev, saddr);
>>> + if (IS_ERR(neigh))
>>> + goto out;
>>> + }
>>> if (neigh) {
>>> ndisc_update(dev, neigh, lladdr, NUD_STALE,
>>> NEIGH_UPDATE_F_WEAK_OVERRIDE|
>>> @@ -1478,9 +1483,14 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb)
>>> * Process options.
>>> */
>>>
>>> - if (!neigh)
>>> - neigh = __neigh_lookup(nd_table(net), &ipv6_hdr(skb)->saddr,
>>> - skb->dev, 1);
>>> + if (!neigh) {
>>> + neigh = ipv6_neigh_lookup(skb->dev, &ipv6_hdr(skb)->saddr);
>>> + if (!neigh) {
>>> + neigh = ipv6_neigh_create(skb->dev, &ipv6_hdr(skb)->saddr);
>>> + if (IS_ERR(neigh))
>>> + neigh = NULL;
>>> + }
>>> + }
>>> if (neigh) {
>>> u8 *lladdr = NULL;
>>> if (ndopts.nd_opts_src_lladdr) {
>>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>>> index 8baac4d85251..ea9f0a4c34f9 100644
>>> --- a/net/ipv6/route.c
>>> +++ b/net/ipv6/route.c
>>> @@ -218,7 +218,7 @@ struct neighbour *__ip6_dst_neigh_lookup(const struct in6_addr *gw,
>>> if (n)
>>> return n;
>>>
>>> - n = neigh_create(nd_table(dev_net(dev)), daddr, dev);
>>> + n = ipv6_neigh_create(dev, daddr);
>>> return IS_ERR(n) ? NULL : n;
>>> }
>>>
>>> @@ -4277,9 +4277,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
>>> */
>>> dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
>>>
>>> - neigh = __neigh_lookup(nd_table(dev_net(dev)), &msg->target, dev, 1);
>>> - if (!neigh)
>>> - return;
>>> + neigh = ipv6_neigh_lookup(dev, &msg->target);
>>> + if (!neigh) {
>>> + neigh = ipv6_neigh_create(dev, &msg->target);
>>> + if (IS_ERR(neigh))
>>> + return;
>>> + }
>>>
>>> /*
>>> * We have finally decided to accept it.
>>> diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
>>> index 409ce50cc0db..19ccf1a55988 100644
>>> --- a/net/sched/sch_teql.c
>>> +++ b/net/sched/sch_teql.c
>>> @@ -16,6 +16,7 @@
>>> #include <linux/skbuff.h>
>>> #include <linux/moduleparam.h>
>>> #include <net/dst.h>
>>> +#include <net/ndisc.h>
>>> #include <net/neighbour.h>
>>> #include <net/pkt_sched.h>
>>>
>>> @@ -257,7 +258,16 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
>>> if (dst->dev != dev) {
>>> struct neighbour *mn;
>>>
>>> - mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
>>> +#if IS_ENABLED(CONFIG_IPV6)
>>> + if (n->tbl->family == AF_INET6) {
>>> + mn = ipv6_neigh_lookup(dev, n->primary_key);
>>> + if (!mn)
>>> + mn = ipv6_neigh_create(dev, n->primary_key);
>>> + } else
>>> +#endif
>>> + {
>>> + mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
>>> + }
>>> neigh_release(n);
>>> if (IS_ERR(mn))
>>> return PTR_ERR(mn);
>>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends.
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (8 preceding siblings ...)
2026-10-03 21:23 ` [PATCH v2 net-next 9/9] neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create() Kuniyuki Iwashima
@ 2026-10-06 20:39 ` Fernando Fernandez Mancera
2026-10-07 16:35 ` Jakub Kicinski
2026-10-07 23:20 ` patchwork-bot+netdevbpf
11 siblings, 0 replies; 18+ messages in thread
From: Fernando Fernandez Mancera @ 2026-10-06 20:39 UTC (permalink / raw)
To: Kuniyuki Iwashima, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, netdev
On 10/3/26 11:23 PM, Kuniyuki Iwashima wrote:
> syzbot reported that ip6_finish_output2() could pass tbl and dev
> from different netns to neigh_create().
>
> When namespacifying neigh_table, I chose to resolve neigh_table
> in callers to minimise changes, but it turned out to be error-prone.
>
> This series adds IPv4/IPv6-specific helpers for neigh_lookup()
> and neigh_create() that always fetch the netns from dev to fix
> the problem.
>
> Along the way, the confusing and now mostly redundant helpers
> __neigh_lookup() and __neigh_lookup_errno() are converted and
> removed.
>
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Thanks!
>
> Changes:
> v2:
> * Add Patch 9
> * Patch 6 & 7: Convert __teql_resolve()
>
> v1: https://lore.kernel.org/netdev/20260930200326.718459-1-kuniyu@google.com/
>
>
> Kuniyuki Iwashima (9):
> ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup().
> ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup().
> ipv4: Add wrappers for neigh_lookup() and neigh_create().
> ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create().
> mlxsw: spectrum: Resolve neigh_table right before neigh_lookup().
> ipv6: Use ipv6_neigh_lookup() and friends.
> ipv4: Use ipv4_neigh_lookup() and friends.
> neighbour: Remove __neigh_lookup() and __neigh_lookup_errno().
> neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create().
>
> .../marvell/prestera/prestera_router.c | 14 ++--
> .../mellanox/mlx5/core/en/tc_tun_encap.c | 14 ++--
> .../mellanox/mlx5/core/en_accel/ipsec.c | 6 +-
> .../ethernet/mellanox/mlxsw/spectrum_router.c | 77 +++++++++++--------
> .../ethernet/mellanox/mlxsw/spectrum_span.c | 42 ++++++----
> .../netronome/nfp/flower/tunnel_conf.c | 8 +-
> drivers/net/ethernet/rocker/rocker_ofdpa.c | 2 +-
> drivers/net/ethernet/sfc/tc_counters.c | 11 +--
> drivers/net/vrf.c | 4 +-
> drivers/net/vxlan/vxlan_core.c | 14 +---
> include/net/arp.h | 16 ++++
> include/net/ip6_route.h | 6 +-
> include/net/ndisc.h | 31 ++++++--
> include/net/neighbour.h | 24 ------
> net/bridge/br_arp_nd_proxy.c | 4 +-
> net/core/neighbour.c | 11 ++-
> net/ieee802154/6lowpan/tx.c | 3 +-
> net/ipv4/arp.c | 26 ++++---
> net/ipv4/fib_semantics.c | 5 +-
> net/ipv4/route.c | 18 ++---
> net/ipv6/ip6_output.c | 2 +-
> net/ipv6/ndisc.c | 48 +++++++-----
> net/ipv6/route.c | 23 +++---
> net/sched/sch_teql.c | 15 +++-
> 24 files changed, 234 insertions(+), 190 deletions(-)
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends.
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (9 preceding siblings ...)
2026-10-06 20:39 ` [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Fernando Fernandez Mancera
@ 2026-10-07 16:35 ` Jakub Kicinski
2026-10-07 16:50 ` Ido Schimmel
2026-10-07 23:20 ` patchwork-bot+netdevbpf
11 siblings, 1 reply; 18+ messages in thread
From: Jakub Kicinski @ 2026-10-07 16:35 UTC (permalink / raw)
To: David Ahern, Ido Schimmel
Cc: Kuniyuki Iwashima, Andrew Lunn, David S . Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Kuniyuki Iwashima, netdev
On Sat, 3 Oct 2026 21:23:13 +0000 Kuniyuki Iwashima wrote:
> syzbot reported that ip6_finish_output2() could pass tbl and dev
> from different netns to neigh_create().
>
> When namespacifying neigh_table, I chose to resolve neigh_table
> in callers to minimise changes, but it turned out to be error-prone.
>
> This series adds IPv4/IPv6-specific helpers for neigh_lookup()
> and neigh_create() that always fetch the netns from dev to fix
> the problem.
>
> Along the way, the confusing and now mostly redundant helpers
> __neigh_lookup() and __neigh_lookup_errno() are converted and
> removed.
Ido, David, thoughts?
The unusual (for Ido) silence makes me suspicious :)
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends.
2026-10-07 16:35 ` Jakub Kicinski
@ 2026-10-07 16:50 ` Ido Schimmel
2026-10-07 18:20 ` Jakub Kicinski
0 siblings, 1 reply; 18+ messages in thread
From: Ido Schimmel @ 2026-10-07 16:50 UTC (permalink / raw)
To: Jakub Kicinski
Cc: David Ahern, Kuniyuki Iwashima, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, Kuniyuki Iwashima,
netdev
On Wed, Oct 07, 2026 at 09:35:55AM -0700, Jakub Kicinski wrote:
> On Sat, 3 Oct 2026 21:23:13 +0000 Kuniyuki Iwashima wrote:
> > syzbot reported that ip6_finish_output2() could pass tbl and dev
> > from different netns to neigh_create().
> >
> > When namespacifying neigh_table, I chose to resolve neigh_table
> > in callers to minimise changes, but it turned out to be error-prone.
> >
> > This series adds IPv4/IPv6-specific helpers for neigh_lookup()
> > and neigh_create() that always fetch the netns from dev to fix
> > the problem.
> >
> > Along the way, the confusing and now mostly redundant helpers
> > __neigh_lookup() and __neigh_lookup_errno() are converted and
> > removed.
>
> Ido, David, thoughts?
> The unusual (for Ido) silence makes me suspicious :)
Too many other patches to review...
The series looks good to me:
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends.
2026-10-07 16:50 ` Ido Schimmel
@ 2026-10-07 18:20 ` Jakub Kicinski
0 siblings, 0 replies; 18+ messages in thread
From: Jakub Kicinski @ 2026-10-07 18:20 UTC (permalink / raw)
To: Ido Schimmel
Cc: David Ahern, Kuniyuki Iwashima, Andrew Lunn, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, Kuniyuki Iwashima,
netdev
On Wed, 7 Oct 2026 19:50:00 +0300 Ido Schimmel wrote:
> > Ido, David, thoughts?
> > The unusual (for Ido) silence makes me suspicious :)
>
> Too many other patches to review...
FWIW you may be able to find some use of SUIE with the MAINTAINER
filter (funnel icon)
https://netdev-ctrl.bots.linux.dev/suie.html?delegate=netdev
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends.
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
` (10 preceding siblings ...)
2026-10-07 16:35 ` Jakub Kicinski
@ 2026-10-07 23:20 ` patchwork-bot+netdevbpf
11 siblings, 0 replies; 18+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-10-07 23:20 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, dsahern, idosch,
horms, kuni1840, netdev
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Sat, 3 Oct 2026 21:23:13 +0000 you wrote:
> syzbot reported that ip6_finish_output2() could pass tbl and dev
> from different netns to neigh_create().
>
> When namespacifying neigh_table, I chose to resolve neigh_table
> in callers to minimise changes, but it turned out to be error-prone.
>
> This series adds IPv4/IPv6-specific helpers for neigh_lookup()
> and neigh_create() that always fetch the netns from dev to fix
> the problem.
>
> [...]
Here is the summary with links:
- [v2,net-next,1/9] ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup().
https://git.kernel.org/netdev/net-next/c/07cc2b151a26
- [v2,net-next,2/9] ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup().
https://git.kernel.org/netdev/net-next/c/3e33cdcf54ee
- [v2,net-next,3/9] ipv4: Add wrappers for neigh_lookup() and neigh_create().
https://git.kernel.org/netdev/net-next/c/33ea2463c432
- [v2,net-next,4/9] ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create().
https://git.kernel.org/netdev/net-next/c/616b2143f901
- [v2,net-next,5/9] mlxsw: spectrum: Resolve neigh_table right before neigh_lookup().
https://git.kernel.org/netdev/net-next/c/98071355ffc9
- [v2,net-next,6/9] ipv6: Use ipv6_neigh_lookup() and friends.
https://git.kernel.org/netdev/net-next/c/0e59523b440c
- [v2,net-next,7/9] ipv4: Use ipv4_neigh_lookup() and friends.
https://git.kernel.org/netdev/net-next/c/f2f25d59f56a
- [v2,net-next,8/9] neighbour: Remove __neigh_lookup() and __neigh_lookup_errno().
https://git.kernel.org/netdev/net-next/c/29ff0101dc00
- [v2,net-next,9/9] neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create().
https://git.kernel.org/netdev/net-next/c/023753192e3c
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-10-07 23:20 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-03 21:23 [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 1/9] ipv4: Rename ipv4_neigh_lookup() to ipv4_dst_neigh_lookup() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 2/9] ipv6: Rename ip6_neigh_lookup() to __ip6_dst_neigh_lookup() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 3/9] ipv4: Add wrappers for neigh_lookup() and neigh_create() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 4/9] ipv6: Add wrappers for neigh_lookup() and (__)?neigh_create() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 5/9] mlxsw: spectrum: Resolve neigh_table right before neigh_lookup() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 6/9] ipv6: Use ipv6_neigh_lookup() and friends Kuniyuki Iwashima
2026-10-06 17:53 ` Fernando Fernandez Mancera
2026-10-06 18:01 ` Kuniyuki Iwashima
2026-10-06 20:34 ` Fernando Fernandez Mancera
2026-10-03 21:23 ` [PATCH v2 net-next 7/9] ipv4: Use ipv4_neigh_lookup() " Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 8/9] neighbour: Remove __neigh_lookup() and __neigh_lookup_errno() Kuniyuki Iwashima
2026-10-03 21:23 ` [PATCH v2 net-next 9/9] neighbour: Check n->parms->tbl under tbl->lock in ___neigh_create() Kuniyuki Iwashima
2026-10-06 20:39 ` [PATCH v2 net-next 0/9] neighbour: Add IPv4/IPv6-specific wrappers for neigh_lookup() and friends Fernando Fernandez Mancera
2026-10-07 16:35 ` Jakub Kicinski
2026-10-07 16:50 ` Ido Schimmel
2026-10-07 18:20 ` Jakub Kicinski
2026-10-07 23:20 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox