RE: [PATCH net-next 1/2] bridge: Do not suppress ARP probes and DAD NS unconditionally
Danielle Ratson <[email protected]> Thu, 30 Apr 2026 10:33:38 +0000
| Newsgroups | dev.linux.lists.bridge,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kernel.vger.netdev |
|---|---|
| Message-ID | <DM6PR12MB451618D785F300F4B78F742AD8352@DM6PR12MB4516.namprd12.prod.outlook.com> |
> -----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.