Skip to content

Commit

Permalink
northd: Add logical flow to skip GARP with LLA
Browse files Browse the repository at this point in the history
Skip GARP packet with link-local (ip6.dst == ff00::/8)
address being advertised when "always_learn_from_arp_request=false",
this should prevent huge grow of MAC Binding table. To keep the option
consistent overwrite the previous MAC with LLA if it was
already stored in DB.

Reported-at: https://bugzilla.redhat.com/2211240
Signed-off-by: Ales Musil <amusil@redhat.com>
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
  • Loading branch information
almusil authored and dceara committed Jun 8, 2023
1 parent 45b82f1 commit 5e0cb03
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 26 deletions.
18 changes: 18 additions & 0 deletions northd/northd.c
Original file line number Diff line number Diff line change
Expand Up @@ -12448,6 +12448,24 @@ build_neigh_learning_flows_for_lrouter(
ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na",
ds_cstr(actions));

if (!learn_from_arp_request) {
/* Add flow to skip GARP LLA if we don't know it already.
* From RFC 2461, section 4.4, Neighbor Advertisement Message
* Format, the Destination Address should be:
* For solicited advertisements, the Source Address of
* an invoking Neighbor Solicitation or, if the
* solicitation's Source Address is the unspecified
* address, the all-nodes multicast address. */
ds_clear(actions);
ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT
" = lookup_nd(inport, ip6.src, nd.tll); "
REGBIT_LOOKUP_NEIGHBOR_IP_RESULT
" = lookup_nd_ip(inport, ip6.src); next;");
ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 110,
"nd_na && ip6.src == fe80::/10 && ip6.dst == ff00::/8",
ds_cstr(actions));
}

ds_clear(actions);
ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT
" = lookup_nd(inport, ip6.src, nd.sll); %snext;",
Expand Down
78 changes: 52 additions & 26 deletions tests/ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -5062,6 +5062,7 @@ AT_CLEANUP

