public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
@ 2026-04-29  6:24 Danielle Ratson
  2026-04-29  6:24 ` [PATCH net-next 1/2] " Danielle Ratson
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-04-29  6:24 UTC (permalink / raw)
  To: netdev
  Cc: razor, idosch, davem, edumazet, kuba, pabeni, horms, shuah,
	bridge, linux-kernel, linux-kselftest, Danielle Ratson

When using bridge neighbor suppression in EVPN deployments, Duplicate
Address Detection (DAD) is currently broken for both IPv4 (ARP probes)
and IPv6 (DAD Neighbor Solicitations). This prevents proper address
conflict detection across the VXLAN fabric.

The neighbor suppression feature allows the bridge to reply to ARP/NS
messages on behalf of remote hosts when FDB and neighbor entries exist,
suppressing unnecessary flooding over the VXLAN overlay. However, the
current implementation unconditionally suppresses ARP probes and DAD NS,
which breaks DAD.

For DAD to work correctly:
- When the bridge doesn't know the answer:
  flood the probe/DAD packet to allow remote VTEPs to respond.
- When the bridge knows the answer:
  reply to indicate the address is in use.

This series fixes the issue by adjusting the early suppression checks to
exclude ARP probes and DAD NS from unconditional suppression, allowing
them to reach the normal FDB lookup path. Gratuitous ARP and IPv6
unsolicited-NA messages are still suppressed unconditionally as before.

Patchset overview:
Patch #1: Fixes the unconditional suppression.
Patch #2: Adds selftests.

Danielle Ratson (2):
  bridge: Do not suppress ARP probes and DAD NS unconditionally
  selftests: net: Add tests for ARP probe and DAD NS handling

 net/bridge/br_arp_nd_proxy.c                  |  16 ++-
 .../net/test_bridge_neigh_suppress.sh         | 126 ++++++++++++++++++
 2 files changed, 137 insertions(+), 5 deletions(-)

-- 
2.51.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net-next 1/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
  2026-04-29  6:24 [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally Danielle Ratson
@ 2026-04-29  6:24 ` Danielle Ratson
  2026-04-29  9:04   ` Nikolay Aleksandrov
  2026-04-30 10:33   ` Danielle Ratson
  2026-04-29  6:24 ` [PATCH net-next 2/2] selftests: net: Add tests for ARP probe and DAD NS handling Danielle Ratson
  2026-05-01  1:10 ` [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally patchwork-bot+netdevbpf
  2 siblings, 2 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-04-29  6:24 UTC (permalink / raw)
  To: netdev
  Cc: razor, idosch, davem, edumazet, kuba, pabeni, horms, shuah,
	bridge, linux-kernel, linux-kselftest, Danielle Ratson

When neighbor suppression is enabled on a VXLAN port, the bridge is
expected to reply to ARP/NS messages on behalf of remote hosts when both
FDB and neighbor entries exist. This allows the bridge to suppress
flooding of these messages to the VXLAN overlay.

According to RFC 9161 ("Operational Aspects of Proxy ARP/ND in Ethernet
Virtual Private Networks"):
"A PE SHOULD reply to broadcast/multicast address resolution messages,
i.e., ARP Requests, ARP probes, NS messages, as well as DAD NS messages.
An ARP probe is an ARP Request constructed with an all-zero sender IP
address that may be used by hosts for IPv4 Address Conflict Detection as
specified in [RFC5227]".

However, the current implementation unconditionally suppresses ARP probes
and DAD Neighbor Solicitations, which breaks Duplicate Address Detection
(DAD) over EVPN.

For DAD to work correctly over the VXLAN fabric:
- When the bridge does not know the answer:
  flood the probe/DAD packet to allow remote VTEPs to respond.
- When the bridge knows the answer:
  reply to indicate the address is in use.

Fix by adjusting the early suppression checks to exclude ARP probes and
DAD NS from unconditional suppression.

When replying to a DAD NS, br_nd_send() is adjusted to set the NA
destination to the all-nodes multicast address (ff02::1) and clear the
Solicited flag, in accordance with RFC 4861 section 7.2.4.

Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
 net/bridge/br_arp_nd_proxy.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
index deb1ab1f24b0..3205346f298c 100644
--- a/net/bridge/br_arp_nd_proxy.c
+++ b/net/bridge/br_arp_nd_proxy.c
@@ -164,7 +164,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
 			return;
 		if (parp->ar_op != htons(ARPOP_RREQUEST) &&
 		    parp->ar_op != htons(ARPOP_RREPLY) &&
-		    (ipv4_is_zeronet(sip) || sip == tip)) {
+		    sip == tip) {
 			/* prevent flooding to neigh suppress ports */
 			BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
 			return;
@@ -262,6 +262,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
 	int ns_olen;
 	int i, len;
 	u8 *daddr;
+	bool dad;
 	u16 pvid;
 
 	if (!dev || skb_linearize(request))
@@ -300,8 +301,13 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
 		}
 	}
 
+	dad = ipv6_addr_any(&ipv6_hdr(request)->saddr);
+
 	/* Ethernet header */
-	ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
+	if (dad)
+		ipv6_eth_mc_map(&in6addr_linklocal_allnodes, eth_hdr(reply)->h_dest);
+	else
+		ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
 	ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
 	eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
 	reply->protocol = htons(ETH_P_IPV6);
@@ -317,7 +323,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
 	pip6->priority = ipv6_hdr(request)->priority;
 	pip6->nexthdr = IPPROTO_ICMPV6;
 	pip6->hop_limit = 255;
-	pip6->daddr = ipv6_hdr(request)->saddr;
+	pip6->daddr = dad ? in6addr_linklocal_allnodes : ipv6_hdr(request)->saddr;
 	pip6->saddr = *(struct in6_addr *)n->primary_key;
 
 	skb_pull(reply, sizeof(struct ipv6hdr));
@@ -330,7 +336,7 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
 	na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
 	na->icmph.icmp6_router = (n->flags & NTF_ROUTER) ? 1 : 0;
 	na->icmph.icmp6_override = 1;
-	na->icmph.icmp6_solicited = 1;
+	na->icmph.icmp6_solicited = dad ? 0 : 1;
 	na->target = ns->target;
 	ether_addr_copy(&na->opt[2], n->ha);
 	na->opt[0] = ND_OPT_TARGET_LL_ADDR;
@@ -435,7 +441,7 @@ void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
 	saddr = &iphdr->saddr;
 	daddr = &iphdr->daddr;
 
-	if (ipv6_addr_any(saddr) || !ipv6_addr_cmp(saddr, daddr)) {
+	if (!ipv6_addr_cmp(saddr, daddr)) {
 		/* prevent flooding to neigh suppress ports */
 		BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
 		return;
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net-next 2/2] selftests: net: Add tests for ARP probe and DAD NS handling
  2026-04-29  6:24 [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally Danielle Ratson
  2026-04-29  6:24 ` [PATCH net-next 1/2] " Danielle Ratson
@ 2026-04-29  6:24 ` Danielle Ratson
  2026-04-29  9:04   ` Nikolay Aleksandrov
  2026-05-01  1:10 ` [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally patchwork-bot+netdevbpf
  2 siblings, 1 reply; 7+ messages in thread
From: Danielle Ratson @ 2026-04-29  6:24 UTC (permalink / raw)
  To: netdev
  Cc: razor, idosch, davem, edumazet, kuba, pabeni, horms, shuah,
	bridge, linux-kernel, linux-kselftest, Danielle Ratson

Add test cases to verify that ARP probes and DAD Neighbor Solicitations
are handled correctly by the bridge neighbor suppression feature.

When neighbor suppression is enabled on a bridge VXLAN port, the bridge
should reply to ARP/NS messages on behalf of remote hosts when both FDB
and neighbor entries exist, and the answer is known. However, when
either the FDB or the neighbor exists, ARP probes / DAD NS should be
treated like regular ARP requests / NS and flood to VXLAN.

Add two new test functions:

neigh_suppress_arp_probe(): Tests ARP probe handling by triggering
duplicate address detection using arping -D. Verifies that probes are
flooded when the bridge doesn't know the answer, and suppressed when FDB
and neighbor entries exist.

neigh_suppress_dad_ns(): Tests DAD NS handling by constructing DAD NS
packets using mausezahn and verifies correct flooding/suppression
behavior.

Before the previous patch:

$ ./test_bridge_neigh_suppress.sh -t "neigh_suppress_arp_probe neigh_suppress_dad_ns"

Per-port ARP probe suppression
------------------------------
TEST: ARP probe suppression                                         [ OK ]
TEST: "neigh_suppress" is on                                        [ OK ]
TEST: ARP probe suppression                                         [FAIL]
TEST: FDB and neighbor entry installation                           [ OK ]
TEST: arping                                                        [FAIL]
TEST: ARP probe suppression                                         [FAIL]
TEST: neighbor removal                                              [ OK ]
TEST: ARP probe suppression                                         [FAIL]
TEST: "neigh_suppress" is off                                       [ OK ]
TEST: ARP probe suppression                                         [FAIL]

Per-port DAD NS suppression
---------------------------
TEST: DAD NS suppression                                            [ OK ]
TEST: "neigh_suppress" is on                                        [ OK ]
TEST: DAD NS suppression                                            [FAIL]
TEST: FDB and neighbor entry installation                           [ OK ]
TEST: DAD NS suppression                                            [FAIL]
TEST: neighbor removal                                              [ OK ]
TEST: DAD NS suppression                                            [FAIL]
TEST: DAD NS proxy NA reply                                         [FAIL]
TEST: "neigh_suppress" is off                                       [ OK ]
TEST: DAD NS suppression                                            [FAIL]

Tests passed:   10
Tests failed:   10

After the previous patch:

$ ./test_bridge_neigh_suppress.sh -t "neigh_suppress_arp_probe neigh_suppress_dad_ns"

Per-port ARP probe suppression
------------------------------
TEST: ARP probe suppression                                         [ OK ]
TEST: "neigh_suppress" is on                                        [ OK ]
TEST: ARP probe suppression                                         [ OK ]
TEST: FDB and neighbor entry installation                           [ OK ]
TEST: arping                                                        [ OK ]
TEST: ARP probe suppression                                         [ OK ]
TEST: neighbor removal                                              [ OK ]
TEST: ARP probe suppression                                         [ OK ]
TEST: "neigh_suppress" is off                                       [ OK ]
TEST: ARP probe suppression                                         [ OK ]

Per-port DAD NS suppression
---------------------------
TEST: DAD NS suppression                                            [ OK ]
TEST: "neigh_suppress" is on                                        [ OK ]
TEST: DAD NS suppression                                            [ OK ]
TEST: FDB and neighbor entry installation                           [ OK ]
TEST: DAD NS suppression                                            [ OK ]
TEST: neighbor removal                                              [ OK ]
TEST: DAD NS suppression                                            [ OK ]
TEST: DAD NS proxy NA reply                                         [ OK ]
TEST: "neigh_suppress" is off                                       [ OK ]
TEST: DAD NS suppression                                            [ OK ]

Tests passed:  20
Tests failed:   0

Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
 .../net/test_bridge_neigh_suppress.sh         | 126 ++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/tools/testing/selftests/net/test_bridge_neigh_suppress.sh b/tools/testing/selftests/net/test_bridge_neigh_suppress.sh
index 9067197c9055..4bc92078e173 100755
--- a/tools/testing/selftests/net/test_bridge_neigh_suppress.sh
+++ b/tools/testing/selftests/net/test_bridge_neigh_suppress.sh
@@ -56,6 +56,8 @@ TESTS="
 	neigh_suppress_uc_ns
 	neigh_vlan_suppress_arp
 	neigh_vlan_suppress_ns
+	neigh_suppress_arp_probe
+	neigh_suppress_dad_ns
 "
 VERBOSE=0
 PAUSE_ON_FAIL=no
@@ -875,6 +877,130 @@ neigh_vlan_suppress_ns()
 	log_test $? 0 "NS suppression (VLAN $vid2)"
 }
 
+neigh_suppress_arp_probe()
+{
+	local vid=10
+	local tip=192.0.2.2
+	local h2_mac
+
+	echo
+	echo "Per-port ARP probe suppression"
+	echo "------------------------------"
+
+	run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+	run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto 0x0806 flower indev swp1 arp_tip $tip arp_sip 0.0.0.0 arp_op request action pass"
+
+	# Initial state - check that ARP probes are not suppressed.
+	run_cmd "ip netns exec $h1 arping -D -q -c 1 -w 5 -I eth0.$vid $tip"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 1
+	log_test $? 0 "ARP probe suppression"
+
+	# Enable neighbor suppression and check that nothing changes.
+	run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+	run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+	log_test $? 0 "\"neigh_suppress\" is on"
+
+	run_cmd "ip netns exec $h1 arping -D -q -c 1 -w 5 -I eth0.$vid $tip"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 2
+	log_test $? 0 "ARP probe suppression"
+
+	# Install FDB and a neighbor and check that ARP probes are suppressed.
+	h2_mac=$(ip -n "$h2" -j -p link show eth0."$vid" | jq -r '.[]["address"]')
+	run_cmd "bridge -n $sw1 fdb replace $h2_mac dev vx0 master static vlan $vid"
+	run_cmd "ip -n $sw1 neigh replace $tip lladdr $h2_mac nud permanent dev br0.$vid"
+	log_test $? 0 "FDB and neighbor entry installation"
+
+	run_cmd "ip netns exec $h1 arping -D -q -c 1 -w 5 -I eth0.$vid $tip"
+	log_test $? 1 "arping"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 2
+	log_test $? 0 "ARP probe suppression"
+
+	# Remove the neighbor entry and check that ARP probes are not suppressed.
+	run_cmd "ip -n $sw1 neigh del $tip dev br0.$vid"
+	log_test $? 0 "neighbor removal"
+
+	run_cmd "ip netns exec $h1 arping -D -q -c 1 -w 5 -I eth0.$vid $tip"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 3
+	log_test $? 0 "ARP probe suppression"
+
+	# Disable neighbor suppression.
+	run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off"
+	run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
+	log_test $? 0 "\"neigh_suppress\" is off"
+
+	run_cmd "ip netns exec $h1 arping -D -q -c 1 -w 5 -I eth0.$vid $tip"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 4
+	log_test $? 0 "ARP probe suppression"
+}
+
+neigh_suppress_dad_ns()
+{
+	local vid=10
+	local tip=2001:db8:1::99
+	local mcast=ff02::1:ff00:99
+	local dmac=33:33:ff:00:00:99
+	local full_tip=20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:99
+	local csum="4b:bc"
+	local smac
+	local tmac
+
+	echo
+	echo "Per-port DAD NS suppression"
+	echo "---------------------------"
+
+	smac=$(ip -n "$h1" -j -p link show eth0."$vid" | jq -r '.[]["address"]')
+
+	run_cmd "tc -n $sw1 qdisc replace dev vx0 clsact"
+	run_cmd "tc -n $sw1 filter replace dev vx0 egress pref 1 handle 101 proto ipv6 flower indev swp1 ip_proto icmpv6 dst_ip $mcast src_ip :: type 135 code 0 action pass"
+
+	# Initial state - check that DAD NS are not suppressed.
+	run_cmd "ip netns exec $h1 mausezahn -6 eth0.$vid -c 1 -a $smac -b $dmac -A :: -B $mcast -t ip hop=255,next=58,payload=$(icmpv6_header_get "$csum" "$full_tip") -q"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 1
+	log_test $? 0 "DAD NS suppression"
+
+	# Enable neighbor suppression and check that nothing changes.
+	run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress on"
+	run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress on\""
+	log_test $? 0 "\"neigh_suppress\" is on"
+
+	run_cmd "ip netns exec $h1 mausezahn -6 eth0.$vid -c 1 -a $smac -b $dmac -A :: -B $mcast -t ip hop=255,next=58,payload=$(icmpv6_header_get "$csum" "$full_tip") -q"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 2
+	log_test $? 0 "DAD NS suppression"
+
+	# Install FDB and a neighbor and check that DAD NS are suppressed
+	# and that a proxy NA is sent back to h1.
+	tmac=$(ip -n "$h2" -j -p link show eth0."$vid" | jq -r '.[]["address"]')
+	run_cmd "bridge -n $sw1 fdb replace $tmac dev vx0 master static vlan $vid"
+	run_cmd "ip -n $sw1 -6 neigh replace $tip lladdr $tmac nud permanent dev br0.$vid"
+	log_test $? 0 "FDB and neighbor entry installation"
+
+	run_cmd "tc -n $h1 qdisc replace dev eth0.$vid clsact"
+	run_cmd "tc -n $h1 filter replace dev eth0.$vid ingress pref 1 handle 101 proto ipv6 flower ip_proto icmpv6 dst_ip ff02::1 src_ip $tip type 136 code 0 action pass"
+
+	run_cmd "ip netns exec $h1 mausezahn -6 eth0.$vid -c 1 -a $smac -b $dmac -A :: -B $mcast -t ip hop=255,next=58,payload=$(icmpv6_header_get "$csum" "$full_tip") -q"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 2
+	log_test $? 0 "DAD NS suppression"
+	tc_check_packets "$h1" "dev eth0.$vid ingress" 101 1
+	log_test $? 0 "DAD NS proxy NA reply"
+
+	# Remove the neighbor entry and check that DAD NS are not suppressed.
+	run_cmd "ip -n $sw1 -6 neigh del $tip dev br0.$vid"
+	log_test $? 0 "neighbor removal"
+
+	run_cmd "ip netns exec $h1 mausezahn -6 eth0.$vid -c 1 -a $smac -b $dmac -A :: -B $mcast -t ip hop=255,next=58,payload=$(icmpv6_header_get "$csum" "$full_tip") -q"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 3
+	log_test $? 0 "DAD NS suppression"
+
+	# Disable neighbor suppression.
+	run_cmd "bridge -n $sw1 link set dev vx0 neigh_suppress off"
+	run_cmd "bridge -n $sw1 -d link show dev vx0 | grep \"neigh_suppress off\""
+	log_test $? 0 "\"neigh_suppress\" is off"
+
+	run_cmd "ip netns exec $h1 mausezahn -6 eth0.$vid -c 1 -a $smac -b $dmac -A :: -B $mcast -t ip hop=255,next=58,payload=$(icmpv6_header_get "$csum" "$full_tip") -q"
+	tc_check_packets "$sw1" "dev vx0 egress" 101 4
+	log_test $? 0 "DAD NS suppression"
+}
+
 ################################################################################
 # Usage
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 1/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
  2026-04-29  6:24 ` [PATCH net-next 1/2] " Danielle Ratson
@ 2026-04-29  9:04   ` Nikolay Aleksandrov
  2026-04-30 10:33   ` Danielle Ratson
  1 sibling, 0 replies; 7+ messages in thread
From: Nikolay Aleksandrov @ 2026-04-29  9:04 UTC (permalink / raw)
  To: Danielle Ratson, netdev
  Cc: idosch, davem, edumazet, kuba, pabeni, horms, shuah, bridge,
	linux-kernel, linux-kselftest

On 29/04/2026 09:24, Danielle Ratson wrote:
> When neighbor suppression is enabled on a VXLAN port, the bridge is
> expected to reply to ARP/NS messages on behalf of remote hosts when both
> FDB and neighbor entries exist. This allows the bridge to suppress
> flooding of these messages to the VXLAN overlay.
> 
> According to RFC 9161 ("Operational Aspects of Proxy ARP/ND in Ethernet
> Virtual Private Networks"):
> "A PE SHOULD reply to broadcast/multicast address resolution messages,
> i.e., ARP Requests, ARP probes, NS messages, as well as DAD NS messages.
> An ARP probe is an ARP Request constructed with an all-zero sender IP
> address that may be used by hosts for IPv4 Address Conflict Detection as
> specified in [RFC5227]".
> 
> However, the current implementation unconditionally suppresses ARP probes
> and DAD Neighbor Solicitations, which breaks Duplicate Address Detection
> (DAD) over EVPN.
> 
> For DAD to work correctly over the VXLAN fabric:
> - When the bridge does not know the answer:
>    flood the probe/DAD packet to allow remote VTEPs to respond.
> - When the bridge knows the answer:
>    reply to indicate the address is in use.
> 
> Fix by adjusting the early suppression checks to exclude ARP probes and
> DAD NS from unconditional suppression.
> 
> When replying to a DAD NS, br_nd_send() is adjusted to set the NA
> destination to the all-nodes multicast address (ff02::1) and clear the
> Solicited flag, in accordance with RFC 4861 section 7.2.4.
> 
> Reviewed-by: Ido Schimmel <idosch@nvidia.com>
> Signed-off-by: Danielle Ratson <danieller@nvidia.com>
> ---
>   net/bridge/br_arp_nd_proxy.c | 16 +++++++++++-----
>   1 file changed, 11 insertions(+), 5 deletions(-)
> 

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 2/2] selftests: net: Add tests for ARP probe and DAD NS handling
  2026-04-29  6:24 ` [PATCH net-next 2/2] selftests: net: Add tests for ARP probe and DAD NS handling Danielle Ratson
@ 2026-04-29  9:04   ` Nikolay Aleksandrov
  0 siblings, 0 replies; 7+ messages in thread
From: Nikolay Aleksandrov @ 2026-04-29  9:04 UTC (permalink / raw)
  To: Danielle Ratson, netdev
  Cc: idosch, davem, edumazet, kuba, pabeni, horms, shuah, bridge,
	linux-kernel, linux-kselftest

On 29/04/2026 09:24, Danielle Ratson wrote:
> Add test cases to verify that ARP probes and DAD Neighbor Solicitations
> are handled correctly by the bridge neighbor suppression feature.
> 
> When neighbor suppression is enabled on a bridge VXLAN port, the bridge
> should reply to ARP/NS messages on behalf of remote hosts when both FDB
> and neighbor entries exist, and the answer is known. However, when
> either the FDB or the neighbor exists, ARP probes / DAD NS should be
> treated like regular ARP requests / NS and flood to VXLAN.
> 
> Add two new test functions:
> 
> neigh_suppress_arp_probe(): Tests ARP probe handling by triggering
> duplicate address detection using arping -D. Verifies that probes are
> flooded when the bridge doesn't know the answer, and suppressed when FDB
> and neighbor entries exist.
> 
> neigh_suppress_dad_ns(): Tests DAD NS handling by constructing DAD NS
> packets using mausezahn and verifies correct flooding/suppression
> behavior.
> 
> Before the previous patch:
> 
> $ ./test_bridge_neigh_suppress.sh -t "neigh_suppress_arp_probe neigh_suppress_dad_ns"
> 
> Per-port ARP probe suppression
> ------------------------------
> TEST: ARP probe suppression                                         [ OK ]
> TEST: "neigh_suppress" is on                                        [ OK ]
> TEST: ARP probe suppression                                         [FAIL]
> TEST: FDB and neighbor entry installation                           [ OK ]
> TEST: arping                                                        [FAIL]
> TEST: ARP probe suppression                                         [FAIL]
> TEST: neighbor removal                                              [ OK ]
> TEST: ARP probe suppression                                         [FAIL]
> TEST: "neigh_suppress" is off                                       [ OK ]
> TEST: ARP probe suppression                                         [FAIL]
> 
> Per-port DAD NS suppression
> ---------------------------
> TEST: DAD NS suppression                                            [ OK ]
> TEST: "neigh_suppress" is on                                        [ OK ]
> TEST: DAD NS suppression                                            [FAIL]
> TEST: FDB and neighbor entry installation                           [ OK ]
> TEST: DAD NS suppression                                            [FAIL]
> TEST: neighbor removal                                              [ OK ]
> TEST: DAD NS suppression                                            [FAIL]
> TEST: DAD NS proxy NA reply                                         [FAIL]
> TEST: "neigh_suppress" is off                                       [ OK ]
> TEST: DAD NS suppression                                            [FAIL]
> 
> Tests passed:   10
> Tests failed:   10
> 
> After the previous patch:
> 
> $ ./test_bridge_neigh_suppress.sh -t "neigh_suppress_arp_probe neigh_suppress_dad_ns"
> 
> Per-port ARP probe suppression
> ------------------------------
> TEST: ARP probe suppression                                         [ OK ]
> TEST: "neigh_suppress" is on                                        [ OK ]
> TEST: ARP probe suppression                                         [ OK ]
> TEST: FDB and neighbor entry installation                           [ OK ]
> TEST: arping                                                        [ OK ]
> TEST: ARP probe suppression                                         [ OK ]
> TEST: neighbor removal                                              [ OK ]
> TEST: ARP probe suppression                                         [ OK ]
> TEST: "neigh_suppress" is off                                       [ OK ]
> TEST: ARP probe suppression                                         [ OK ]
> 
> Per-port DAD NS suppression
> ---------------------------
> TEST: DAD NS suppression                                            [ OK ]
> TEST: "neigh_suppress" is on                                        [ OK ]
> TEST: DAD NS suppression                                            [ OK ]
> TEST: FDB and neighbor entry installation                           [ OK ]
> TEST: DAD NS suppression                                            [ OK ]
> TEST: neighbor removal                                              [ OK ]
> TEST: DAD NS suppression                                            [ OK ]
> TEST: DAD NS proxy NA reply                                         [ OK ]
> TEST: "neigh_suppress" is off                                       [ OK ]
> TEST: DAD NS suppression                                            [ OK ]
> 
> Tests passed:  20
> Tests failed:   0
> 
> Signed-off-by: Danielle Ratson <danieller@nvidia.com>
> ---
>   .../net/test_bridge_neigh_suppress.sh         | 126 ++++++++++++++++++
>   1 file changed, 126 insertions(+)
> 

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH net-next 1/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
  2026-04-29  6:24 ` [PATCH net-next 1/2] " Danielle Ratson
  2026-04-29  9:04   ` Nikolay Aleksandrov
@ 2026-04-30 10:33   ` Danielle Ratson
  1 sibling, 0 replies; 7+ messages in thread
From: Danielle Ratson @ 2026-04-30 10:33 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: razor@blackwall.org, Ido Schimmel, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org, shuah@kernel.org, bridge@lists.linux.dev,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org

> -----Original Message-----
> From: Danielle Ratson <danieller@nvidia.com>
> Sent: Wednesday, 29 April 2026 9:24
> To: netdev@vger.kernel.org
> Cc: razor@blackwall.org; Ido Schimmel <idosch@nvidia.com>;
> davem@davemloft.net; edumazet@google.com; kuba@kernel.org;
> pabeni@redhat.com; horms@kernel.org; shuah@kernel.org;
> bridge@lists.linux.dev; linux-kernel@vger.kernel.org; linux-
> kselftest@vger.kernel.org; Danielle Ratson <danieller@nvidia.com>
> Subject: [PATCH net-next 1/2] bridge: Do not suppress ARP probes and DAD
> NS unconditionally
> 
> When neighbor suppression is enabled on a VXLAN port, the bridge is
> expected to reply to ARP/NS messages on behalf of remote hosts when both
> FDB and neighbor entries exist. This allows the bridge to suppress flooding of
> these messages to the VXLAN overlay.
> 
> According to RFC 9161 ("Operational Aspects of Proxy ARP/ND in Ethernet
> Virtual Private Networks"):
> "A PE SHOULD reply to broadcast/multicast address resolution messages, i.e.,
> ARP Requests, ARP probes, NS messages, as well as DAD NS messages.
> An ARP probe is an ARP Request constructed with an all-zero sender IP
> address that may be used by hosts for IPv4 Address Conflict Detection as
> specified in [RFC5227]".
> 
> However, the current implementation unconditionally suppresses ARP probes
> and DAD Neighbor Solicitations, which breaks Duplicate Address Detection
> (DAD) over EVPN.
> 
> For DAD to work correctly over the VXLAN fabric:
> - When the bridge does not know the answer:
>   flood the probe/DAD packet to allow remote VTEPs to respond.
> - When the bridge knows the answer:
>   reply to indicate the address is in use.
> 
> Fix by adjusting the early suppression checks to exclude ARP probes and DAD
> NS from unconditional suppression.
> 
> When replying to a DAD NS, br_nd_send() is adjusted to set the NA destination
> to the all-nodes multicast address (ff02::1) and clear the Solicited flag, in
> accordance with RFC 4861 section 7.2.4.
> 
> Reviewed-by: Ido Schimmel <idosch@nvidia.com>
> Signed-off-by: Danielle Ratson <danieller@nvidia.com>
> ---
>  net/bridge/br_arp_nd_proxy.c | 16 +++++++++++-----
>  1 file changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
> index deb1ab1f24b0..3205346f298c 100644
> --- a/net/bridge/br_arp_nd_proxy.c
> +++ b/net/bridge/br_arp_nd_proxy.c
> @@ -164,7 +164,7 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb,
> struct net_bridge *br,
>  			return;
>  		if (parp->ar_op != htons(ARPOP_RREQUEST) &&
>  		    parp->ar_op != htons(ARPOP_RREPLY) &&
> -		    (ipv4_is_zeronet(sip) || sip == tip)) {
> +		    sip == tip) {
>  			/* prevent flooding to neigh suppress ports */
>  			BR_INPUT_SKB_CB(skb)->proxyarp_replied = 1;
>  			return;
> @@ -262,6 +262,7 @@ static void br_nd_send(struct net_bridge *br, struct
> net_bridge_port *p,
>  	int ns_olen;
>  	int i, len;
>  	u8 *daddr;
> +	bool dad;
>  	u16 pvid;
> 
>  	if (!dev || skb_linearize(request))
> @@ -300,8 +301,13 @@ static void br_nd_send(struct net_bridge *br, struct
> net_bridge_port *p,
>  		}
>  	}
> 
> +	dad = ipv6_addr_any(&ipv6_hdr(request)->saddr);
> +
>  	/* Ethernet header */
> -	ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
> +	if (dad)
> +		ipv6_eth_mc_map(&in6addr_linklocal_allnodes,
> eth_hdr(reply)->h_dest);
> +	else
> +		ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
>  	ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
>  	eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
>  	reply->protocol = htons(ETH_P_IPV6);
> @@ -317,7 +323,7 @@ static void br_nd_send(struct net_bridge *br, struct
> net_bridge_port *p,
>  	pip6->priority = ipv6_hdr(request)->priority;
>  	pip6->nexthdr = IPPROTO_ICMPV6;
>  	pip6->hop_limit = 255;
> -	pip6->daddr = ipv6_hdr(request)->saddr;
> +	pip6->daddr = dad ? in6addr_linklocal_allnodes :
> +ipv6_hdr(request)->saddr;
>  	pip6->saddr = *(struct in6_addr *)n->primary_key;
> 
>  	skb_pull(reply, sizeof(struct ipv6hdr)); @@ -330,7 +336,7 @@ static
> void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
>  	na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
>  	na->icmph.icmp6_router = (n->flags & NTF_ROUTER) ? 1 : 0;
>  	na->icmph.icmp6_override = 1;
> -	na->icmph.icmp6_solicited = 1;
> +	na->icmph.icmp6_solicited = dad ? 0 : 1;

Hi, 

Sashiko wrote:
> Should the override flag also be conditionally cleared when responding to a
> DAD solicitation?
> According to RFC 4861 section 7.2.4, the Override flag should not be set
> when responding to DAD solicitations (where the source address is
> unspecified).

The NA sent in response to a DAD NS is an unsolicited advertisement- the Solicited flag is explicitly cleared for this case:

na->icmph.icmp6_solicited = dad ? 0 : 1;

RFC 4861 section 4.4 defines when the Override flag should be set:

"It SHOULD NOT be set in solicited advertisements for anycast addresses and in solicited proxy advertisements. It SHOULD be set in other solicited advertisements and in unsolicited advertisements."

Since a DAD response is an unsolicited advertisement, Override SHOULD be set, so leaving icmp6_override = 1 unconditionally is correct.

This is also consistent with how the Linux host stack behaves. A regular Linux host responding to a DAD probe sends:

12:08:13.391138 5e:79:d1:22:89:61 > 33:33:ff:00:00:02, ethertype IPv6 (0x86dd), length 86: (hlim 255, next-header ICMPv6 (58), payload length 32) :: > ff02::1:ff00:2: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has 2001:db8:1::2
                unknown option (14), length 8 (1):
                  0x0000:  d73f 45b7 5343
12:08:13.392867 76:93:dd:a0:c7:7d > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 86: (hlim 255, next-header ICMPv6 (58), payload length 32) 2001:db8:1::2 > ff02::1: [icmp6 sum ok] ICMP6, neighbor advertisement, length 32, tgt is 2001:db8:1::2, Flags [override]
                destination link-address option (2), length 8 (1): 76:93:dd:a0:c7:7d
                  0x0000:  7693 dda0 c77d

The NA has Override set but no Solicited flag, consistent with RFC 4861 section 4.4.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
  2026-04-29  6:24 [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally Danielle Ratson
  2026-04-29  6:24 ` [PATCH net-next 1/2] " Danielle Ratson
  2026-04-29  6:24 ` [PATCH net-next 2/2] selftests: net: Add tests for ARP probe and DAD NS handling Danielle Ratson
@ 2026-05-01  1:10 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-05-01  1:10 UTC (permalink / raw)
  To: Danielle Ratson
  Cc: netdev, razor, idosch, davem, edumazet, kuba, pabeni, horms,
	shuah, bridge, linux-kernel, linux-kselftest

Hello:

This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Wed, 29 Apr 2026 09:24:03 +0300 you wrote:
> When using bridge neighbor suppression in EVPN deployments, Duplicate
> Address Detection (DAD) is currently broken for both IPv4 (ARP probes)
> and IPv6 (DAD Neighbor Solicitations). This prevents proper address
> conflict detection across the VXLAN fabric.
> 
> The neighbor suppression feature allows the bridge to reply to ARP/NS
> messages on behalf of remote hosts when FDB and neighbor entries exist,
> suppressing unnecessary flooding over the VXLAN overlay. However, the
> current implementation unconditionally suppresses ARP probes and DAD NS,
> which breaks DAD.
> 
> [...]

Here is the summary with links:
  - [net-next,1/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
    https://git.kernel.org/netdev/net-next/c/fee1fc1d5a54
  - [net-next,2/2] selftests: net: Add tests for ARP probe and DAD NS handling
    https://git.kernel.org/netdev/net-next/c/a3f88d89f698

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] 7+ messages in thread

end of thread, other threads:[~2026-05-01  1:10 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29  6:24 [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally Danielle Ratson
2026-04-29  6:24 ` [PATCH net-next 1/2] " Danielle Ratson
2026-04-29  9:04   ` Nikolay Aleksandrov
2026-04-30 10:33   ` Danielle Ratson
2026-04-29  6:24 ` [PATCH net-next 2/2] selftests: net: Add tests for ARP probe and DAD NS handling Danielle Ratson
2026-04-29  9:04   ` Nikolay Aleksandrov
2026-05-01  1:10 ` [PATCH net-next 0/2] bridge: Do not suppress ARP probes and DAD NS unconditionally 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