mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'bridge-do-not-suppress-arp-probes-and-dad-ns-unconditionally'
Danielle Ratson says: ==================== bridge: Do not suppress ARP probes and DAD NS unconditionally 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. ==================== Link: https://patch.msgid.link/20260429062405.1386417-1-danieller@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
4eb407d9da
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user