OVN_FOR_EACH_NORTHD([
AT_SETUP([IP relocation using GARP request])
AT_SKIP_IF([test $HAVE_SCAPY = no])
ovn_start

# Logical network:
Expand Down Expand Up @@ -5161,7 +5162,9 @@ done
test_ip() {
# This packet has bad checksums but logical L3 routing doesn't check.
local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
local packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
local packet=$(fmt_pkt "Ether(dst='${dst_mac}', src='${src_mac}')/ \
IP(dst='${dst_ip}', src='${src_ip}')/ \
UDP(sport=53, dport=4369)")
shift; shift; shift; shift; shift
hv=hv`vif_to_hv $inport`
as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
Expand All @@ -5176,7 +5179,9 @@ test_ip() {
# Routing decrements TTL and updates source and dest MAC
# (and checksum).
out_lrp=`vif_to_lrp $outport`
echo f000000000${outport}00000000ff0${out_lrp}08004500001c00000000"3f1101"00${src_ip}${dst_ip}0035111100080000
echo $(fmt_pkt "Ether(dst='f0:00:00:00:00:${outport}', src='00:00:00:00:ff:${out_lrp}')/ \
IP(src='${src_ip}', dst='${dst_ip}', ttl=63)/ \
UDP(sport=53, dport=4369)")
fi >> $outport.expected
done
}
Expand All @@ -5192,8 +5197,10 @@ test_ip() {
# SHA and REPLY_HA are each 12 hex digits.
# SPA and TPA are each 8 hex digits.
test_arp() {
local inport=$1 sha=$2 spa=$3 tpa=$4 reply_ha=$5
local request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
local inport=$1 sha=$2 spa=$3 tpa=$3
local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${sha}')/ \
ARP(hwsrc='${sha}', hwdst='ff:ff:ff:ff:ff:ff', psrc='${spa}', pdst='${tpa}')")

hv=hv`vif_to_hv $inport`
as $hv ovs-appctl netdev-dummy/receive vif$inport $request

Expand All @@ -5206,53 +5213,72 @@ test_arp() {
echo $request >> $i$j$k.expected
fi
done
}

# Expect to receive the reply, if any.
if test X$reply_ha != X; then
lrp=`vif_to_lrp $inport`
local reply=${sha}00000000ff0${lrp}08060001080006040002${reply_ha}${tpa}${sha}${spa}
echo $reply >> $inport.expected
fi
test_na() {
local inport=$1 sha=$2 spa=$3
local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${sha}')/ \
IPv6(dst='ff01::1', src='${spa}')/ \
ICMPv6ND_NA(tgt='${spa}')")

hv=hv`vif_to_hv $inport`
as $hv ovs-appctl netdev-dummy/receive vif$inport $request

# Expect to receive the broadcast ARP on the other logical switch ports if
# IP address is not configured to the switch patch port.
local i=`vif_to_ls $inport`
local j
for j in 1 2; do
if test $i$j != $inport; then
echo $request >> $i$j$k.expected
fi
done
}

# lp11 send GARP request to announce ownership of 192.168.1.100.
# lp11 send GARP request to announce ownership of 192.168.1.100 and fe80::abcd:1.

sha=f00000000011
spa=`ip_to_hex 192 168 1 100`
tpa=$spa
sha="f0:00:00:00:00:11"
spa="192.168.1.100"
spa6="fe80::abcd:1"

# When always_learn_from_arp_request=false, the new mac-binding will not be learned
# through GARP request.
ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false

test_arp 11 $sha $spa $tpa
test_arp 11 $sha $spa
test_na 11 $sha $spa6
sleep 1
check_row_count MAC_Binding 0 ip="192.168.1.100"
check_row_count MAC_Binding 0 ip="$spa"
check_row_count MAC_Binding 0 ip=\"$spa6\"

# When always_learn_from_arp_request=true, the new mac-binding will be learned.
ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=true

test_arp 11 $sha $spa $tpa
OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding ip="192.168.1.100" | wc -l` -gt 0])
test_arp 11 $sha $spa
test_na 11 $sha $spa6
wait_row_count MAC_Binding 1 ip="$spa" mac=\"$sha\"
wait_row_count MAC_Binding 1 ip=\"$spa6\" mac=\"$sha\"
ovn-nbctl --wait=hv sync

# Send an IP packet from lp21 to 192.168.1.100, which should go to lp11.

smac=f00000000021
dmac=00000000ff02
sip=`ip_to_hex 192 168 2 11`
dip=`ip_to_hex 192 168 1 100`
smac="f0:00:00:00:00:21"
dmac="00:00:00:00:ff:02"
sip="192.168.2.11"
dip="192.168.1.100"
test_ip 21 $smac $dmac $sip $dip 11

# lp12 send GARP request to announce ownership of 192.168.1.100.
# lp12 send GARP request to announce ownership of 192.168.1.100 and fe80::abcd:1.

# Even when always_learn_from_arp_request=false, the existing mac-binding should be
# updated through GARP request.
ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false

sha=f00000000012
test_arp 12 $sha $spa $tpa
wait_row_count MAC_Binding 1 ip="192.168.1.100" mac='"f0:00:00:00:00:12"'
sha="f0:00:00:00:00:12"
test_arp 12 $sha $spa
test_na 11 $sha $spa6
wait_row_count MAC_Binding 1 ip="$spa" mac=\"$sha\"
wait_row_count MAC_Binding 1 ip=\"$spa6\" mac=\"$sha\"
ovn-nbctl --wait=hv sync
# give to the hv the time to send queued ip packets
sleep 1
Expand Down
73 changes: 73 additions & 0 deletions tests/system-ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -11550,3 +11550,76 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d

AT_CLEANUP
])

OVN_FOR_EACH_NORTHD([
AT_SETUP([Traffic to router port via LLA])
ovn_start
OVS_TRAFFIC_VSWITCHD_START()
ADD_BR([br-int])
ADD_BR([br-phys], [set Bridge br-phys fail-mode=standalone])

# Set external-ids in br-int needed for ovn-controller
ovs-vsctl \
-- set Open_vSwitch . external-ids:system-id=hv1 \
-- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-- set bridge br-int fail-mode=secure other-config:disable-in-band=true

start_daemon ovn-controller

check ovn-nbctl lr-add lr0
check ovn-nbctl lrp-add lr0 lr0-ls0 00:00:00:00:00:01 fd00::1/64

check ovn-nbctl ls-add ls0
check ovn-nbctl lsp-add ls0 vif0 \
-- lsp-set-addresses vif0 "00:00:00:00:00:02 fd00::2"
check ovn-nbctl lsp-add ls0 ls0-lr0 \
-- lsp-set-type ls0-lr0 router \
-- lsp-set-addresses ls0-lr0 router \
-- lsp-set-options ls0-lr0 router-port=lr0-ls0

ADD_NAMESPACES(vif0)
ADD_VETH(vif0, vif0, br-int, "fd00::2/64", "00:00:00:00:00:02", "fd00::1")
OVS_WAIT_UNTIL([test "$(ip netns exec vif0 ip a | grep fe80:: | grep tentative)" = ""])

check ovn-nbctl set logical_router lr0 options:always_learn_from_arp_request=false

OVN_POPULATE_ARP
wait_for_ports_up
check ovn-nbctl --wait=sb sync

NS_CHECK_EXEC([vif0], [ping -q -c 3 -i 0.3 -w 2 fe80::200:ff:fe00:1 | FORMAT_PING], \
[0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

check_row_count mac_binding 1 mac=\"00:00:00:00:00:02\"
ovn-sbctl --all destroy mac_binding

ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=true

NS_CHECK_EXEC([vif0], [ping -q -c 3 -i 0.3 -w 2 fe80::200:ff:fe00:1 | FORMAT_PING], \
[0], [dnl
3 packets transmitted, 3 received, 0% packet loss, time 0ms
])

check_row_count mac_binding 1 mac=\"00:00:00:00:00:02\"

OVS_APP_EXIT_AND_WAIT([ovn-controller])

as ovn-sb
OVS_APP_EXIT_AND_WAIT([ovsdb-server])

as ovn-nb
OVS_APP_EXIT_AND_WAIT([ovsdb-server])

as northd
OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])

as
OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
/connection dropped.*/d"])

AT_CLEANUP
])

0 comments on commit 5e0cb03

Please sign in to comment.