> -----Original Message-----
> From: Danielle Ratson <[email protected]>
> Sent: Wednesday, 29 April 2026 9:24
> To: [email protected]
> Cc: [email protected]; Ido Schimmel <[email protected]>;
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; [email protected]; linux-
> [email protected]; Danielle Ratson <[email protected]>
> 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 <[email protected]>
> Signed-off-by: Danielle Ratson <[email protected]>
> ---
>  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.

Reply via email to