rcv_text=`echo "$rcv_pcap.packets" | sed 's/\.pcap//'`
exp_text=$2
exp_n=`wc -l < "$exp_text"`
- ovs_wait_cond () {
- $PYTHON "$top_srcdir/utilities/ovs-pcap.in" $rcv_pcap > $rcv_text
- rcv_n=`wc -l < "$rcv_text"`
- test $rcv_n -ge $exp_n
- }
- ovs_wait || echo "expected $exp_n packets, only received $rcv_n"
-
+ OVS_WAIT_UNTIL(
+ [$PYTHON "$top_srcdir/utilities/ovs-pcap.in" $rcv_pcap > $rcv_text
+ rcv_n=`wc -l < "$rcv_text"`
+ echo "rcv_n=$rcv_n exp_n=$exp_n"
+ test $rcv_n -ge $exp_n])
sort $exp_text > expout
}
])
inport == "eth0"
!(inport != "eth0") => inport == "eth0"
+(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) => 0
+
ip4.src == "eth0" => Integer field ip4.src is not compatible with string constant.
inport == 1 => String field inport is not compatible with integer constant.
ip4.src = 1.2.3.4 => Syntax error at `=' expecting relational operator.
ip4.src == {1.2.3.4, $set1, $unknownset} => Syntax error at `$unknownset' expecting address set name.
eth.src == {$set3, badmac, 00:00:00:00:00:01} => Syntax error at `badmac' expecting constant.
+
+((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) => Parentheses nested too deeply.
+
+ct_label > $set4 => Only == and != operators may be used to compare a field against an empty value set.
]])
sed 's/ =>.*//' test-cases.txt > input.txt
sed 's/.* => //' test-cases.txt > expout
# put_dhcp_opts
reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause)
-reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain="ovn.org");
- formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain = "ovn.org");
- encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67,pause)
+reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain="ovn.org",wpad="https://example.org");
+ formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain = "ovn.org", wpad = "https://example.org");
+ encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67,pause)
reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0);
formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0);
encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00,pause)
set_meter(4294967295, 4294967295);
encodes as meter:3
+# log
+log(verdict=allow, severity=warning);
+ encodes as controller(userdata=00.00.00.07.00.00.00.00.00.04)
+log(name="test1", verdict=drop, severity=info);
+ encodes as controller(userdata=00.00.00.07.00.00.00.00.01.06.74.65.73.74.31)
+log(verdict=drop, severity=info, meter="meter1");
+ encodes as controller(userdata=00.00.00.07.00.00.00.00.01.06,meter_id=4)
+log(name="test1", verdict=drop, severity=info, meter="meter1");
+ encodes as controller(userdata=00.00.00.07.00.00.00.00.01.06.74.65.73.74.31,meter_id=4)
+log(verdict=drop);
+ formats as log(verdict=drop, severity=info);
+ encodes as controller(userdata=00.00.00.07.00.00.00.00.01.06)
+log(verdict=bad_verdict, severity=info);
+ Syntax error at `bad_verdict' unknown verdict.
+log(verdict=drop, severity=bad_severity);
+ Syntax error at `bad_severity' unknown severity.
+log(severity=notice);
+ Syntax error at `;' expecting verdict.
+
# put_nd_ra_opts
reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, prefix = aef0::/64, slla = ae:01:02:03:04:05);
encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.00.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.dc.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.05,pause)
ovn-nbctl \
-- lsp-add ls$i lp$i$j$k \
- -- lsp-set-addresses lp$i$j$k "f0:00:00:00:0$i:$j$k \
- 192.168.$i$j.$k" $unknown
+ -- lsp-set-addresses lp$i$j$k \
+ "f0:00:00:00:0$i:$j$k 192.168.$i$j.$k" $unknown
done
done
done
done
}
+# test_arp INPORT SHA SPA TPA [REPLY_HA]
+#
+# Causes a packet to be received on INPORT. The packet is an ARP
+# request with SHA, SPA, and TPA as specified. If REPLY_HA is provided, then
+# it should be the hardware address of the target to expect to receive in an
+# ARP reply; otherwise no reply is expected.
+#
+# INPORT is an logical switch port number, e.g. 11 for vif11.
+# 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}
+ hv=hv`vif_to_hv $inport`
+ as $hv ovs-appctl netdev-dummy/receive vif$inport $request
+ as $hv ovs-appctl ofproto/trace br-int in_port=$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 k
+ for j in 1 2 3; do
+ for k in 1 2 3; do
+ # 192.168.33.254 is configured to the switch patch port for lrp33,
+ # so no ARP flooding expected for it.
+ if test $i$j$k != $inport && test $tpa != `ip_to_hex 192 168 33 254`; then
+ echo $request >> $i$j$k.expected
+ fi
+ done
+ done
+
+ # Expect to receive the reply, if any.
+ if test X$reply_ha != X; then
+ lrp=`vif_to_lrp $inport`
+ local reply=${sha}00000000ff${lrp}08060001080006040002${reply_ha}${tpa}${sha}${spa}
+ echo $reply >> $inport.expected
+ fi
+}
+
as hv1 ovs-vsctl --columns=name,ofport list interface
as hv1 ovn-sbctl list port_binding
as hv1 ovn-sbctl list datapath_binding
done
done
+: > mac_bindings.expected
+
# 3. Send an IP packet from every logical port to every other subnet,
# to an IP address that does not have a static IP-MAC binding.
# This should generate a broadcast ARP request for the destination
# IP address in the destination subnet.
+# Moreover generate an ARP reply for each of the IP addresses ARPed
for is in 1 2 3; do
for js in 1 2 3; do
for ks in 1 2 3; do
echo $arp >> $id$jd2$kd.expected
done
done
+ if test $(vif_to_hv ${is}${js}${ks}) = $(vif_to_hv ${id}${jd}1); then
+ hmac=8000000000$o4
+ rmac=00000000ff$id$jd
+ echo ${hmac}${rmac}08004500001c00000000"3f1101"00${sip}${dip}0035111100080000 >> ${id}11.expected
+ fi
+
+ host_mac=8000000000$o4
+ lrmac=00000000ff$id$jd
+
+ arp_reply=${lrmac}${host_mac}08060001080006040002${host_mac}${dip}${lrmac}${lrip}
+
+ hv=hv`vif_to_hv ${id}${jd}1`
+ as $hv ovs-appctl netdev-dummy/receive vif${id}${jd}1 $arp_reply
+
+ host_ip_pretty=192.168.$id$jd.$o4
+ host_mac_pretty=80:00:00:00:00:$o4
+ echo lrp$id$jd,$host_ip_pretty,$host_mac_pretty >> mac_bindings.expected
done
done
done
done
done
-# test_arp INPORT SHA SPA TPA [REPLY_HA]
-#
-# Causes a packet to be received on INPORT. The packet is an ARP
-# request with SHA, SPA, and TPA as specified. If REPLY_HA is provided, then
-# it should be the hardware address of the target to expect to receive in an
-# ARP reply; otherwise no reply is expected.
-#
-# INPORT is an logical switch port number, e.g. 11 for vif11.
-# 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}
- hv=hv`vif_to_hv $inport`
- as $hv ovs-appctl netdev-dummy/receive vif$inport $request
- as $hv ovs-appctl ofproto/trace br-int in_port=$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 k
- for j in 1 2 3; do
- for k in 1 2 3; do
- # 192.168.33.254 is configured to the switch patch port for lrp33,
- # so no ARP flooding expected for it.
- if test $i$j$k != $inport && test $tpa != `ip_to_hex 192 168 33 254`; then
- echo $request >> $i$j$k.expected
- fi
- done
- done
-
- # Expect to receive the reply, if any.
- if test X$reply_ha != X; then
- lrp=`vif_to_lrp $inport`
- local reply=${sha}00000000ff${lrp}08060001080006040002${reply_ha}${tpa}${sha}${spa}
- echo $reply >> $inport.expected
- fi
-}
-
# Test router replies to ARP requests from all source ports:
#
# 4. Router replies to query for its MAC address from port's own IP address.
# 5. Router replies to query for its MAC address from any random IP address
# in its subnet.
#
-# 6. Router replies to query for its MAC address from another subnet.
+# 6. No reply to query for IP address other than router IP.
#
-# 7. No reply to query for IP address other than router IP.
+# 7. No reply to query from another subnet.
for i in 1 2 3; do
for j in 1 2 3; do
for k in 1 2 3; do
rip=`ip_to_hex 192 168 $i$j 254` # Router IP
rmac=00000000ff$i$j # Router MAC
otherip=`ip_to_hex 192 168 $i$j 55` # Some other IP in subnet
- test_arp $i$j$k $smac $sip $rip $rmac #4
- test_arp $i$j$k $smac $otherip $rip $rmac #5
- test_arp $i$j$k $smac 0a123456 $rip $rmac #6
- test_arp $i$j$k $smac $sip $otherip #7
- done
- done
-done
-
-# Allow some time for packet forwarding.
-# XXX This can be improved.
-sleep 1
-
-# 8. Generate an ARP reply for each of the IP addresses ARPed for
-# earlier as #3.
-#
-# Here, the $s is the VIF that originated the ARP request and $d is
-# the VIF that sends the ARP reply, which is somewhat backward but
-# it means that $s and $d are the same as #3.
-: > mac_bindings.expected
-for is in 1 2 3; do
- for js in 1 2 3; do
- for ks in 1 2 3; do
- s=$is$js$ks
- for id in 1 2 3; do
- for jd in 1 2 3; do
- if test $is$js = $id$jd; then
- continue
+ externalip=`ip_to_hex 1 2 3 4` # Some other IP not in subnet
+
+ test_arp $i$j$k $smac $sip $rip $rmac #4
+ test_arp $i$j$k $smac $otherip $rip $rmac #5
+ test_arp $i$j$k $smac $sip $otherip #6
+
+ # When rip is 192.168.33.254, ARP request from externalip won't be
+ # filtered, because 192.168.33.254 is configured to switch peer port
+ # for lrp33.
+ lrp33_rsp=
+ if test $i = 3 && test $j = 3; then
+ lrp33_rsp=$rmac
+ fi
+ test_arp $i$j$k $smac $externalip $rip $lrp33_rsp #7
+
+ # MAC binding should be learned from ARP request.
+ host_mac_pretty=f0:00:00:00:0$i:$j$k
+
+ host_ip_pretty=192.168.$i$j.$k
+ echo lrp$i$j,$host_ip_pretty,$host_mac_pretty >> mac_bindings.expected
+
+ # mac_binding is learned and overwritten so only the last one remains.
+ if test $k = 3; then
+ # lrp33 will not learn from ARP request, because 192.168.33.254 is
+ # configured to switch peer port for lrp33.
+ if test $i != 3 || test $j != 3; then
+ host_ip_pretty=192.168.$i$j.55
+ echo lrp$i$j,$host_ip_pretty,$host_mac_pretty >> mac_bindings.expected
fi
+ fi
- kd=1
- d=$id$jd$kd
-
- o4=`expr $is '*' 9 + $js '*' 3 + $ks + 10`
- host_ip=`ip_to_hex 192 168 $id$jd $o4`
- host_mac=8000000000$o4
-
- lrmac=00000000ff$id$jd
- lrip=`ip_to_hex 192 168 $id$jd 254`
-
- arp=${lrmac}${host_mac}08060001080006040002${host_mac}${host_ip}${lrmac}${lrip}
-
- echo
- echo
- echo
- hv=hv`vif_to_hv $d`
- as $hv ovs-appctl netdev-dummy/receive vif$d $arp
- #as $hv ovs-appctl ofproto/trace br-int in_port=$d $arp
- #as $hv ovs-ofctl dump-flows br-int table=19
-
- host_ip_pretty=192.168.$id$jd.$o4
- host_mac_pretty=80:00:00:00:00:$o4
- echo lrp$id$jd,$host_ip_pretty,$host_mac_pretty >> mac_bindings.expected
- done
- done
done
done
done
+
# Allow some time for packet forwarding.
# XXX This can be improved.
sleep 1
-# 9. Send an IP packet from every logical port to every other subnet. These
+# 8. Send an IP packet from every logical port to every other subnet. These
# are the same packets already sent as #3, but now the destinations' IP-MAC
# bindings have been discovered via ARP, so instead of provoking an ARP
# request, these packets now get routed to their destinations (which don't
AT_CLEANUP
-# 3 hypervisors, one logical switch, 3 logical ports per hypervisor
-AT_SETUP([ovn -- portsecurity : 3 HVs, 1 LS, 3 lports/HV])
+AT_SETUP([ovn -- IP relocation using GARP request])
AT_SKIP_IF([test $HAVE_PYTHON = no])
ovn_start
-# Create hypervisors hv[123].
-# Add vif1[123] to hv1, vif2[123] to hv2, vif3[123] to hv3.
-# Add all of the vifs to a single logical switch lsw0.
-# Turn off port security on vifs vif[123]1
-# Turn on l2 port security on vifs vif[123]2
-# Turn of l2 and l3 port security on vifs vif[123]3
-# Make vif13, vif2[23], vif3[123] destinations for unknown MACs.
-ovn-nbctl ls-add lsw0
+# Logical network:
+#
+# Two logical switches ls1, ls2.
+# One logical router lr0 connected to ls[12],
+# with 2 subnets, 1 per logical switch:
+#
+# lrp1 on ls1 for subnet 192.168.1.1/24
+# lrp2 on ls2 for subnet 192.168.2.1/24
+#
+# 4 VIFs, 2 per LS lp[12][12], first digit being LS.
+# VIFs' fixed IP addresses are 192.168.[12].1[12].
+#
+# There is a secondary IP 192.168.1.100 that is unknown in NB and learned
+# through ARP only, and it can move between lp11 and lp12.
+#
+ovn-nbctl lr-add lr0
+for i in 1 2 ; do
+ ovn-nbctl ls-add ls$i
+ ovn-nbctl lrp-add lr0 lrp$i 00:00:00:00:ff:0$i 192.168.$i.1/24
+ ovn-nbctl \
+ -- lsp-add ls$i lrp$i-attachment \
+ -- set Logical_Switch_Port lrp$i-attachment type=router \
+ options:router-port=lrp$i \
+ addresses=router
+ for j in 1 2; do
+ ovn-nbctl \
+ -- lsp-add ls$i lp$i$j \
+ -- lsp-set-addresses lp$i$j \
+ "f0:00:00:00:00:$i$j 192.168.$i.1$j"
+ done
+done
+
+# Physical network:
+# 2 hypervisors hv[12], lp?1 on hv1, lp?2 on hv2.
+
+# Given the name of a logical port, prints the name of the hypervisor
+# on which it is located, e.g. "vif_to_hv 12" yields 2.
+vif_to_hv() {
+ echo ${1#?}
+}
+
+# Given the name of a logical port, prints the name of its logical router
+# port, e.g. "vif_to_lrp 12" yields 1.
+vif_to_lrp() {
+ echo ${1%?}
+}
+
+# Given the name of a logical port, prints the name of its logical
+# switch, e.g. "vif_to_ls 12" yields 1.
+vif_to_ls() {
+ echo ${1%?}
+}
+
net_add n1
-for i in 1 2 3; do
+for i in 1 2; do
sim_add hv$i
as hv$i
ovs-vsctl add-br br-phys
ovn_attach n1 br-phys 192.168.0.$i
-
- for j in 1 2 3; do
- ovs-vsctl add-port br-int vif$i$j -- set Interface vif$i$j external-ids:iface-id=lp$i$j options:tx_pcap=hv$i/vif$i$j-tx.pcap options:rxq_pcap=hv$i/vif$i$j-rx.pcap ofport-request=$i$j
- ovn-nbctl lsp-add lsw0 lp$i$j
- if test $j = 1; then
- ovn-nbctl lsp-set-addresses lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j" unknown
- elif test $j = 2; then
- ovn-nbctl lsp-set-addresses lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j"
- ovn-nbctl lsp-set-port-security lp$i$j f0:00:00:00:00:$i$j
- else
- extra_addr="f0:00:00:00:0$i:$i$j fe80::ea2a:eaff:fe28:$i$j"
- ovn-nbctl lsp-set-addresses lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j" "$extra_addr"
- ovn-nbctl lsp-set-port-security lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j" "$extra_addr"
- fi
+done
+for i in 1 2; do
+ for j in 1 2; do
+ hv=`vif_to_hv $i$j`
+ as hv$hv ovs-vsctl \
+ -- add-port br-int vif$i$j \
+ -- set Interface vif$i$j \
+ external-ids:iface-id=lp$i$j \
+ options:tx_pcap=hv$hv/vif$i$j-tx.pcap \
+ options:rxq_pcap=hv$hv/vif$i$j-rx.pcap \
+ ofport-request=$i$j
done
done
# XXX This should be more systematic.
sleep 1
-# Given the name of a logical port, prints the name of the hypervisor
-# on which it is located.
-vif_to_hv() {
- echo hv${1%?}
-}
-
-for i in 1 2 3; do
- for j in 1 2 3; do
+# test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
+#
+# This shell function causes a packet to be received on INPORT. The packet's
+# content has Ethernet destination DST and source SRC (each exactly 12 hex
+# digits) and Ethernet type ETHTYPE (4 hex digits). The OUTPORTs (zero or
+# more) list the VIFs on which the packet should be received. INPORT and the
+# OUTPORTs are specified as logical switch port numbers, e.g. 12 for vif12.
+for i in 1 2; do
+ for j in 1 2; do
: > $i$j.expected
done
done
-
-# test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
-#
-# This shell function causes an ip packet to be received on INPORT.
-# The packet's content has Ethernet destination DST and source SRC
-# (each exactly 12 hex digits) and Ethernet type ETHTYPE (4 hex digits).
-# The OUTPORTs (zero or more) list the VIFs on which the packet should
-# be received. INPORT and the OUTPORTs are specified as logical switch
-# port numbers, e.g. 11 for vif11.
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
shift; shift; shift; shift; shift
- hv=`vif_to_hv $inport`
+ hv=hv`vif_to_hv $inport`
as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
- #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $packet
+ in_ls=`vif_to_ls $inport`
+ in_lrp=`vif_to_lrp $inport`
for outport; do
- echo $packet >> $outport.expected
+ out_ls=`vif_to_ls $outport`
+ if test $in_ls = $out_ls; then
+ # Ports on the same logical switch receive exactly the same packet.
+ echo $packet
+ else
+ # 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
+ fi >> $outport.expected
done
}
-# test_arp INPORT SHA SPA TPA DROP [REPLY_HA]
+# test_arp INPORT SHA SPA TPA [REPLY_HA]
#
# Causes a packet to be received on INPORT. The packet is an ARP
# request with SHA, SPA, and TPA as specified. If REPLY_HA is provided, then
# SHA and REPLY_HA are each 12 hex digits.
# SPA and TPA are each 8 hex digits.
test_arp() {
- local inport=$1 smac=$2 sha=$3 spa=$4 tpa=$5 drop=$6 reply_ha=$7
- local request=ffffffffffff${smac}08060001080006040001${sha}${spa}ffffffffffff${tpa}
- hv=`vif_to_hv $inport`
+ local inport=$1 sha=$2 spa=$3 tpa=$4 reply_ha=$5
+ local request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
+ hv=hv`vif_to_hv $inport`
as $hv ovs-appctl netdev-dummy/receive vif$inport $request
- #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $request
- if test $drop != 1; then
- if test X$reply_ha = X; then
- # Expect to receive the broadcast ARP on the other logical switch ports
- # if no reply is expected.
- local i j
- for i in 1 2 3; do
- for j in 1 2 3; do
- if test $i$j != $inport; then
- echo $request >> $i$j.expected
- fi
- done
- done
- else
- # Expect to receive the reply, if any.
- local reply=${smac}${reply_ha}08060001080006040002${reply_ha}${tpa}${sha}${spa}
- echo $reply >> $inport.expected
+
+ # 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
- 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
+}
+
+ip_to_hex() {
+ printf "%02x%02x%02x%02x" "$@"
+}
+
+# lp11 send GARP request to announce ownership of 192.168.1.100.
+
+sha=f00000000011
+spa=`ip_to_hex 192 168 1 100`
+tpa=$spa
+test_arp 11 $sha $spa $tpa
+OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding ip="192.168.1.100" | wc -l` -gt 0])
+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`
+test_ip 21 $smac $dmac $sip $dip 11
+
+# lp12 send GARP request to announce ownership of 192.168.1.100.
+
+sha=f00000000012
+test_arp 12 $sha $spa $tpa
+OVS_WAIT_UNTIL([ovn-sbctl find mac_binding ip="192.168.1.100" | grep f0:00:00:00:00:12])
+ovn-nbctl --wait=hv sync
+
+# Send an IP packet from lp21 to 192.168.1.100, which should go to lp12.
+
+test_ip 21 $smac $dmac $sip $dip 12
+
+# Now check the packets actually received against the ones expected.
+for i in 1 2; do
+ for j in 1 2; do
+ OVN_CHECK_PACKETS([hv`vif_to_hv $i$j`/vif$i$j-tx.pcap],
+ [$i$j.expected])
+ done
+done
+
+# Gracefully terminate daemons
+OVN_CLEANUP([hv1], [hv2])
+
+AT_CLEANUP
+
+# 3 hypervisors, one logical switch, 3 logical ports per hypervisor
+AT_SETUP([ovn -- portsecurity : 3 HVs, 1 LS, 3 lports/HV])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# Create hypervisors hv[123].
+# Add vif1[123] to hv1, vif2[123] to hv2, vif3[123] to hv3.
+# Add all of the vifs to a single logical switch lsw0.
+# Turn off port security on vifs vif[123]1
+# Turn on l2 port security on vifs vif[123]2
+# Turn of l2 and l3 port security on vifs vif[123]3
+# Make vif13, vif2[23], vif3[123] destinations for unknown MACs.
+ovn-nbctl ls-add lsw0
+net_add n1
+for i in 1 2 3; do
+ sim_add hv$i
+ as hv$i
+ ovs-vsctl add-br br-phys
+ ovn_attach n1 br-phys 192.168.0.$i
+
+ for j in 1 2 3; do
+ ovs-vsctl add-port br-int vif$i$j -- set Interface vif$i$j external-ids:iface-id=lp$i$j options:tx_pcap=hv$i/vif$i$j-tx.pcap options:rxq_pcap=hv$i/vif$i$j-rx.pcap ofport-request=$i$j
+ ovn-nbctl lsp-add lsw0 lp$i$j
+ if test $j = 1; then
+ ovn-nbctl lsp-set-addresses lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j" unknown
+ elif test $j = 2; then
+ ovn-nbctl lsp-set-addresses lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j"
+ ovn-nbctl lsp-set-port-security lp$i$j f0:00:00:00:00:$i$j
+ else
+ extra_addr="f0:00:00:00:0$i:$i$j fe80::ea2a:eaff:fe28:$i$j"
+ ovn-nbctl lsp-set-addresses lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j" "$extra_addr"
+ ovn-nbctl lsp-set-port-security lp$i$j "f0:00:00:00:00:$i$j 192.168.0.$i$j" "$extra_addr"
+ fi
+ done
+done
+
+# Pre-populate the hypervisors' ARP tables so that we don't lose any
+# packets for ARP resolution (native tunneling doesn't queue packets
+# for ARP resolution).
+OVN_POPULATE_ARP
+
+# Allow some time for ovn-northd and ovn-controller to catch up.
+# XXX This should be more systematic.
+sleep 1
+
+# Given the name of a logical port, prints the name of the hypervisor
+# on which it is located.
+vif_to_hv() {
+ echo hv${1%?}
+}
+
+for i in 1 2 3; do
+ for j in 1 2 3; do
+ : > $i$j.expected
+ done
+done
+
+# test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
+#
+# This shell function causes an ip packet to be received on INPORT.
+# The packet's content has Ethernet destination DST and source SRC
+# (each exactly 12 hex digits) and Ethernet type ETHTYPE (4 hex digits).
+# The OUTPORTs (zero or more) list the VIFs on which the packet should
+# be received. INPORT and the OUTPORTs are specified as logical switch
+# port numbers, e.g. 11 for vif11.
+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
+ shift; shift; shift; shift; shift
+ hv=`vif_to_hv $inport`
+ as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
+ #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $packet
+ for outport; do
+ echo $packet >> $outport.expected
+ done
+}
+
+# test_arp INPORT SHA SPA TPA DROP [REPLY_HA]
+#
+# Causes a packet to be received on INPORT. The packet is an ARP
+# request with SHA, SPA, and TPA as specified. If REPLY_HA is provided, then
+# it should be the hardware address of the target to expect to receive in an
+# ARP reply; otherwise no reply is expected.
+#
+# INPORT is an logical switch port number, e.g. 11 for vif11.
+# SHA and REPLY_HA are each 12 hex digits.
+# SPA and TPA are each 8 hex digits.
+test_arp() {
+ local inport=$1 smac=$2 sha=$3 spa=$4 tpa=$5 drop=$6 reply_ha=$7
+ local request=ffffffffffff${smac}08060001080006040001${sha}${spa}ffffffffffff${tpa}
+ hv=`vif_to_hv $inport`
+ as $hv ovs-appctl netdev-dummy/receive vif$inport $request
+ #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $request
+ if test $drop != 1; then
+ if test X$reply_ha = X; then
+ # Expect to receive the broadcast ARP on the other logical switch ports
+ # if no reply is expected.
+ local i j
+ for i in 1 2 3; do
+ for j in 1 2 3; do
+ if test $i$j != $inport; then
+ echo $request >> $i$j.expected
+ fi
+ done
+ done
+ else
+ # Expect to receive the reply, if any.
+ local reply=${smac}${reply_ha}08060001080006040002${reply_ha}${tpa}${sha}${spa}
+ echo $reply >> $inport.expected
+ fi
+ fi
+}
# test_ipv6 INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
# This function is similar to test_ip() except that it sends
as hv1 ovs-vsctl show
# This shell function sends a DHCP request packet
-# test_dhcp INPORT SRC_MAC DHCP_TYPE OFFER_IP ...
+# test_dhcp INPORT SRC_MAC DHCP_TYPE OFFER_IP REQUEST_IP ...
test_dhcp() {
- local inport=$1 src_mac=$2 dhcp_type=$3 offer_ip=$4 use_ip=$5
- shift; shift; shift; shift; shift;
+ local inport=$1 src_mac=$2 dhcp_type=$3 ciaddr=$4 offer_ip=$5 request_ip=$6 use_ip=$7
+ shift; shift; shift; shift; shift; shift; shift;
if test $use_ip != 0; then
src_ip=$1
dst_ip=$2
src_ip=`ip_to_hex 0 0 0 0`
dst_ip=`ip_to_hex 255 255 255 255`
fi
- local request=ffffffffffff${src_mac}0800451001100000000080110000${src_ip}${dst_ip}
+ if test $request_ip != 0; then
+ ip_len=0120
+ udp_len=010b
+ else
+ ip_len=011a
+ udp_len=0106
+ fi
+ local request=ffffffffffff${src_mac}08004510${ip_len}0000000080110000${src_ip}${dst_ip}
# udp header and dhcp header
- request=${request}0044004300fc0000
- request=${request}010106006359aa760000000000000000000000000000000000000000${src_mac}
+ request=${request}00440043${udp_len}0000
+ request=${request}010106006359aa7600000000${ciaddr}000000000000000000000000${src_mac}
# client hardware padding
request=${request}00000000000000000000
# server hostname
# dhcp magic cookie
request=${request}63825363
# dhcp message type
- request=${request}3501${dhcp_type}ff
+ request=${request}3501${dhcp_type}
+ # dhcp unknown option
+ request=${request}d70701020304050607
+ # dhcp pad option
+ request=${request}00
+ if test $request_ip != 0; then
+ # dhcp requested ip
+ request=${request}3204${request_ip}
+ fi
+ # dhcp end option
+ request=${request}ff
+ for port in $inport "$@"; do
+ : >> $port.expected
+ done
if test $offer_ip != 0; then
- local srv_mac=$1 srv_ip=$2 expected_dhcp_opts=$3
+ local srv_mac=$1 srv_ip=$2 dhcp_reply_type=$3 expected_dhcp_opts=$4
# total IP length will be the IP length of the request packet
# (which is 272 in our case) + 8 (padding bytes) + (expected_dhcp_opts / 2)
ip_len=`expr 280 + ${#expected_dhcp_opts} / 2`
local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${offer_ip}
# udp header and dhcp header.
# $udp_len var will be in 3 digits. So adding a '0' before $udp_len
- reply=${reply}004300440${udp_len}0000020106006359aa760000000000000000
- # your ip address
- reply=${reply}${offer_ip}
+ reply=${reply}004300440${udp_len}0000020106006359aa7600000000${ciaddr}
+ # your ip address; 0 for NAK
+ if test $dhcp_reply_type = 06; then
+ reply=${reply}00000000
+ else
+ reply=${reply}${offer_ip}
+ fi
# next server ip address, relay agent ip address, client mac address
reply=${reply}0000000000000000${src_mac}
# client hardware padding
reply=${reply}0000000000000000000000000000000000000000000000000000000000000000
# dhcp magic cookie
reply=${reply}63825363
- # dhcp message type
- local dhcp_reply_type=02
- if test $dhcp_type = 03; then
- dhcp_reply_type=05
- fi
reply=${reply}3501${dhcp_reply_type}${expected_dhcp_opts}00000000ff00000000
echo $reply >> $inport.expected
else
# Send DHCPDISCOVER.
offer_ip=`ip_to_hex 10 0 0 4`
server_ip=`ip_to_hex 10 0 0 1`
+ciaddr=`ip_to_hex 0 0 0 0`
+request_ip=0
expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
-test_dhcp 1 f00000000001 01 $offer_ip 0 ff1000000001 $server_ip $expected_dhcp_opts
+test_dhcp 1 f00000000001 01 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
# NXT_RESUMEs should be 1.
OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
rm -f 1.expected
rm -f 2.expected
-# Send DHCPREQUEST.
+# Send DHCPREQUEST in the SELECTING/INIT-REBOOT state with the offered IP
+# address in the Requested IP Address option.
offer_ip=`ip_to_hex 10 0 0 6`
server_ip=`ip_to_hex 10 0 0 1`
+ciaddr=`ip_to_hex 0 0 0 0`
+request_ip=$offer_ip
expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
-test_dhcp 2 f00000000002 03 $offer_ip 0 ff1000000001 $server_ip $expected_dhcp_opts
+test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
# NXT_RESUMEs should be 2.
OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
rm -f 1.expected
rm -f 2.expected
+# Send DHCPREQUEST in the SELECTING/INIT-REBOOT state with a mismatched IP in
+# the Requested IP Address option, expect a DHCPNAK.
+offer_ip=`ip_to_hex 10 0 0 6`
+server_ip=`ip_to_hex 10 0 0 1`
+ciaddr=`ip_to_hex 0 0 0 0`
+request_ip=`ip_to_hex 10 0 0 7`
+expected_dhcp_opts=""
+test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 06 $expected_dhcp_opts
+
+# NXT_RESUMEs should be 3.
+OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+cat 2.expected | cut -c -48 > expout
+AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
+# Skipping the IPv4 checksum.
+cat 2.expected | cut -c 53- > expout
+AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
+
+reset_pcap_file hv1-vif1 hv1/vif1
+reset_pcap_file hv1-vif2 hv1/vif2
+rm -f 1.expected
+rm -f 2.expected
+
# Send Invalid DHCPv4 packet on ls1-lp2. It should be received by ovn-controller
# but should be resumed without the reply.
# ls1-lp1 (vif1-tx.pcap) should receive the DHCPv4 request packet twice,
# one from ovn-controller and the other from "ovs-ofctl resume."
+ciaddr=`ip_to_hex 0 0 0 0`
offer_ip=0
-test_dhcp 2 f00000000002 08 $offer_ip 0 1 1
+request_ip=0
+test_dhcp 2 f00000000002 08 $ciaddr $offer_ip $request_ip 0 1 1
-# NXT_RESUMEs should be 3.
-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+# NXT_RESUMEs should be 4.
+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
# vif1-tx.pcap should have received the DHCPv4 (invalid) request packet
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
# Send DHCPv4 packet on ls2-lp1. It doesn't have any DHCPv4 options defined.
# ls2-lp2 (vif4-tx.pcap) should receive the DHCPv4 request packet once.
-test_dhcp 3 f00000000003 01 0 4 0
+ciaddr=`ip_to_hex 0 0 0 0`
+test_dhcp 3 f00000000003 01 $ciaddr 0 0 4 0
# Send DHCPv4 packet on ls2-lp2. "router" DHCPv4 option is not defined for
# this lport.
-test_dhcp 4 f00000000004 01 0 3 0
+ciaddr=`ip_to_hex 0 0 0 0`
+test_dhcp 4 f00000000004 01 $ciaddr 0 0 3 0
-# NXT_RESUMEs should be 3.
-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+# NXT_RESUMEs should be 4.
+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
-OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [3.expected])
-OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [4.expected])
+#OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [3.expected])
+#OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [4.expected])
-# Send DHCPREQUEST with ip4.src set to 10.0.0.6 and ip4.dst set to 10.0.0.1.
+# Send DHCPREQUEST in the RENEWING/REBINDING state with ip4.src set to 10.0.0.6
+# and ip4.dst set to 10.0.0.1.
offer_ip=`ip_to_hex 10 0 0 6`
server_ip=`ip_to_hex 10 0 0 1`
-expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+ciaddr=$offer_ip
+request_ip=0
src_ip=$offer_ip
dst_ip=$server_ip
-test_dhcp 2 f00000000002 03 $offer_ip 1 $src_ip $dst_ip ff1000000001 $server_ip $expected_dhcp_opts
+expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
-# NXT_RESUMEs should be 4.
-OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+# NXT_RESUMEs should be 5.
+OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
cat 2.expected | cut -c -48 > expout
rm -f 1.expected
rm -f 2.expected
-# Send DHCPREQUEST with ip4.src set to 10.0.0.6 and ip4.dst set to 255.255.255.255.
+# Send DHCPREQUEST in the RENEWING/REBINDING state with ip4.src set to 10.0.0.6
+# and ip4.dst set to 255.255.255.255.
offer_ip=`ip_to_hex 10 0 0 6`
server_ip=`ip_to_hex 10 0 0 1`
+ciaddr=$offer_ip
+request_ip=0
+src_ip=$offer_ip
+dst_ip=`ip_to_hex 255 255 255 255`
expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
+test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
+
+# NXT_RESUMEs should be 6.
+OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+cat 2.expected | cut -c -48 > expout
+AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
+# Skipping the IPv4 checksum.
+cat 2.expected | cut -c 53- > expout
+AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
+
+reset_pcap_file hv1-vif1 hv1/vif1
+reset_pcap_file hv1-vif2 hv1/vif2
+rm -f 1.expected
+rm -f 2.expected
+
+# Send DHCPREQUEST in the RENEWING/REBINDING state with a mismatched IP in the
+# ciaddr, expect a DHCPNAK.
+offer_ip=`ip_to_hex 10 0 0 6`
+server_ip=`ip_to_hex 10 0 0 1`
+ciaddr=`ip_to_hex 10 0 0 7`
+request_ip=0
src_ip=$offer_ip
dst_ip=`ip_to_hex 255 255 255 255`
-test_dhcp 2 f00000000002 03 $offer_ip 1 $src_ip $dst_ip ff1000000001 $server_ip $expected_dhcp_opts
+expected_dhcp_opts=""
+test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
-# NXT_RESUMEs should be 5.
-OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+# NXT_RESUMEs should be 7.
+OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
+cat 2.expected | cut -c -48 > expout
+AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
+# Skipping the IPv4 checksum.
+cat 2.expected | cut -c 53- > expout
+AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
+
+reset_pcap_file hv1-vif1 hv1/vif1
+reset_pcap_file hv1-vif2 hv1/vif2
+rm -f 1.expected
+rm -f 2.expected
+
+# Send DHCPREQUEST in the RENEWING/REBINDING state without a specifyied ciaddr,
+# expect a DHCPNAK.
+offer_ip=`ip_to_hex 10 0 0 6`
+server_ip=`ip_to_hex 10 0 0 1`
+ciaddr=`ip_to_hex 0 0 0 0`
+request_ip=0
+src_ip=$offer_ip
+dst_ip=`ip_to_hex 255 255 255 255`
+expected_dhcp_opts=""
+test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
+
+# NXT_RESUMEs should be 8.
+OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
cat 2.expected | cut -c -48 > expout
# Send DHCPREQUEST with ip4.src set to 10.0.0.6 and ip4.dst set to 10.0.0.4.
# The packet should not be received by ovn-controller.
+ciaddr=`ip_to_hex 0 0 0 0`
src_ip=`ip_to_hex 10 0 0 6`
dst_ip=`ip_to_hex 10 0 0 4`
-test_dhcp 2 f00000000002 03 0 1 $src_ip $dst_ip 1
+test_dhcp 2 f00000000002 03 $ciaddr 0 0 1 $src_ip $dst_ip 1
-# NXT_RESUMEs should be 5.
-OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+# NXT_RESUMEs should be 8.
+OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
# vif1-tx.pcap should have received the DHCPv4 request packet
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
# from the "ovs-ofctl monitor br-int resume"
test_dhcpv6() {
local inport=$1 src_mac=$2 src_lla=$3 msg_code=$4 offer_ip=$5
- local request=ffffffffffff${src_mac}86dd00000000002a1101${src_lla}
+ if test $msg_code != 0b; then
+ req_len=2a
+ else
+ req_len=1a
+ fi
+ local request=ffffffffffff${src_mac}86dd0000000000${req_len}1101${src_lla}
# dst ip ff02::1:2
request=${request}ff020000000000000000000000010002
# udp header and dhcpv6 header
- request=${request}02220223002affff${msg_code}010203
+ request=${request}0222022300${req_len}ffff${msg_code}010203
# Client identifier
request=${request}0001000a00030001${src_mac}
- # IA-NA (Identity Association for Non Temporary Address)
- request=${request}0003000c0102030400000e1000001518
+ # Add IA-NA (Identity Association for Non Temporary Address) if msg_code
+ # is not 11 (information request packet)
+ if test $msg_code != 0b; then
+ request=${request}0003000c0102030400000e1000001518
+ fi
shift; shift; shift; shift; shift;
if test $offer_ip != 0; then
local server_mac=000000100001
AT_CHECK([cat 4.packets], [0], [expout])
# Send DHCPv6 packet on ls1-lp3. native DHCPv6 works as stateless mode for this port.
-# The DHCPv6 reply should doesn't contian offer_ip.
+# The DHCPv6 reply shouldn't contain offer_ip.
src_mac=f00000000022
src_lla=fe80000000000000f20000fffe000022
reset_pcap_file hv1-vif5 hv1/vif5
cat 5.expected | cut -c 1-120,125- > expout
AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout])
+# Send DHCPv6 information request (code 11) on ls1-lp3. The DHCPv6 reply
+# shouldn't contain offer_ip
+src_mac=f00000000022
+src_lla=fe80000000000000f20000fffe000022
+reset_pcap_file hv1-vif5 hv1/vif5
+rm -f 5.expected
+test_dhcpv6 5 $src_mac $src_lla 0b 1 5
+
+# NXT_RESUMEs should be 4.
+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif5-tx.pcap |
+trim_zeros > 5.packets
+# Skipping the UDP checksum
+cat 5.expected | cut -c 1-120,125- > expout
+AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout])
+
as hv1
OVS_APP_EXIT_AND_WAIT([ovn-controller])
OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
ovn-nbctl lsp-add sw0 p0 -- lsp-set-addresses p0 dynamic
ovn-nbctl --wait=sb add Logical-Switch sw0 other_config subnet=192.168.1.0/24
AT_CHECK([ovn-nbctl get Logical-Switch-Port p0 dynamic_addresses], [0],
- ["0a:00:00:00:00:01 192.168.1.2"
+ ["0a:00:00:a8:01:03 192.168.1.2"
])
# Add 9 more ports to sw0, addresses should all be unique.
ovn-nbctl --wait=sb lsp-add sw0 "p$n" -- lsp-set-addresses "p$n" dynamic
done
AT_CHECK([ovn-nbctl get Logical-Switch-Port p1 dynamic_addresses], [0],
- ["0a:00:00:00:00:02 192.168.1.3"
+ ["0a:00:00:a8:01:04 192.168.1.3"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p2 dynamic_addresses], [0],
- ["0a:00:00:00:00:03 192.168.1.4"
+ ["0a:00:00:a8:01:05 192.168.1.4"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p3 dynamic_addresses], [0],
- ["0a:00:00:00:00:04 192.168.1.5"
+ ["0a:00:00:a8:01:06 192.168.1.5"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p4 dynamic_addresses], [0],
- ["0a:00:00:00:00:05 192.168.1.6"
+ ["0a:00:00:a8:01:07 192.168.1.6"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p5 dynamic_addresses], [0],
- ["0a:00:00:00:00:06 192.168.1.7"
+ ["0a:00:00:a8:01:08 192.168.1.7"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p6 dynamic_addresses], [0],
- ["0a:00:00:00:00:07 192.168.1.8"
+ ["0a:00:00:a8:01:09 192.168.1.8"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p7 dynamic_addresses], [0],
- ["0a:00:00:00:00:08 192.168.1.9"
+ ["0a:00:00:a8:01:0a 192.168.1.9"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p8 dynamic_addresses], [0],
- ["0a:00:00:00:00:09 192.168.1.10"
+ ["0a:00:00:a8:01:0b 192.168.1.10"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p9 dynamic_addresses], [0],
- ["0a:00:00:00:00:0a 192.168.1.11"
+ ["0a:00:00:a8:01:0c 192.168.1.11"
])
# Trying similar tests with a second switch. MAC addresses should be unique
ovn-nbctl lsp-add sw1 p10 -- lsp-set-addresses p10 dynamic
ovn-nbctl --wait=sb add Logical-Switch sw1 other_config subnet=192.168.1.0/24
AT_CHECK([ovn-nbctl get Logical-Switch-Port p10 dynamic_addresses], [0],
- ["0a:00:00:00:00:0b 192.168.1.2"
+ ["0a:00:00:a8:01:0d 192.168.1.2"
])
for n in `seq 11 19`; do
ovn-nbctl --wait=sb lsp-add sw1 "p$n" -- lsp-set-addresses "p$n" dynamic
done
AT_CHECK([ovn-nbctl get Logical-Switch-Port p11 dynamic_addresses], [0],
- ["0a:00:00:00:00:0c 192.168.1.3"
+ ["0a:00:00:a8:01:0e 192.168.1.3"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p12 dynamic_addresses], [0],
- ["0a:00:00:00:00:0d 192.168.1.4"
+ ["0a:00:00:a8:01:0f 192.168.1.4"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p13 dynamic_addresses], [0],
- ["0a:00:00:00:00:0e 192.168.1.5"
+ ["0a:00:00:a8:01:10 192.168.1.5"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p14 dynamic_addresses], [0],
- ["0a:00:00:00:00:0f 192.168.1.6"
+ ["0a:00:00:a8:01:11 192.168.1.6"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p15 dynamic_addresses], [0],
- ["0a:00:00:00:00:10 192.168.1.7"
+ ["0a:00:00:a8:01:12 192.168.1.7"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p16 dynamic_addresses], [0],
- ["0a:00:00:00:00:11 192.168.1.8"
+ ["0a:00:00:a8:01:13 192.168.1.8"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p17 dynamic_addresses], [0],
- ["0a:00:00:00:00:12 192.168.1.9"
+ ["0a:00:00:a8:01:14 192.168.1.9"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p18 dynamic_addresses], [0],
- ["0a:00:00:00:00:13 192.168.1.10"
+ ["0a:00:00:a8:01:15 192.168.1.10"
])
AT_CHECK([ovn-nbctl get Logical-Switch-Port p19 dynamic_addresses], [0],
- ["0a:00:00:00:00:14 192.168.1.11"
+ ["0a:00:00:a8:01:16 192.168.1.11"
])
# Change a port's address to test for multiple ip's for a single address entry
# and addresses set by the user.
-ovn-nbctl lsp-set-addresses p0 "0a:00:00:00:00:15 192.168.1.12 192.168.1.14"
+ovn-nbctl lsp-set-addresses p0 "0a:00:00:a8:01:17 192.168.1.2 192.168.1.12 192.168.1.14"
ovn-nbctl --wait=sb lsp-add sw0 p20 -- lsp-set-addresses p20 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p20 dynamic_addresses], [0],
- ["0a:00:00:00:00:16 192.168.1.13"
+ ["0a:00:00:a8:01:18 192.168.1.13"
])
# Test for logical router port address management.
ovn-nbctl create Logical_Router name=R1
ovn-nbctl -- --id=@lrp create Logical_Router_port name=sw0 \
-network="192.168.1.1/24" mac=\"0a:00:00:00:00:17\" \
+network="192.168.1.1/24" mac=\"0a:00:00:a8:01:19\" \
-- add Logical_Router R1 ports @lrp -- lsp-add sw0 rp-sw0 \
-- set Logical_Switch_Port rp-sw0 type=router options:router-port=sw0
ovn-nbctl --wait=sb lsp-add sw0 p21 -- lsp-set-addresses p21 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p21 dynamic_addresses], [0],
- ["0a:00:00:00:00:18 192.168.1.15"
+ ["0a:00:00:a8:01:1a 192.168.1.15"
])
# Test for address reuse after logical port is deleted.
ovn-nbctl lsp-del p0
ovn-nbctl --wait=sb lsp-add sw0 p23 -- lsp-set-addresses p23 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p23 dynamic_addresses], [0],
- ["0a:00:00:00:00:19 192.168.1.2"
+ ["0a:00:00:a8:01:03 192.168.1.2"
])
# Test for multiple addresses to one logical port.
ovn-nbctl lsp-add sw0 p25 -- lsp-set-addresses p25 \
-"0a:00:00:00:00:1a 192.168.1.12" "0a:00:00:00:00:1b 192.168.1.14"
+"0a:00:00:a8:01:1b 192.168.1.12" "0a:00:00:a8:01:1c 192.168.1.14"
ovn-nbctl --wait=sb lsp-add sw0 p26 -- lsp-set-addresses p26 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p26 dynamic_addresses], [0],
- ["0a:00:00:00:00:1c 192.168.1.16"
+ ["0a:00:00:a8:01:17 192.168.1.16"
])
# Test for exhausting subnet address space.
ovn-nbctl ls-add sw2 -- add Logical-Switch sw2 other_config subnet=172.16.1.0/30
ovn-nbctl --wait=sb lsp-add sw2 p27 -- lsp-set-addresses p27 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p27 dynamic_addresses], [0],
- ["0a:00:00:00:00:1d 172.16.1.2"
+ ["0a:00:00:10:01:03 172.16.1.2"
])
ovn-nbctl --wait=sb lsp-add sw2 p28 -- lsp-set-addresses p28 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p28 dynamic_addresses], [0],
- ["0a:00:00:00:00:1e"
+ ["0a:00:00:00:00:01"
])
# Test that address management does not add duplicate MAC for lsp/lrp peers.
ovn-nbctl create Logical_Router name=R2
ovn-nbctl ls-add sw3
ovn-nbctl lsp-add sw3 p29 -- lsp-set-addresses p29 \
-"0a:00:00:00:00:1f"
+"0a:00:00:a8:01:18"
ovn-nbctl -- --id=@lrp create Logical_Router_port name=sw3 \
-network="192.168.2.1/24" mac=\"0a:00:00:00:00:1f\" \
+network="192.168.2.1/24" mac=\"0a:00:00:a8:01:18\" \
-- add Logical_Router R2 ports @lrp -- lsp-add sw3 rp-sw3 \
-- set Logical_Switch_Port rp-sw3 type=router options:router-port=sw3
ovn-nbctl --wait=sb lsp-add sw0 p30 -- lsp-set-addresses p30 dynamic
AT_CHECK([ovn-nbctl get Logical-Switch-Port p30 dynamic_addresses], [0],
- ["0a:00:00:00:00:20 192.168.1.17"
+ ["0a:00:00:a8:01:1d 192.168.1.17"
])
# Test static MAC address with dynamically allocated IP
# Update the static MAC address with dynamically allocated IP and check
# if the MAC address is updated in 'Logical_Switch_Port.dynamic_adddresses'
ovn-nbctl --wait=sb lsp-set-addresses p31 "fe:dc:ba:98:76:55 dynamic"
-ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses
AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses], [0],
["fe:dc:ba:98:76:55 192.168.1.18"
ovn-nbctl --wait=sb lsp-set-addresses p31 "dynamic"
AT_CHECK([ovn-nbctl get Logical-Switch-Port p31 dynamic_addresses], [0],
- ["fe:dc:ba:98:76:55 192.168.1.18"
+ ["0a:00:00:a8:01:1e 192.168.1.18"
])
ovn-nbctl --wait=sb lsp-set-addresses p31 "fe:dc:ba:98:76:56 dynamic"
"dynamic"
# 192.168.1.20 should be assigned as 192.168.1.19 is excluded.
AT_CHECK([ovn-nbctl get Logical-Switch-Port p32 dynamic_addresses], [0],
- ["0a:00:00:00:00:21 192.168.1.20"
+ ["0a:00:00:a8:01:1e 192.168.1.20"
])
ovn-nbctl --wait=sb lsp-add sw0 p33 -- lsp-set-addresses p33 \
"dynamic"
# 192.168.1.22 should be assigned as 192.168.1.21 is excluded.
AT_CHECK([ovn-nbctl get Logical-Switch-Port p33 dynamic_addresses], [0],
- ["0a:00:00:00:00:22 192.168.1.22"
+ ["0a:00:00:a8:01:1f 192.168.1.22"
])
ovn-nbctl --wait=sb lsp-add sw0 p34 -- lsp-set-addresses p34 \
"dynamic"
# 192.168.1.51 should be assigned as 192.168.1.23-192.168.1.50 is excluded.
AT_CHECK([ovn-nbctl get Logical-Switch-Port p34 dynamic_addresses], [0],
- ["0a:00:00:00:00:23 192.168.1.51"
+ ["0a:00:00:a8:01:34 192.168.1.51"
])
# Now clear the exclude_ips list. 192.168.1.19 should be assigned.
ovn-nbctl --wait=sb lsp-add sw0 p35 -- lsp-set-addresses p35 \
"dynamic"
AT_CHECK([ovn-nbctl get Logical-Switch-Port p35 dynamic_addresses], [0],
- ["0a:00:00:00:00:24 192.168.1.19"
+ ["0a:00:00:a8:01:20 192.168.1.19"
])
# Set invalid data in exclude_ips list. It should be ignored.
"dynamic"
# 192.168.1.21 should be assigned as that's the next free one.
AT_CHECK([ovn-nbctl get Logical-Switch-Port p36 dynamic_addresses], [0],
- ["0a:00:00:00:00:25 192.168.1.21"
+ ["0a:00:00:a8:01:21 192.168.1.21"
])
# Clear the dynamic addresses assignment request.
# With prefix aef0 and mac 0a:00:00:00:00:26, the dynamic IPv6 should be
# - aef0::800:ff:fe00:26 (EUI64)
AT_CHECK([ovn-nbctl get Logical-Switch-Port p37 dynamic_addresses], [0],
- ["0a:00:00:00:00:26 192.168.1.21 aef0::800:ff:fe00:26"
+ ["0a:00:00:a8:01:21 192.168.1.21 aef0::800:ff:fea8:121"
])
ovn-nbctl --wait=sb ls-add sw4
-ovn-nbctl --wait=sb set Logical-switch sw4 other_config:ipv6_prefix="bef0::"
+ovn-nbctl --wait=sb set Logical-switch sw4 other_config:ipv6_prefix="bef0::" \
+-- set Logical-switch sw4 other_config:subnet=192.168.2.0/30
ovn-nbctl --wait=sb lsp-add sw4 p38 -- lsp-set-addresses p38 \
"dynamic"
AT_CHECK([ovn-nbctl get Logical-Switch-Port p38 dynamic_addresses], [0],
- ["0a:00:00:00:00:27 bef0::800:ff:fe00:27"
+ ["0a:00:00:a8:02:03 192.168.2.2 bef0::800:ff:fea8:203"
])
ovn-nbctl --wait=sb lsp-add sw4 p39 -- lsp-set-addresses p39 \
["f0:00:00:00:10:12 bef0::f200:ff:fe00:1012"
])
-# Clear the other_config for sw4. No dynamic ip should be assigned.
-ovn-nbctl --wait=sb clear Logical-switch sw4 other_config
+# Test the case where IPv4 addresses are exhausted and IPv6 prefix is set
+# p40 should not have an IPv4 address since the pool is exhausted
ovn-nbctl --wait=sb lsp-add sw4 p40 -- lsp-set-addresses p40 \
"dynamic"
-
AT_CHECK([ovn-nbctl get Logical-Switch-Port p40 dynamic_addresses], [0],
+ ["0a:00:00:00:00:02 bef0::800:ff:fe00:2"
+])
+
+# Test dynamic changes on switch ports.
+#
+ovn-nbctl --wait=sb ls-add sw5
+ovn-nbctl --wait=sb lsp-add sw5 p41 -- lsp-set-addresses p41 \
+"dynamic"
+# p41 will start with nothing
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
[[[]]
])
-# Test the case where IPv4 addresses are exhausted and IPv6 prefix is set
-ovn-nbctl --wait=sb set Logical-switch sw4 other_config:subnet=192.168.2.0/30 \
--- set Logical-switch sw4 other_config:ipv6_prefix="bef0::"
+# Set a subnet. Now p41 should have an ipv4 address, too
+ovn-nbctl --wait=sb add Logical-Switch sw5 other_config subnet=192.168.1.0/24
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["0a:00:00:a8:01:22 192.168.1.2"
+])
-# Now p40 should be assigned with dynamic addresses.
-AT_CHECK([ovn-nbctl get Logical-Switch-Port p40 dynamic_addresses], [0],
- ["0a:00:00:00:00:28 192.168.2.2 bef0::800:ff:fe00:28"
+# Clear the other_config. The IPv4 address should be gone
+ovn-nbctl --wait=sb clear Logical-Switch sw5 other_config
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ [[[]]
])
-ovn-nbctl --wait=sb lsp-add sw4 p41 -- lsp-set-addresses p41 \
-"dynamic"
-# p41 should not have IPv4 address (as the pool is exhausted).
+# Set an IPv6 prefix. Now p41 should have an IPv6 address.
+ovn-nbctl --wait=sb set Logical-Switch sw5 other_config:ipv6_prefix="aef0::"
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["0a:00:00:00:00:03 aef0::800:ff:fe00:3"
+])
+
+# Change the MAC address to a static one. The IPv6 address should update.
+ovn-nbctl --wait=sb lsp-set-addresses p41 "f0:00:00:00:10:2b dynamic"
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["f0:00:00:00:10:2b aef0::f200:ff:fe00:102b"
+])
+
+# Change the IPv6 prefix. The IPv6 address should update.
+ovn-nbctl --wait=sb set Logical-Switch sw5 other_config:ipv6_prefix="bef0::"
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["f0:00:00:00:10:2b bef0::f200:ff:fe00:102b"
+])
+
+# Clear the other_config. The IPv6 address should be gone
+ovn-nbctl --wait=sb clear Logical-Switch sw5 other_config
AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
- ["0a:00:00:00:00:29 bef0::800:ff:fe00:29"
+ [[[]]
+])
+
+# Set the subnet again. Now p41 should get the IPv4 address again.
+ovn-nbctl --wait=sb add Logical-Switch sw5 other_config subnet=192.168.1.0/24
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["f0:00:00:00:10:2b 192.168.1.2"
+])
+
+# Add an excluded IP address that conflicts with p41. p41 should update.
+ovn-nbctl --wait=sb add Logical-Switch sw5 other_config \
+exclude_ips="192.168.1.2"
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["f0:00:00:00:10:2b 192.168.1.3"
+])
+
+# Add static ip address
+ovn-nbctl --wait=sb lsp-set-addresses p41 "dynamic 192.168.1.100"
+ovn-nbctl list Logical-Switch-Port p41
+ovn-nbctl --wait=sb lsp-add sw5 p42 -- lsp-set-addresses p42 \
+"dynamic 192.168.1.101"
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p41 dynamic_addresses], [0],
+ ["0a:00:00:a8:01:65 192.168.1.100"
+])
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p42 dynamic_addresses], [0],
+ ["0a:00:00:a8:01:66 192.168.1.101"
+])
+
+# define a mac address prefix
+ovn-nbctl ls-add sw6
+ovn-nbctl --wait=hv set NB_Global . options:mac_prefix="00:11:22:33:44:55"
+ovn-nbctl --wait=sb set Logical-Switch sw6 other_config:subnet=192.168.100.0/24
+for n in $(seq 1 3); do
+ ovn-nbctl --wait=sb lsp-add sw6 "p5$n" -- lsp-set-addresses "p5$n" dynamic
+done
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p51 dynamic_addresses], [0],
+ ["00:11:22:a8:64:03 192.168.100.2"
+])
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p52 dynamic_addresses], [0],
+ ["00:11:22:a8:64:04 192.168.100.3"
+])
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p53 dynamic_addresses], [0],
+ ["00:11:22:a8:64:05 192.168.100.4"
+])
+
+# verify configuration order does not break IPAM/MACAM
+ovn-nbctl ls-add sw7
+for n in $(seq 1 3); do
+ ovn-nbctl --wait=sb lsp-add sw7 "p7$n" -- lsp-set-addresses "p7$n" dynamic
+done
+ovn-nbctl --wait=sb set Logical-Switch sw7 other_config:ipv6_prefix="bef0::"
+p71_addr=$(ovn-nbctl get Logical-Switch-Port p71 dynamic_addresses)
+p72_addr=$(ovn-nbctl get Logical-Switch-Port p72 dynamic_addresses)
+p73_addr=$(ovn-nbctl get Logical-Switch-Port p73 dynamic_addresses)
+AT_CHECK([test "$p71_addr" != "$p72_addr"], [0], [])
+AT_CHECK([test "$p71_addr" != "$p73_addr"], [0], [])
+AT_CHECK([test "$p72_addr" != "$p73_addr"], [0], [])
+
+# request to assign mac only
+#
+ovn-nbctl ls-add sw8
+ovn-nbctl --wait=sb set Logical-Switch sw8 other_config:mac_only=true
+for n in $(seq 1 3); do
+ ovn-nbctl --wait=sb lsp-add sw8 "p8$n" -- lsp-set-addresses "p8$n" dynamic
+done
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p81 dynamic_addresses], [0],
+ ["00:11:22:00:00:06"
+])
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p82 dynamic_addresses], [0],
+ ["00:11:22:00:00:07"
+])
+AT_CHECK([ovn-nbctl get Logical-Switch-Port p83 dynamic_addresses], [0],
+ ["00:11:22:00:00:08"
])
as ovn-sb
# Create logical port foo1 in foo
ovn-nbctl --wait=sb lsp-add foo foo1 \
-- lsp-set-addresses foo1 "dynamic"
-AT_CHECK([ovn-nbctl --timeout=10 wait-until Logical-Switch-Port foo1 dynamic_addresses='"0a:00:00:00:00:01 192.168.1.2"'], [0])
+AT_CHECK([ovn-nbctl --timeout=10 wait-until Logical-Switch-Port foo1 dynamic_addresses='"0a:00:00:a8:01:03 192.168.1.2"'], [0])
# Create logical port alice1 in alice
ovn-nbctl --wait=sb lsp-add alice alice1 \
-- lsp-set-addresses alice1 "dynamic"
-AT_CHECK([ovn-nbctl --timeout=10 wait-until Logical-Switch-Port alice1 dynamic_addresses='"0a:00:00:00:00:02 192.168.2.2"'])
+AT_CHECK([ovn-nbctl --timeout=10 wait-until Logical-Switch-Port alice1 dynamic_addresses='"0a:00:00:a8:02:03 192.168.2.2"'])
# Create logical port foo2 in foo
ovn-nbctl --wait=sb lsp-add foo foo2 \
-- lsp-set-addresses foo2 "dynamic"
-AT_CHECK([ovn-nbctl --timeout=10 wait-until Logical-Switch-Port foo2 dynamic_addresses='"0a:00:00:00:00:03 192.168.1.3"'])
+AT_CHECK([ovn-nbctl --timeout=10 wait-until Logical-Switch-Port foo2 dynamic_addresses='"0a:00:00:a8:01:04 192.168.1.3"'])
# Create a hypervisor and create OVS ports corresponding to logical ports.
net_add n1
}
# Send ip packets between foo1 and foo2
-src_mac="0a0000000001"
-dst_mac="0a0000000003"
+src_mac="0a0000a80103"
+dst_mac="0a0000a80104"
src_ip=`ip_to_hex 192 168 1 2`
dst_ip=`ip_to_hex 192 168 1 3`
packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
# Send ip packets between foo1 and alice1
-src_mac="0a0000000001"
+src_mac="0a0000a80103"
dst_mac="000000010203"
src_ip=`ip_to_hex 192 168 1 2`
dst_ip=`ip_to_hex 192 168 2 2`
as hv1 ovs-ofctl dump-flows br-int
# Packet to Expect at foo2
-src_mac="0a0000000001"
-dst_mac="0a0000000003"
+src_mac="0a0000a80103"
+dst_mac="0a0000a80104"
src_ip=`ip_to_hex 192 168 1 2`
dst_ip=`ip_to_hex 192 168 1 3`
expected=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
# Packet to Expect at alice1
src_mac="000000010204"
-dst_mac="0a0000000002"
+dst_mac="0a0000a80203"
src_ip=`ip_to_hex 192 168 1 2`
dst_ip=`ip_to_hex 192 168 2 2`
expected=${dst_mac}${src_mac}08004500001c000000003f110100${src_ip}${dst_ip}0035111100080000
AT_CHECK([ovn-nbctl lsp-set-addresses localvif1 "f0:00:00:00:00:01 192.168.1.1"])
AT_CHECK([ovn-nbctl lsp-set-port-security localvif1 "f0:00:00:00:00:01"])
AT_CHECK([ovn-nbctl lsp-add lsw0 localvif2])
-AT_CHECK([ovn-nbctl lsp-set-addresses localvif2 "f0:00:00:00:00:01 192.168.1.2"])
+AT_CHECK([ovn-nbctl lsp-set-addresses localvif2 "f0:00:00:00:00:02 192.168.1.2"])
AT_CHECK([ovn-nbctl lsp-set-port-security localvif2 "f0:00:00:00:00:02"])
AT_CHECK([ovn-nbctl lsp-add lsw0 localvif3])
AT_CHECK([ovn-nbctl lsp-set-addresses localvif3 "f0:00:00:00:00:03 192.168.1.3"])
AT_CLEANUP
+AT_SETUP([ovn -- ACL rate-limited logging])
+AT_KEYWORDS([ovn])
+ovn_start
+
+net_add n1
+
+sim_add hv
+as hv
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+for i in lp1 lp2; do
+ ovs-vsctl -- add-port br-int $i -- \
+ set interface $i external-ids:iface-id=$i \
+ options:tx_pcap=hv/$i-tx.pcap \
+ options:rxq_pcap=hv/$i-rx.pcap
+done
+
+lp1_mac="f0:00:00:00:00:01"
+lp1_ip="192.168.1.2"
+
+lp2_mac="f0:00:00:00:00:02"
+lp2_ip="192.168.1.3"
+
+ovn-nbctl ls-add lsw0
+ovn-nbctl --wait=sb lsp-add lsw0 lp1
+ovn-nbctl --wait=sb lsp-add lsw0 lp2
+ovn-nbctl lsp-set-addresses lp1 $lp1_mac
+ovn-nbctl lsp-set-addresses lp2 $lp2_mac
+ovn-nbctl --wait=sb sync
+
+
+# Add an ACL that rate-limits logs at 10 per second.
+ovn-nbctl meter-add http-rl1 drop 10 pktps
+ovn-nbctl --log --severity=alert --meter=http-rl1 --name=http-acl1 acl-add lsw0 to-lport 1000 'tcp.dst==80' drop
+
+# Add an ACL that rate-limits logs at 5 per second.
+ovn-nbctl meter-add http-rl2 drop 5 pktps
+ovn-nbctl --log --severity=alert --meter=http-rl2 --name=http-acl2 acl-add lsw0 to-lport 1000 'tcp.dst==81' allow
+
+# Add an ACL that doesn't rate-limit logs.
+ovn-nbctl --log --severity=alert --name=http-acl3 acl-add lsw0 to-lport 1000 'tcp.dst==82' drop
+
+
+# For each ACL, send 100 packets.
+for i in `seq 1 100`; do
+ ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=80)'
+
+ ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=81)'
+
+ ovs-appctl netdev-dummy/receive lp1 'in_port(1),eth(src=f0:00:00:00:00:01,dst=f0:00:00:00:00:02),eth_type(0x0800),ipv4(src=192.168.1.2,dst=192.168.1.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=7777,dst=82)'
+done
+
+# The rate at which packets are sent is highly system-dependent, so we
+# can't count on precise drop counts. To work around that, we just
+# check that exactly 100 "http-acl3" actions were logged and that there
+# were more "http-acl1" actions than "http-acl2" ones.
+OVS_WAIT_UNTIL([ test 100 = $(grep -c 'http-acl3' hv/ovn-controller.log) ])
+
+# On particularly slow or overloaded systems, the transmission rate may
+# be lower than the configured meter rate. To prevent false test
+# failures, we check the duration count of the meter, and if it's
+# greater than nine seconds, just skip the test.
+d_secs=$(as hv ovs-ofctl -O OpenFlow13 meter-stats br-int | grep "meter:1" | sed 's/.* duration:\([[0-9]]\{1,\}\)\.[[0-9]]\+s .*/\1/')
+
+echo "Meter duration: $d_secs"
+AT_SKIP_IF([test $d_secs -gt 9])
+
+# Print some information that may help debugging.
+as hv ovs-appctl -t ovn-controller meter-table-list
+as hv ovs-ofctl -O OpenFlow13 meter-stats br-int
+
+n_acl1=$(grep -c 'http-acl1' hv/ovn-controller.log)
+n_acl2=$(grep -c 'http-acl2' hv/ovn-controller.log)
+n_acl3=$(grep -c 'http-acl3' hv/ovn-controller.log)
+
+AT_CHECK([ test $n_acl3 -gt $n_acl1 ], [0], [])
+AT_CHECK([ test $n_acl1 -gt $n_acl2 ], [0], [])
+
+OVN_CLEANUP([hv])
+AT_CLEANUP
+
+
AT_SETUP([ovn -- DSCP marking and meter check])
AT_KEYWORDS([ovn])
ovn_start
echo $packet >> expected1
OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1])
+# Send broadcast packet from foo1. foo1 should not receive the same packet.
+src_mac="f00000010205"
+dst_mac="ffffffffffff"
+src_ip=`ip_to_hex 192 168 1 2`
+dst_ip=`ip_to_hex 255 255 255 255`
+packet=${dst_mac}${src_mac}8100000108004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
+as hv1 ovs-appctl netdev-dummy/receive vm1 $packet
+
+# expected packet at VM1
+OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1])
+
OVN_CLEANUP([hv1],[hv2])
AT_CLEANUP
AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=32 | grep =0x3,metadata=0x1 | wc -l], [0], [0
])
# Check that arp reply on distributed gateway port is only programmed on hv2
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep arp | grep =0x2,metadata=0x1 | wc -l], [0], [0
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep arp | grep load:0x2- | grep =0x2,metadata=0x1 | wc -l], [0], [0
])
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int | grep arp | grep =0x2,metadata=0x1 | wc -l], [0], [1
+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int | grep arp | grep load:0x2- | grep =0x2,metadata=0x1 | wc -l], [0], [1
])
dst_ip=`ip_to_hex 172 16 1 3`
packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
-# ARP request packet to expect at outside1
-src_mac="000002010203"
-src_ip=`ip_to_hex 172 16 1 1`
-arp_request=ffffffffffff${src_mac}08060001080006040001${src_mac}${src_ip}000000000000${dst_ip}
-
-as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
-
-echo $arp_request >> hv3-vif1.expected
-OVN_CHECK_PACKETS([hv3/vif1-tx.pcap], [hv3-vif1.expected])
-
-# Send ARP reply from outside1 back to the router
-reply_mac="f00000010204"
-arp_reply=${src_mac}${reply_mac}08060001080006040002${reply_mac}${dst_ip}${src_mac}${src_ip}
-
-as hv3 ovs-appctl netdev-dummy/receive hv3-vif1 $arp_reply
-
-# Allow some time for ovn-northd and ovn-controller to catch up.
-# XXX This should be more systematic.
-sleep 1
-
# Packet to Expect at outside1
src_mac="000002010203"
dst_mac="f00000010204"
-src_ip=`ip_to_hex 192 168 1 2`
-dst_ip=`ip_to_hex 172 16 1 3`
expected=${dst_mac}${src_mac}08004500001c000000003f110100${src_ip}${dst_ip}0035111100080000
-# Resend packet from foo1 to outside1
as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
echo "------ hv1 dump ----------"
AT_CLEANUP
+# VLAN traffic for external network redirected through distributed router
+# gateway port should use vlans(i.e input network vlan tag) across hypervisors
+# instead of tunneling.
+AT_SETUP([ovn -- vlan traffic for external network with distributed router gateway port])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# Logical network:
+# # One LR R1 that has switches foo (192.168.1.0/24) and
+# # alice (172.16.1.0/24) connected to it. The logical port
+# # between R1 and alice has a "redirect-chassis" specified,
+# # i.e. it is the distributed router gateway port(172.16.1.6).
+# # Switch alice also has a localnet port defined.
+# # An additional switch outside has the same subnet as alice
+# # (172.16.1.0/24), a localnet port and nexthop port(172.16.1.1)
+# # which will receive the packet destined for external network
+# # (i.e 8.8.8.8 as destination ip).
+
+# Physical network:
+# # Three hypervisors hv[123].
+# # hv1 hosts vif foo1.
+# # hv2 is the "redirect-chassis" that hosts the distributed router gateway port.
+# # hv3 hosts nexthop port vif outside1.
+# # All other tests connect hypervisors to network n1 through br-phys for tunneling.
+# # But in this test, hv1 won't connect to n1(and no br-phys in hv1), and
+# # in order to show vlans(instead of tunneling) used between hv1 and hv2,
+# # a new network n2 created and hv1 and hv2 connected to this network through br-ex.
+# # hv2 and hv3 are still connected to n1 network through br-phys.
+net_add n1
+
+# We are not calling ovn_attach for hv1, to avoid adding br-phys.
+# Tunneling won't work in hv1 as ovn-encap-ip is not added to any bridge in hv1
+sim_add hv1
+as hv1
+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,vxlan \
+ -- set Open_vSwitch . external-ids:ovn-encap-ip=192.168.0.1 \
+ -- add-br br-int \
+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \
+ -- set Open_vSwitch . external-ids:ovn-bridge-mappings=public:br-ex
+
+start_daemon ovn-controller
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=foo1 \
+ ofport-request=1
+
+sim_add hv2
+as hv2
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.2
+ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings="public:br-ex,phys:br-phys"
+
+sim_add hv3
+as hv3
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.3
+ovs-vsctl -- add-port br-int hv3-vif1 -- \
+ set interface hv3-vif1 external-ids:iface-id=outside1 \
+ options:tx_pcap=hv3/vif1-tx.pcap \
+ options:rxq_pcap=hv3/vif1-rx.pcap \
+ ofport-request=1
+ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings="phys:br-phys"
+
+# Create network n2 for vlan connectivity between hv1 and hv2
+net_add n2
+
+as hv1
+ovs-vsctl add-br br-ex
+net_attach n2 br-ex
+
+as hv2
+ovs-vsctl add-br br-ex
+net_attach n2 br-ex
+
+OVN_POPULATE_ARP
+
+ovn-nbctl create Logical_Router name=R1
+
+ovn-nbctl ls-add foo
+ovn-nbctl ls-add alice
+ovn-nbctl ls-add outside
+
+# Connect foo to R1
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+ type=router options:router-port=foo \
+ -- lsp-set-addresses rp-foo router
+
+# Connect alice to R1 as distributed router gateway port (172.16.1.6) on hv2
+ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 172.16.1.6/24 \
+ -- set Logical_Router_Port alice options:redirect-chassis="hv2"
+ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
+ type=router options:router-port=alice \
+ -- lsp-set-addresses rp-alice router \
+
+# Create logical port foo1 in foo
+ovn-nbctl lsp-add foo foo1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
+
+# Create logical port outside1 in outside, which is a nexthop address
+# for 172.16.1.0/24
+ovn-nbctl lsp-add outside outside1 \
+-- lsp-set-addresses outside1 "f0:00:00:01:02:04 172.16.1.1"
+
+# Set default gateway (nexthop) to 172.16.1.1
+ovn-nbctl lr-route-add R1 "0.0.0.0/0" 172.16.1.1 alice
+AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.6 192.168.1.1/24])
+ovn-nbctl set Logical_Switch_Port rp-alice options:nat-addresses=router
+
+ovn-nbctl lsp-add foo ln-foo
+ovn-nbctl lsp-set-addresses ln-foo unknown
+ovn-nbctl lsp-set-options ln-foo network_name=public
+ovn-nbctl lsp-set-type ln-foo localnet
+AT_CHECK([ovn-nbctl set Logical_Switch_Port ln-foo tag=2])
+
+# Create localnet port in alice
+ovn-nbctl lsp-add alice ln-alice
+ovn-nbctl lsp-set-addresses ln-alice unknown
+ovn-nbctl lsp-set-type ln-alice localnet
+ovn-nbctl lsp-set-options ln-alice network_name=phys
+
+# Create localnet port in outside
+ovn-nbctl lsp-add outside ln-outside
+ovn-nbctl lsp-set-addresses ln-outside unknown
+ovn-nbctl lsp-set-type ln-outside localnet
+ovn-nbctl lsp-set-options ln-outside network_name=phys
+
+# Allow some time for ovn-northd and ovn-controller to catch up.
+# XXX This should be more systematic.
+ovn-nbctl --wait=hv --timeout=3 sync
+
+# Check that there is a logical flow in logical switch foo's pipeline
+# to set the outport to rp-foo (which is expected).
+OVS_WAIT_UNTIL([test 1 = `ovn-sbctl dump-flows foo | grep ls_in_l2_lkup | \
+grep rp-foo | grep -v is_chassis_resident | wc -l`])
+
+# Set the option 'reside-on-redirect-chassis' for foo
+ovn-nbctl set logical_router_port foo options:reside-on-redirect-chassis=true
+# Check that there is a logical flow in logical switch foo's pipeline
+# to set the outport to rp-foo with the condition is_chassis_redirect.
+ovn-sbctl dump-flows foo
+OVS_WAIT_UNTIL([test 1 = `ovn-sbctl dump-flows foo | grep ls_in_l2_lkup | \
+grep rp-foo | grep is_chassis_resident | wc -l`])
+
+echo "---------NB dump-----"
+ovn-nbctl show
+echo "---------------------"
+ovn-nbctl list logical_router
+echo "---------------------"
+ovn-nbctl list nat
+echo "---------------------"
+ovn-nbctl list logical_router_port
+echo "---------------------"
+
+echo "---------SB dump-----"
+ovn-sbctl list datapath_binding
+echo "---------------------"
+ovn-sbctl list port_binding
+echo "---------------------"
+ovn-sbctl dump-flows
+echo "---------------------"
+ovn-sbctl list chassis
+echo "---------------------"
+
+for chassis in hv1 hv2 hv3; do
+ as $chassis
+ echo "------ $chassis dump ----------"
+ ovs-vsctl show br-int
+ ovs-ofctl show br-int
+ ovs-ofctl dump-flows br-int
+ echo "--------------------------"
+done
+
+ip_to_hex() {
+ printf "%02x%02x%02x%02x" "$@"
+}
+
+foo1_ip=$(ip_to_hex 192 168 1 2)
+gw_ip=$(ip_to_hex 172 16 1 6)
+dst_ip=$(ip_to_hex 8 8 8 8)
+nexthop_ip=$(ip_to_hex 172 16 1 1)
+
+foo1_mac="f00000010203"
+foo_mac="000001010203"
+gw_mac="000002010203"
+nexthop_mac="f00000010204"
+
+# Send ip packet from foo1 to 8.8.8.8
+src_mac="f00000010203"
+dst_mac="000001010203"
+packet=${foo_mac}${foo1_mac}08004500001c0000000040110000${foo1_ip}${dst_ip}0035111100080000
+
+# Wait for GARPs announcing gw IP to arrive
+OVS_WAIT_UNTIL([
+ test `as hv2 ovs-ofctl dump-flows br-int | grep table=66 | \
+grep actions=mod_dl_dst:f0:00:00:01:02:04 | wc -l` -eq 1
+ ])
+
+# VLAN tagged packet with router port(192.168.1.1) MAC as destination MAC
+# is expected on bridge connecting hv1 and hv2
+expected=${foo_mac}${foo1_mac}8100000208004500001c0000000040110000${foo1_ip}${dst_ip}0035111100080000
+echo $expected > hv1-br-ex_n2.expected
+
+# Packet to Expect at outside1 i.e nexthop(172.16.1.1) port.
+# As connection tracking not enabled for this test, snat can't be done on the packet.
+# We still see foo1 as the source ip address. But source mac(gateway MAC) and
+# dest mac(nexthop mac) are properly configured.
+expected=${nexthop_mac}${gw_mac}08004500001c000000003f110100${foo1_ip}${dst_ip}0035111100080000
+echo $expected > hv3-vif1.expected
+
+reset_pcap_file() {
+ local iface=$1
+ local pcap_file=$2
+ ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
+options:rxq_pcap=dummy-rx.pcap
+ rm -f ${pcap_file}*.pcap
+ ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
+options:rxq_pcap=${pcap_file}-rx.pcap
+}
+
+as hv1 reset_pcap_file br-ex_n2 hv1/br-ex_n2
+as hv3 reset_pcap_file hv3-vif1 hv3/vif1
+sleep 2
+# Take note of how many packets arrived on the VLAN switch before generating
+# further traffic
+n_packets=`as hv1 ovs-ofctl dump-flows br-int table=65 | grep "priority=100,reg15=0x1,metadata=0x2" | grep actions=clone | sed 's/.*n_packets=\([[0-9]]*\),.*/\1/'`
+as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
+sleep 2
+
+# On hv1, the packet should not go from vlan switch pipleline to router
+# pipeline
+as hv1 ovs-ofctl dump-flows br-int
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=65 | grep "priority=100,reg15=0x1,metadata=0x2" \
+| grep actions=clone | grep -v n_packets=$n_packets | wc -l], [0], [[0
+]])
+
+# On hv1, table 32 check that no packet goes via the tunnel port
+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=32 \
+| grep "NXM_NX_TUN_ID" | grep -v n_packets=0 | wc -l], [0], [[0
+]])
+
+ip_packet() {
+ grep "1010203f00000010203"
+}
+
+# Check vlan tagged packet on the bridge connecting hv1 and hv2 with the
+# foo1's mac.
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-ex_n2-tx.pcap | ip_packet | uniq > hv1-br-ex_n2
+cat hv1-br-ex_n2.expected > expout
+AT_CHECK([sort hv1-br-ex_n2], [0], [expout])
+
+# Check expected packet on nexthop interface
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv3/vif1-tx.pcap | grep ${foo1_ip}${dst_ip} | uniq > hv3-vif1
+cat hv3-vif1.expected > expout
+AT_CHECK([sort hv3-vif1], [0], [expout])
+
+OVN_CLEANUP([hv1],[hv2],[hv3])
+AT_CLEANUP
+
AT_SETUP([ovn -- IPv6 ND Router Solicitation responder])
AT_KEYWORDS([ovn-nd_ra])
AT_SKIP_IF([test $HAVE_PYTHON = no])
as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding ip="10.0.0.2" | wc -l` -gt 0])
ovn-nbctl --wait=hv sync
-# Send the second packet to reach the destination.
-as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
# Packet to Expect at 'alice1'
src_mac="000000010204"
ovs-ofctl dump-flows br-int
echo "--------------------------"
done
-function bfd_dump() {
+bfd_dump() {
for chassis in gw1 gw2 hv1 hv2; do
as $chassis
echo "------ $chassis dump (BFD)----"
done
# make sure BFD is not enabled to hv2, we don't need it
AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv2-0],[0],
- [[enable=false
+ [[
]])
done
# make sure BFD is not enabled to hv1, we don't need it
AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
- [[enable=false
+ [[
]])
sleep 3 # let BFD sessions settle so we get the right flows on the right chassis
[0],[[1
]])
+ovn-nbctl --wait=hv set NB_Global . options:"bfd-min-rx"=2000
+as gw2
+for chassis in gw1 hv1 hv2; do
+ echo "checking gw2 -> $chassis"
+ OVS_WAIT_UNTIL([
+ bfd_cfg=$(ovs-vsctl --bare --columns bfd find Interface name=ovn-$chassis-0)
+ test "$bfd_cfg" = "enable=true min_rx=2000"
+])
+done
+ovn-nbctl --wait=hv set NB_Global . options:"bfd-min-tx"=1500
+for chassis in gw1 hv1 hv2; do
+ echo "checking gw2 -> $chassis"
+ OVS_WAIT_UNTIL([
+ bfd_cfg=$(ovs-vsctl --bare --columns bfd find Interface name=ovn-$chassis-0)
+ test "$bfd_cfg" = "enable=true min_rx=2000 min_tx=1500"
+])
+done
+ovn-nbctl remove NB_Global . options "bfd-min-rx"
+ovn-nbctl --wait=hv set NB_Global . options:"bfd-mult"=5
+for chassis in gw1 hv1 hv2; do
+ echo "checking gw2 -> $chassis"
+ OVS_WAIT_UNTIL([
+ bfd_cfg=$(ovs-vsctl --bare --columns bfd find Interface name=ovn-$chassis-0)
+ test "$bfd_cfg" = "enable=true min_tx=1500 mult=5"
+])
+done
+
OVN_CLEANUP([gw1],[gw2],[hv1],[hv2])
AT_CLEANUP
ovn-nbctl lrp-add lr0_ip6 lrp0_ip6 00:00:00:00:af:01 aef0:0:0:0:0:0:0:0/64
ovn-nbctl lsp-add sw0_ip6 lrp0_ip6-attachment
ovn-nbctl lsp-set-type lrp0_ip6-attachment router
-ovn-nbctl lsp-set-addresses lrp0_ip6-attachment 00:00:00:00:af:01
+ovn-nbctl lsp-set-addresses lrp0_ip6-attachment router
ovn-nbctl lsp-set-options lrp0_ip6-attachment router-port=lrp0_ip6
ovn-nbctl set logical_router_port lrp0_ip6 ipv6_ra_configs:address_mode=slaac
2001:db8:1:0:200:02ff:fe01:0204/64 \
-- set Logical_Router_port ip6_public options:redirect-chassis="hv1"
+#install static route
+ovn-nbctl -- --id=@lrt create Logical_Router_Static_Route \
+ip_prefix="\:\:/0" nexthop="2001\:db8\:1\:0\:200\:02ff\:fe01\:1305" \
+-- add Logical_Router lr0_ip6 static_routes @lrt
ovn-nbctl lsp-add public rp-ip6_public -- set Logical_Switch_Port \
rp-ip6_public type=router options:router-port=ip6_public \
ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw0_ip6-port1` = xup])
+
+# There should be 2 Neighbor Advertisement flows for the router port
+# aef0:: ip address in logical switch pipeline with action nd_na_router.
+AT_CHECK([ovn-sbctl dump-flows sw0_ip6 | grep ls_in_arp_rsp | \
+grep "nd_na_router" | wc -l], [0], [2
+])
+
+# There should be 4 Neighbor Advertisement flows with action nd_na_router
+# in the router pipeline for the router lr0_ip6.
+AT_CHECK([ovn-sbctl dump-flows lr0_ip6 | grep nd_na_router | \
+wc -l], [0], [4
+])
+
cr_uuid=`ovn-sbctl find port_binding logical_port=cr-ip6_public | grep _uuid | cut -f2 -d ":"`
# There is only one chassis.
sed 's/\(00\)\{1,\}$//'
}
+reset_pcap_file() {
+ local iface=$1
+ local pcap_file=$2
+ ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
+options:rxq_pcap=dummy-rx.pcap
+ rm -f ${pcap_file}*.pcap
+ ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \
+options:rxq_pcap=${pcap_file}-rx.pcap
+}
+
# Test the IPv6 Neighbor Solicitation (NS) - nd_ns action for unknown MAC
# addresses. ovn-controller should generate an IPv6 NS request for IPv6
# packets whose MAC is unknown (in the ARP_REQUEST router pipeline stage.
# test_ipv6 INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
# This function sends ipv6 packet
test_ipv6() {
- local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4
- dst_ip=20010db800010000020002fffe010205
+ local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
+ local dst_mcast_mac=$6 mcast_node_ip=$7 nd_target=$8
local packet=${dst_mac}${src_mac}86dd6000000000083aff${src_ip}${dst_ip}
packet=${packet}8000000000000000
- shift; shift; shift; shift
- dst_mac=3333ff010205
src_mac=000002010204
- mcast_node_ip=ff0200000000000000000001ff010205
- expected_packet=${dst_mac}${src_mac}86dd6000000000203aff${src_ip}
- expected_packet=${expected_packet}${mcast_node_ip}8700XXXX00000000${dst_ip}
- expected_packet=${expected_packet}0101${src_mac}
+ expected_packet=${dst_mcast_mac}${src_mac}86dd6000000000203aff${src_ip}
+ expected_packet=${expected_packet}${mcast_node_ip}8700XXXX00000000
+ expected_packet=${expected_packet}${nd_target}0101${src_mac}
as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $packet
+ rm -f ipv6_ns.expected
echo $expected_packet >> ipv6_ns.expected
}
src_mac=506400000002
dst_mac=00000000af01
src_ip=aef0000000000000526400fffe000002
+dst_ip=20010db800010000020002fffe010205
+dst_mcast_mac=3333ff010205
+mcast_node_ip=ff0200000000000000000001ff010205
+nd_target=20010db800010000020002fffe010205
# Send an IPv6 packet. Generated IPv6 Neighbor solicitation packet
# should be received by the ports attached to br-phys.
-test_ipv6 1 $src_mac $dst_mac $src_ip 2
+test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \
+$mcast_node_ip $nd_target
+
+OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)])
+OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)])
+
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys_n1-tx.pcap | \
+trim_zeros > 1.packets
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys-tx.pcap | \
+trim_zeros > 2.packets
+
+cat ipv6_ns.expected | cut -c -112 > expout
+AT_CHECK([cat 1.packets | cut -c -112], [0], [expout])
+AT_CHECK([cat 2.packets | cut -c -112], [0], [expout])
+
+# Skipping the ICMPv6 checksum
+cat ipv6_ns.expected | cut -c 117- > expout
+AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout])
+AT_CHECK([cat 2.packets | cut -c 117-], [0], [expout])
+
+# Now send a packet with destination ip other than
+# 2001:db8:1:0:200:02ff:fe01:0204/64 prefix.
+reset_pcap_file br-phys_n1 hv1/br-phys_n1
+reset_pcap_file br-phys hv1/br-phys
+
+src_mac=506400000002
+dst_mac=00000000af01
+src_ip=aef0000000000000526400fffe000002
+dst_ip=20020ab8000100000200020000020306
+# multicast mac of the nexthop IP - 2001:db8:1:0:200:02ff:fe01:1305
+dst_mcast_mac=3333ff011305
+mcast_node_ip=ff0200000000000000000001ff011305
+nd_target=20010db800010000020002fffe011305
+test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \
+$mcast_node_ip $nd_target
OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)])
OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)])
for k in 1 2 3; do
ovn-nbctl \
-- lsp-add ls$i lp$i$j$k \
- -- lsp-set-addresses lp$i$j$k "f0:00:00:00:0$i:$j$k \
- 192.168.$i$j.$k"
+ -- lsp-set-addresses lp$i$j$k \
+ "f0:00:00:00:0$i:$j$k 192.168.$i$j.$k"
# logical ports lp[12]?1 belongs to port group pg1
if test $i != 3 && test $k == 1; then
pg1_ports="$pg1_ports `get_lsp_uuid $i$j$k`"
for k in 1 2 3; do
ovn-nbctl \
-- lsp-add ls$i lp$i$j$k \
- -- lsp-set-addresses lp$i$j$k "f0:00:00:00:0$i:$j$k \
- 192.168.$i$j.$k"
+ -- lsp-set-addresses lp$i$j$k \
+ "f0:00:00:00:0$i:$j$k 192.168.$i$j.$k"
# logical ports lp[12]?1 belongs to port group pg1
if test $i != 3 && test $k == 1; then
pg1_ports="$pg1_ports `get_lsp_uuid $i$j$k`"
# XXX This should be more systematic.
sleep 1
-# test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
+lsp_to_mac() {
+ echo f0:00:00:00:0${1:0:1}:${1:1:2}
+}
+
+lrp_to_mac() {
+ echo 00:00:00:00:ff:$1
+}
+
+# test_icmp INPORT SRC_MAC DST_MAC SRC_IP DST_IP ICMP_TYPE OUTPORT...
#
-# This shell function causes a packet to be received on INPORT. The packet's
-# content has Ethernet destination DST and source SRC (each exactly 12 hex
-# digits) and Ethernet type ETHTYPE (4 hex digits). The OUTPORTs (zero or
-# more) list the VIFs on which the packet should be received. INPORT and the
-# OUTPORTs are specified as logical switch port numbers, e.g. 123 for vif123.
+# This shell function causes a ICMP packet to be received on INPORT.
+# The OUTPORTs (zero or more) list the VIFs on which the packet should
+# be received. INPORT and the OUTPORTs are specified as logical switch
+# port numbers, e.g. 123 for vif123.
for i in 1 2 3; do
for j in 1 2 3; do
for k in 1 2 3; do
done
done
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
- shift; shift; shift; shift; shift
+
+test_icmp() {
+ local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 icmp_type=$6
+ local packet="inport==\"lp$inport\" && eth.src==$src_mac &&
+ eth.dst==$dst_mac && ip.ttl==64 && ip4.src==$src_ip
+ && ip4.dst==$dst_ip && icmp4.type==$icmp_type &&
+ icmp4.code==0"
+ shift; shift; shift; shift; shift; shift
hv=hv`vif_to_hv $inport`
- as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
- #as $hv ovs-appctl ofproto/trace br-int in_port=$inport $packet
+ as $hv ovs-appctl -t ovn-controller inject-pkt "$packet"
in_ls=`vif_to_ls $inport`
in_lrp=`vif_to_lrp $inport`
for outport; do
out_ls=`vif_to_ls $outport`
if test $in_ls = $out_ls; then
# Ports on the same logical switch receive exactly the same packet.
- echo $packet
+ echo $packet | ovstest test-ovn expr-to-packets
else
# Routing decrements TTL and updates source and dest MAC
# (and checksum).
out_lrp=`vif_to_lrp $outport`
- echo f00000000${outport}00000000ff${out_lrp}08004500001c00000000"3f1101"00${src_ip}${dst_ip}0035111100080000
+ exp_smac=`lrp_to_mac $out_lrp`
+ exp_dmac=`lsp_to_mac $outport`
+ exp_packet="eth.src==$exp_smac && eth.dst==$exp_dmac &&
+ ip.ttl==63 && ip4.src==$src_ip && ip4.dst==$dst_ip &&
+ icmp4.type==$icmp_type && icmp4.code==0"
+ echo $exp_packet | ovstest test-ovn expr-to-packets
+
fi >> $outport.expected
done
}
for ks in 1 2 3; do
bcast=
s=$is$js$ks
- smac=f00000000$s
- sip=`ip_to_hex 192 168 $is$js $ks`
+ slsp_mac=`lsp_to_mac $s`
+ slrp_mac=`lrp_to_mac $is$js`
+ sip=192.168.$is$js.$ks
for id in 1 2 3; do
for jd in 1 2 3; do
for kd in 1 2 3; do
d=$id$jd$kd
- dip=`ip_to_hex 192 168 $id$jd $kd`
- if test $is = $id; then dmac=f00000000$d; else dmac=00000000ff$is$js; fi
+ dlsp_mac=`lsp_to_mac $d`
+ dlrp_mac=`lrp_to_mac $id$jd`
+ dip=192.168.$id$jd.$kd
+ if test $is = $id; then dmac=$dlsp_mac; else dmac=$slrp_mac; fi
if test $d != $s; then unicast=$d; else unicast=; fi
# packets matches ACL1 but not ACL2 should be dropped
unicast=
fi
fi
- test_ip $s $smac $dmac $sip $dip $unicast #1
+ # icmp request (type = 8)
+ test_icmp $s $slsp_mac $dmac $sip $dip 8 $unicast
+
+ # if packets are not dropped, test the return traffic (icmp echo)
+ # to make sure stateful works, too.
+ if test x$unicast != x; then
+ if test $is = $id; then dmac=$slsp_mac; else dmac=$dlrp_mac; fi
+ # icmp echo (type = 0)
+ test_icmp $unicast $dlsp_mac $dmac $dip $sip 0 $s
+ fi
done
done
done
OVN_CLEANUP([hv1], [hv2], [hv3])
AT_CLEANUP
+AT_SETUP([ovn -- Address Set generation from Port Groups (static addressing)])
+ovn_start
+
+ovn-nbctl ls-add ls1
+
+ovn-nbctl lsp-add ls1 lp1
+ovn-nbctl lsp-add ls1 lp2
+ovn-nbctl lsp-add ls1 lp3
+
+ovn-nbctl lsp-set-addresses lp1 "02:00:00:00:00:01 10.0.0.1 2001:db8::1"
+ovn-nbctl lsp-set-addresses lp2 "02:00:00:00:00:02 10.0.0.2 2001:db8::2"
+ovn-nbctl lsp-set-addresses lp3 "02:00:00:00:00:03 10.0.0.3 2001:db8::3"
+
+ovn-nbctl create Port_Group name=pg1
+ovn-nbctl create Port_Group name=pg2
+
+ovn-nbctl --id=@p get Logical_Switch_Port lp1 -- add Port_Group pg1 ports @p
+ovn-nbctl --id=@p get Logical_Switch_Port lp2 -- add Port_Group pg1 ports @p
+ovn-nbctl --id=@p get Logical_Switch_Port lp2 -- add Port_Group pg2 ports @p
+ovn-nbctl --id=@p get Logical_Switch_Port lp3 -- add Port_Group pg2 ports @p
+
+ovn-nbctl --wait=sb sync
+
+dnl Check if port group address sets were populated with ports' addresses
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip4 addresses],
+ [0], [[["10.0.0.1", "10.0.0.2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg2_ip4 addresses],
+ [0], [[["10.0.0.2", "10.0.0.3"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip6 addresses],
+ [0], [[["2001:db8::1", "2001:db8::2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg2_ip6 addresses],
+ [0], [[["2001:db8::2", "2001:db8::3"]]
+])
+
+ovn-nbctl --wait=sb lsp-set-addresses lp1 \
+ "02:00:00:00:00:01 10.0.0.11 2001:db8::11"
+
+dnl Check if updated address got propagated to the port group address sets
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip4 addresses],
+ [0], [[["10.0.0.11", "10.0.0.2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip6 addresses],
+ [0], [[["2001:db8::11", "2001:db8::2"]]
+])
+
+AT_CLEANUP
+
+AT_SETUP([ovn -- Address Set generation from Port Groups (dynamic addressing)])
+ovn_start
+
+ovn-nbctl ls-add ls1
+ovn-nbctl ls-add ls2
+ovn-nbctl ls-add ls3
+
+ovn-nbctl set Logical_Switch ls1 \
+ other_config:subnet=10.1.0.0/24 other_config:ipv6_prefix="2001:db8:1::"
+ovn-nbctl set Logical_Switch ls2 \
+ other_config:subnet=10.2.0.0/24 other_config:ipv6_prefix="2001:db8:2::"
+ovn-nbctl set Logical_Switch ls3 \
+ other_config:subnet=10.3.0.0/24 other_config:ipv6_prefix="2001:db8:3::"
+
+ovn-nbctl lsp-add ls1 lp1
+ovn-nbctl lsp-add ls2 lp2
+ovn-nbctl lsp-add ls3 lp3
+
+ovn-nbctl lsp-set-addresses lp1 "02:00:00:00:00:01 dynamic"
+ovn-nbctl lsp-set-addresses lp2 "02:00:00:00:00:02 dynamic"
+ovn-nbctl lsp-set-addresses lp3 "02:00:00:00:00:03 dynamic"
+
+ovn-nbctl create Port_Group name=pg1
+ovn-nbctl create Port_Group name=pg2
+
+ovn-nbctl --id=@p get Logical_Switch_Port lp1 -- add Port_Group pg1 ports @p
+ovn-nbctl --id=@p get Logical_Switch_Port lp2 -- add Port_Group pg1 ports @p
+ovn-nbctl --id=@p get Logical_Switch_Port lp2 -- add Port_Group pg2 ports @p
+ovn-nbctl --id=@p get Logical_Switch_Port lp3 -- add Port_Group pg2 ports @p
+
+ovn-nbctl --wait=sb sync
+
+dnl Check if port group address sets were populated with ports' addresses
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip4 addresses],
+ [0], [[["10.1.0.2", "10.2.0.2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg2_ip4 addresses],
+ [0], [[["10.2.0.2", "10.3.0.2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip6 addresses],
+ [0], [[["2001:db8:1::ff:fe00:1", "2001:db8:2::ff:fe00:2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg2_ip6 addresses],
+ [0], [[["2001:db8:2::ff:fe00:2", "2001:db8:3::ff:fe00:3"]]
+])
+
+ovn-nbctl set Logical_Switch ls1 \
+ other_config:subnet=10.11.0.0/24 other_config:ipv6_prefix="2001:db8:11::"
+
+dnl Check if updated address got propagated to the port group address sets
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip4 addresses],
+ [0], [[["10.11.0.2", "10.2.0.2"]]
+])
+AT_CHECK([ovn-sbctl get Address_Set pg1_ip6 addresses],
+ [0], [[["2001:db8:11::ff:fe00:1", "2001:db8:2::ff:fe00:2"]]
+])
+
+AT_CLEANUP
+
AT_SETUP([ovn -- ACL conjunction])
ovn_start
as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
}
+# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_ROUTER EXP_ICMP_CHKSUM
+#
+# Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv6
+# packet with ETH_SRC, ETH_DST, IPV6_SRC and IPV6_DST as specified.
+# IPV6_ROUTER and EXP_ICMP_CHKSUM are the source IP and checksum of the icmpv6 ttl exceeded
+# packet sent by OVN logical router
+test_ip6_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_router=$7 exp_icmp_chksum=$8
+ shift 8
+
+ local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
+ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
+
+ local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}
+ echo $reply >> vif$inport.expected
+
+ as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
ip_to_hex() {
printf "%02x%02x%02x%02x" "$@"
}
ovn_attach n$i br-phys 192.168.$i.1
ovn-nbctl lsp-add sw$i sw$i-p${i}0 -- \
- lsp-set-addresses sw$i-p${i}0 "00:00:00:00:00:0$i 192.168.$i.1"
+ lsp-set-addresses sw$i-p${i}0 "00:00:00:00:00:0$i 192.168.$i.1 2001:db8:$i::11"
ovs-vsctl -- add-port br-int vif$i -- \
set interface vif$i \
ovn-nbctl lr-add lr0
for i in 1 2; do
- ovn-nbctl lrp-add lr0 lrp$i 00:00:00:00:ff:0$i 192.168.$i.254/24
+ ovn-nbctl lrp-add lr0 lrp$i 00:00:00:00:ff:0$i 192.168.$i.254/24 2001:db8:$i::1/64
ovn-nbctl -- lsp-add sw$i lrp$i-attachment \
-- set Logical_Switch_Port lrp$i-attachment type=router \
- options:router-port=lrp$i addresses='"00:00:00:00:ff:'0$i'"'
+ options:router-port=lrp$i addresses='"00:00:00:00:ff:0'$i' 192.168.'$i'.254 2001:db8:'$i'::1"'
done
OVN_POPULATE_ARP
ovn-nbctl --wait=hv sync
test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 7dae f4ff
+test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 d461
OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
OVN_CLEANUP([hv1], [hv2])
AT_CLEANUP
+
+AT_SETUP([ovn -- router port unreachable])
+AT_KEYWORDS([router-port-unreachable])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_ROUTER L4_PROTCOL IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM EXP_ICMP_CODE
+#
+# Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv4 packet with
+# ETH_SRC, ETH_DST, IPV4_SRC, IPV4_ROUTER, L4_PROTCOL, IP_CHKSUM as specified.
+# EXP_IP_CHKSUM and EXP_ICMP_CHKSUM are the ip and icmp checksums of the icmp frame generated by OVN logical router
+# EXP_ICMP_CODE are code and type of the icmp frame generated by OVN logical router
+#
+# INPORT is a lport number, e.g. 11 for vif11.
+# HV is a hypervisor number
+# ETH_SRC and ETH_DST are each 12 hex digits.
+# IPV4_SRC and IPV4_ROUTER are each 8 hex digits.
+# IP_CHKSUM, EXP_IP_CHSUM and EXP_ICMP_CHKSUM are each 4 hex digits
+test_ip_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ip_router=$6 l4_proto=$7 ip_chksum=$8
+ local exp_ip_chksum=$9 exp_icmp_chksum=${10} exp_icmp_code=${11}
+ shift 11
+
+ local ip_ttl=ff
+ local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router}
+
+ local reply_icmp_ttl=fe
+ local icmp_data=00000000
+ local reply_icmp_payload=${exp_icmp_code}${exp_icmp_chksum}${icmp_data}
+ local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
+ echo $reply >> vif$inport.expected
+
+ as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
+# test_tcp_syn_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_ROUTER IP_CHKSUM TCP_SPORT TCP_DPORT TCP_CHKSUM EXP_IP_CHKSUM EXP_TCP_RST_CHKSUM
+#
+# Causes a packet to be received on INPORT of the hypervisor HV. The packet is an TCP syn segment with
+# ETH_SRC, ETH_DST, IPV4_SRC, IPV4_ROUTER, IP_CHKSUM, TCP_SPORT, TCP_DPORT, TCP_CHKSUM as specified.
+# EXP_IP_CHKSUM and EXP_TCP_RST_CHKSUM are the ip and tcp checksums of the tcp reset segment generated by OVN logical router
+#
+# INPORT is an lport number, e.g. 11 for vif11.
+# HV is an hypervisor number
+# ETH_SRC and ETH_DST are each 12 hex digits.
+# IPV4_SRC and IPV4_ROUTER are each 8 hex digits.
+# TCP_SPORT and TCP_DPORT are 4 hex digits.
+# IP_CHKSUM, TCP_CHKSUM, EXP_IP_CHSUM and EXP_TCP_RST_CHKSUM are each 4 hex digits
+test_tcp_syn_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ip_router=$6 ip_chksum=$7
+ local tcp_sport=$8 tcp_dport=$9 tcp_chksum=${10}
+ local exp_ip_chksum=${11} exp_tcp_rst_chksum=${12}
+ shift 12
+
+ local ip_ttl=ff
+ local packet=${eth_dst}${eth_src}08004500002800004000${ip_ttl}06${ip_chksum}${ipv4_src}${ip_router}${tcp_sport}${tcp_dport}000000010000000050027210${tcp_chksum}0000
+
+ local tcp_rst_ttl=fe
+ local reply=${eth_src}${eth_dst}08004500002800004000${tcp_rst_ttl}06${exp_ip_chksum}${ip_router}${ipv4_src}${tcp_dport}${tcp_sport}000000000000000150040000${exp_tcp_rst_chksum}0000
+ echo $reply >> vif$inport.expected
+
+ as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
+# test_tcp6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_ROUTER TCP_SPORT TCP_DPORT TCP_CHKSUM EXP_TCP_RST_CHKSUM
+#
+# Causes a packet to be received on INPORT of the hypervisor HV. The packet is a TCP syn segment with
+# ETH_SRC, ETH_DST, IPV6_SRC, IPV6_ROUTER, TCP_SPORT, TCP_DPORT and TCP_CHKSUM as specified.
+# EXP_TCP_RST_CHKSUM is the tcp checksums of the tcp reset segment generated by OVN logical router
+test_tcp6_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_router=$6
+ local tcp_sport=$7 tcp_dport=$8 tcp_chksum=$9
+ local exp_tcp_rst_chksum=${10}
+ shift 10
+
+ local ip6_hdr=60000000001406ff${ipv6_src}${ipv6_router}
+ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${tcp_sport}${tcp_dport}000000010000000050027210${tcp_chksum}0000
+
+ local reply=${eth_src}${eth_dst}86dd60000000001406fe${ipv6_router}${ipv6_src}${tcp_dport}${tcp_sport}000000000000000150040000${exp_tcp_rst_chksum}0000
+ echo $reply >> vif$inport.expected
+
+ as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
+# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_PROTO IPV6_LEN DATA EXP_ICMP_CODE EXP_ICMP_CHKSUM
+#
+# Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv6
+# packet with ETH_SRC, ETH_DST, IPV6_SRC, IPV6_DST, IPV6_PROTO, IPV6_LEN and DATA as specified.
+# EXP_ICMP_CODE and EXP_ICMP_CHKSUM are the code and checksum of the icmp6 packet sent by OVN logical router
+test_ip6_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_proto=$7 ipv6_len=$8 data=$9
+ local exp_icmp_code=${10} exp_icmp_chksum=${11}
+ shift 11
+
+ local ip6_hdr=60000000${ipv6_len}${ipv6_proto}ff${ipv6_src}${ipv6_dst}
+ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${data}
+
+ local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}
+ echo $reply >> vif$inport.expected
+
+ as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
+}
+
+ip_to_hex() {
+ printf "%02x%02x%02x%02x" "$@"
+}
+
+for i in 1 2; do
+ net_add n$i
+ ovn-nbctl ls-add sw$i
+
+ sim_add hv$i
+ as hv$i
+ ovs-vsctl add-br br-phys
+ ovn_attach n$i br-phys 192.168.$i.1
+
+ ovn-nbctl lsp-add sw$i sw$i-p${i}0 -- \
+ lsp-set-addresses sw$i-p${i}0 "00:00:00:00:00:0$i 192.168.$i.1 2001:db8:$i::11"
+
+ ovs-vsctl -- add-port br-int vif$i -- \
+ set interface vif$i \
+ external-ids:iface-id=sw$i-p${i}0 \
+ options:tx_pcap=hv$i/vif$i-tx.pcap \
+ options:rxq_pcap=hv$i/vif$i-rx.pcap \
+ ofport-request=$i
+done
+
+ovn-nbctl lr-add lr0
+for i in 1 2; do
+ ovn-nbctl lrp-add lr0 lrp$i 00:00:00:00:ff:0$i 192.168.$i.254/24 2001:db8:$i::1/64
+ ovn-nbctl -- lsp-add sw$i lrp$i-attachment \
+ -- set Logical_Switch_Port lrp$i-attachment type=router \
+ options:router-port=lrp$i addresses='"00:00:00:00:ff:0'$i' 192.168.'$i'.254 2001:db8:'$i'::1"'
+done
+
+OVN_POPULATE_ARP
+# allow some time for ovn-northd and ovn-controller to catch up.
+ovn-nbctl --wait=hv sync
+
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 7dae fcfc 0303
+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 7dae fcfd 0302
+test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 d570
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
+
+test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 7bae 4486
+test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 627e
+test_tcp6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 8b40 3039 0000 4486
+OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected])
+
+OVN_CLEANUP([hv1], [hv2])
+AT_CLEANUP
+
+AT_SETUP([ovn -- ovn-controller exit])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+# Logical network:
+# One Logical Router: ro, with two logical switches sw1 and sw2.
+# sw1 is for subnet 10.0.0.0/8
+# sw2 is for subnet 20.0.0.0/8
+# sw1 has a single port bound on hv1
+# sw2 has a single port bound on hv2
+
+ovn-nbctl lr-add ro
+ovn-nbctl ls-add sw1
+ovn-nbctl ls-add sw2
+
+sw1_ro_mac=00:00:10:00:00:01
+sw1_ro_ip=10.0.0.1
+sw2_ro_mac=00:00:20:00:00:01
+sw2_ro_ip=20.0.0.1
+sw1_p1_mac=00:00:10:00:00:02
+sw1_p1_ip=10.0.0.2
+sw2_p1_mac=00:00:20:00:00:02
+sw2_p1_ip=20.0.0.2
+
+ovn-nbctl lrp-add ro ro-sw1 $sw1_ro_mac ${sw1_ro_ip}/8
+ovn-nbctl lrp-add ro ro-sw2 $sw2_ro_mac ${sw2_ro_ip}/8
+ovn-nbctl lsp-add sw1 sw1-ro -- set Logical_Switch_Port sw1-ro type=router \
+ options:router-port=ro-sw1 addresses=\"$sw1_ro_mac\"
+ovn-nbctl lsp-add sw2 sw2-ro -- set Logical_Switch_Port sw2-ro type=router \
+ options:router-port=ro-sw2 addresses=\"$sw2_ro_mac\"
+
+ovn-nbctl lsp-add sw1 sw1-p1 \
+-- lsp-set-addresses sw1-p1 "$sw1_p1_mac $sw1_p1_ip"
+
+ovn-nbctl lsp-add sw2 sw2-p1 \
+-- lsp-set-addresses sw2-p1 "$sw2_p1_mac $sw2_p1_ip"
+
+net_add n1
+
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=sw1-p1 \
+ options:tx_pcap=hv1/vif1-tx.pcap \
+ options:rxq_pcap=hv1/vif1-rx.pcap \
+ ofport-request=1
+
+sim_add hv2
+as hv2
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.2
+ovs-vsctl -- add-port br-int hv2-vif1 -- \
+ set interface hv2-vif1 external-ids:iface-id=sw2-p1 \
+ options:tx_pcap=hv2/vif1-tx.pcap \
+ options:rxq_pcap=hv2/vif1-rx.pcap \
+ ofport-request=1
+
+OVN_POPULATE_ARP
+
+sleep 1
+
+packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac &&
+ ip4 && ip.ttl==64 && ip4.src==$sw1_p1_ip && ip4.dst==$sw2_p1_ip &&
+ udp && udp.src==53 && udp.dst==4369"
+
+# Start by Sending the packet and make sure it makes it there as expected
+as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
+
+# Expected packet has TTL decreased by 1
+expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac &&
+ ip4 && ip.ttl==63 && ip4.src==$sw1_p1_ip && ip4.dst==$sw2_p1_ip &&
+ udp && udp.src==53 && udp.dst==4369"
+echo $expected | ovstest test-ovn expr-to-packets > expected
+
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+
+# Stop ovn-controller on hv2
+as hv2 ovs-appctl -t ovn-controller exit
+
+# Now send the packet again. This time, it should not arrive.
+as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
+
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+
+# Start ovn-controller again just so OVN_CLEANUP doesn't complain
+as hv2 start_daemon ovn-controller
+
+OVN_CLEANUP([hv1],[hv2])
+AT_CLEANUP
+
+AT_SETUP([ovn -- ovn-controller restart])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# Logical network:
+# One Logical Router: ro, with two logical switches sw1 and sw2.
+# sw1 is for subnet 10.0.0.0/8
+# sw2 is for subnet 20.0.0.0/8
+# sw1 has a single port bound on hv1
+# sw2 has a single port bound on hv2
+
+ovn-nbctl lr-add ro
+ovn-nbctl ls-add sw1
+ovn-nbctl ls-add sw2
+
+sw1_ro_mac=00:00:10:00:00:01
+sw1_ro_ip=10.0.0.1
+sw2_ro_mac=00:00:20:00:00:01
+sw2_ro_ip=20.0.0.1
+sw1_p1_mac=00:00:10:00:00:02
+sw1_p1_ip=10.0.0.2
+sw2_p1_mac=00:00:20:00:00:02
+sw2_p1_ip=20.0.0.2
+
+ovn-nbctl lrp-add ro ro-sw1 $sw1_ro_mac ${sw1_ro_ip}/8
+ovn-nbctl lrp-add ro ro-sw2 $sw2_ro_mac ${sw2_ro_ip}/8
+ovn-nbctl lsp-add sw1 sw1-ro -- set Logical_Switch_Port sw1-ro type=router \
+ options:router-port=ro-sw1 addresses=\"$sw1_ro_mac\"
+ovn-nbctl lsp-add sw2 sw2-ro -- set Logical_Switch_Port sw2-ro type=router \
+ options:router-port=ro-sw2 addresses=\"$sw2_ro_mac\"
+
+ovn-nbctl lsp-add sw1 sw1-p1 \
+-- lsp-set-addresses sw1-p1 "$sw1_p1_mac $sw1_p1_ip"
+
+ovn-nbctl lsp-add sw2 sw2-p1 \
+-- lsp-set-addresses sw2-p1 "$sw2_p1_mac $sw2_p1_ip"
+
+net_add n1
+
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=sw1-p1 \
+ options:tx_pcap=hv1/vif1-tx.pcap \
+ options:rxq_pcap=hv1/vif1-rx.pcap \
+ ofport-request=1
+
+sim_add hv2
+as hv2
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.2
+ovs-vsctl -- add-port br-int hv2-vif1 -- \
+ set interface hv2-vif1 external-ids:iface-id=sw2-p1 \
+ options:tx_pcap=hv2/vif1-tx.pcap \
+ options:rxq_pcap=hv2/vif1-rx.pcap \
+ ofport-request=1
+
+OVN_POPULATE_ARP
+
+sleep 1
+
+packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac &&
+ ip4 && ip.ttl==64 && ip4.src==$sw1_p1_ip && ip4.dst==$sw2_p1_ip &&
+ udp && udp.src==53 && udp.dst==4369"
+
+# Start by Sending the packet and make sure it makes it there as expected
+as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
+
+# Expected packet has TTL decreased by 1
+expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac &&
+ ip4 && ip.ttl==63 && ip4.src==$sw1_p1_ip && ip4.dst==$sw2_p1_ip &&
+ udp && udp.src==53 && udp.dst==4369"
+echo $expected | ovstest test-ovn expr-to-packets > expected
+
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+
+# Stop ovn-controller on hv2 with --restart flag
+as hv2 ovs-appctl -t ovn-controller exit --restart
+
+# Now send the packet again. This time, it should still arrive
+as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
+
+cat expected expected > expected2
+
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected2])
+
+# Start ovn-controller again just so OVN_CLEANUP doesn't complain
+as hv2 start_daemon ovn-controller
+
+OVN_CLEANUP([hv1],[hv2])
+
+AT_CLEANUP
+
+AT_SETUP([ovn -- ovn-nbctl duplicate addresses])
+ovn_start
+
+# Set up a switch with some switch ports of varying address types
+ovn-nbctl ls-add sw1
+ovn-nbctl set logical_switch sw1 other_config:subnet=192.168.0.0/24
+
+ovn-nbctl lsp-add sw1 sw1-p1
+ovn-nbctl lsp-add sw1 sw1-p2
+ovn-nbctl lsp-add sw1 sw1-p3
+ovn-nbctl lsp-add sw1 sw1-p4
+
+ovn-nbctl lsp-set-addresses sw1-p1 "00:00:00:00:00:01 10.0.0.1 aef0::1" "00:00:00:00:00:02 10.0.0.2 aef0::2"
+ovn-nbctl lsp-set-addresses sw1-p2 "00:00:00:00:00:03 dynamic"
+ovn-nbctl lsp-set-addresses sw1-p3 "dynamic"
+ovn-nbctl lsp-set-addresses sw1-p4 "router"
+ovn-nbctl lsp-set-addresses sw1-p5 "unknown"
+
+ovn-nbctl list logical_switch_port
+
+# Now try to add duplicate addresses on a new port. These should all fail
+ovn-nbctl lsp-add sw1 sw1-p5
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 10.0.0.1"], [1], [],
+[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 10.0.0.1
+])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 10.0.0.2"], [1], [],
+[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 10.0.0.2
+])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 aef0::1"], [1], [],
+[ovn-nbctl: Error on switch sw1: duplicate IPv6 address aef0::1
+])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 aef0::2"], [1], [],
+[ovn-nbctl: Error on switch sw1: duplicate IPv6 address aef0::2
+])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 192.168.0.2"], [1], [],
+[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 192.168.0.2
+])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p5 "00:00:00:00:00:04 192.168.0.3"], [1], [],
+[ovn-nbctl: Error on switch sw1: duplicate IPv4 address 192.168.0.3
+])
+
+# Now try re-setting sw1-p1. This should succeed
+AT_CHECK([ovn-nbctl lsp-set-addresses sw1-p1 "00:00:00:00:00:01 10.0.0.1 aef0::1"])
+
+# Now create a new switch and try setting IP addresses the same as the
+# first switch. This should succeed.
+ovn-nbctl ls-add sw2
+ovn-nbctl lsp-add sw2 sw2-p1
+
+AT_CHECK([ovn-nbctl lsp-set-addresses sw2-p1 "00:00:00:00:00:04 10.0.0.1"])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw2-p1 "00:00:00:00:00:04 192.168.0.2"])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw2-p1 "00:00:00:00:00:04 192.168.0.3"])
+AT_CHECK([ovn-nbctl lsp-set-addresses sw2-p1 "00:00:00:00:00:04 aef0::1"])
+
+AT_CLEANUP
+
+AT_SETUP([ovn -- IP packet buffering])
+AT_KEYWORDS([ip-buffering])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# Logical network:
+# One LR lr0 that has switches sw0 (192.168.1.0/24) and
+# sw1 (172.16.1.0/24) connected to it.
+#
+# Physical network:
+# Tw0 hypervisors hv[12].
+# hv1 hosts vif sw0-p0.
+# hv1 hosts vif sw1-p0.
+
+send_icmp_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6 ip_chksum=$7 data=$8
+ shift 8
+
+ local ip_ttl=ff
+ local ip_len=001c
+ local packet=${eth_dst}${eth_src}08004500${ip_len}00004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}${data}
+ as hv$hv ovs-appctl netdev-dummy/receive hv$hv-vif$inport $packet
+}
+
+send_icmp6_packet() {
+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_router=$7 exp_icmp_chksum=$8
+ shift 8
+
+ local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
+ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000dcb662f00001
+
+ as hv$hv ovs-appctl netdev-dummy/receive hv$hv-vif$inport $packet
+}
+
+get_arp_req() {
+ local eth_src=$1 spa=$2 tpa=$3
+ local request=ffffffffffff${eth_src}08060001080006040001${eth_src}${spa}000000000000${tpa}
+ echo $request
+}
+
+send_arp_reply() {
+ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6
+ local request=${eth_dst}${eth_src}08060001080006040002${eth_src}${spa}${eth_dst}${tpa}
+ as hv$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $request
+}
+
+send_na() {
+ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 src_ip=$5 dst_ip=$6
+ local ip6_hdr=6000000000203aff${src_ip}${dst_ip}
+ local request=${eth_dst}${eth_src}86dd${ip6_hdr}8800d78440000000${src_ip}0201${eth_src}
+
+ as hv$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $request
+}
+
+get_nd() {
+ local eth_src=$1 src_ip=$2 dst_ip=$3 ta=$4
+ local ip6_hdr=6000000000203aff${src_ip}${dst_ip}
+ request=3333ff000010${eth_src}86dd${ip6_hdr}8700357600000000${ta}0101${eth_src}
+
+ echo $request
+}
+
+net_add n1
+
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=sw0-p0 \
+ options:tx_pcap=hv1/vif1-tx.pcap \
+ options:rxq_pcap=hv1/vif1-rx.pcap \
+ ofport-request=1
+
+sim_add hv2
+as hv2
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.2
+ovs-vsctl -- add-port br-int hv2-vif1 -- \
+ set interface hv2-vif1 external-ids:iface-id=sw1-p0 \
+ options:tx_pcap=hv2/vif1-tx.pcap \
+ options:rxq_pcap=hv2/vif1-rx.pcap \
+ ofport-request=1
+
+ovn-nbctl create Logical_Router name=lr0 options:chassis=hv1
+ovn-nbctl ls-add sw0
+ovn-nbctl ls-add sw1
+
+ovn-nbctl lrp-add lr0 sw0 00:00:01:01:02:03 192.168.1.1/24 2001::1/64
+ovn-nbctl lsp-add sw0 rp-sw0 -- set Logical_Switch_Port rp-sw0 \
+ type=router options:router-port=sw0 \
+ -- lsp-set-addresses rp-sw0 router
+
+ovn-nbctl lrp-add lr0 sw1 00:00:02:01:02:03 172.16.1.1/24 2002::1/64
+ovn-nbctl lsp-add sw1 rp-sw1 -- set Logical_Switch_Port rp-sw1 \
+ type=router options:router-port=sw1 \
+ -- lsp-set-addresses rp-sw1 router
+
+ovn-nbctl lsp-add sw0 sw0-p0 \
+ -- lsp-set-addresses sw0-p0 "f0:00:00:01:02:03 192.168.1.2 2001::2"
+
+ovn-nbctl lsp-add sw1 sw1-p0 \
+ -- lsp-set-addresses sw1-p0 unknown
+
+OVN_POPULATE_ARP
+ovn-nbctl --wait=hv sync
+
+ip_to_hex() {
+ printf "%02x%02x%02x%02x" "$@"
+}
+
+src_mac=f00000010203
+src_ip=$(ip_to_hex 192 168 1 2)
+src_ip6=20010000000000000000000000000002
+
+router_mac0=000001010203
+router_mac1=000002010203
+router_ip=$(ip_to_hex 172 16 1 1)
+router_ip6=20020000000000000000000000000001
+
+dst_mac=001122334455
+dst_ip=$(ip_to_hex 172 16 1 10)
+dst_ip6=20020000000000000000000000000010
+
+data=0800bee4391a0001
+
+send_icmp_packet 1 1 $src_mac $router_mac0 $src_ip $dst_ip 0000 $data
+send_arp_reply 2 1 $dst_mac $router_mac1 $dst_ip $router_ip
+echo $(get_arp_req $router_mac1 $router_ip $dst_ip) > expected
+echo "${dst_mac}${router_mac1}08004500001c00004000fe010100${src_ip}${dst_ip}${data}" >> expected
+
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+
+nd_ip=ff0200000000000000000001ff000010
+ip6_hdr=6000000000083afe${src_ip6}${dst_ip6}
+
+send_icmp6_packet 1 1 $src_mac $router_mac0 $src_ip6 $dst_ip6
+echo $(get_nd $router_mac1 $src_ip6 $nd_ip $dst_ip6) >> expected
+echo "${dst_mac}${router_mac1}86dd${ip6_hdr}8000dcb662f00001" >> expected
+send_na 2 1 $dst_mac $router_mac1 $dst_ip6 $router_ip6
+
+OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+
+OVN_CLEANUP([hv1],[hv2])
+AT_CLEANUP
+
+AT_SETUP([ovn -- neighbor update on same HV])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# Logical network:
+# A public switch (pub) with a localnet port connected to two LRs (lr0 and lr1)
+# each with a distributed gateway port.
+# Two VMs: lp0 on sw0 connected to lr0
+# lp1 on sw1 connected to lr1
+#
+# This test adds a floating IP to each VM so when they are bound to the same
+# hypervisor, it checks that the GARP sent by ovn-controller causes the
+# MAC_Binding entries to be updated properly on each logical router.
+# It will also capture packets on the physical interface to make sure that the
+# GARPs have been sent out to the external network as well.
+
+# Create logical switches
+ovn-nbctl ls-add sw0
+ovn-nbctl ls-add sw1
+ovn-nbctl ls-add pub
+
+# Created localnet port on public switch
+ovn-nbctl lsp-add pub ln-pub
+ovn-nbctl lsp-set-type ln-pub localnet
+ovn-nbctl lsp-set-addresses ln-pub unknown
+ovn-nbctl lsp-set-options ln-pub network_name=phys
+
+# Create logical routers and connect them to public switch
+ovn-nbctl create Logical_Router name=lr0
+ovn-nbctl create Logical_Router name=lr1
+
+ovn-nbctl lrp-add lr0 lr0-pub f0:00:00:00:00:01 172.24.4.220/24
+ovn-nbctl lsp-add pub pub-lr0 -- set Logical_Switch_Port pub-lr0 \
+ type=router options:router-port=lr0-pub options:nat-addresses="router" addresses="router"
+ovn-nbctl lrp-add lr1 lr1-pub f0:00:00:00:01:01 172.24.4.221/24
+ovn-nbctl lsp-add pub pub-lr1 -- set Logical_Switch_Port pub-lr1 \
+ type=router options:router-port=lr1-pub options:nat-addresses="router" addresses="router"
+
+ovn-nbctl lrp-set-gateway-chassis lr0-pub hv1 10
+ovn-nbctl lrp-set-gateway-chassis lr1-pub hv1 10
+
+# Connect sw0 and sw1 to lr0 and lr1
+ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.254/24
+ovn-nbctl lsp-add sw0 sw0-lr0 -- set Logical_Switch_Port sw0-lr0 type=router \
+ options:router-port=lr0-sw0 addresses="router"
+ovn-nbctl lrp-add lr1 lr1-sw1 00:00:00:00:ff:02 20.0.0.254/24
+ovn-nbctl lsp-add sw1 sw1-lr1 -- set Logical_Switch_Port sw1-lr1 type=router \
+ options:router-port=lr1-sw1 addresses="router"
+
+
+# Add SNAT rules
+ovn-nbctl lr-nat-add lr0 snat 172.24.4.220 10.0.0.0/24
+ovn-nbctl lr-nat-add lr1 snat 172.24.4.221 20.0.0.0/24
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 172.24.4.1
+ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+
+ovs-vsctl add-port br-int vif0 -- set Interface vif0 external-ids:iface-id=lp0
+ovs-vsctl add-port br-int vif1 -- set Interface vif1 external-ids:iface-id=lp1
+
+ovn-nbctl lsp-add sw0 lp0
+ovn-nbctl lsp-add sw1 lp1
+ovn-nbctl lsp-set-addresses lp0 "50:54:00:00:00:01 10.0.0.10"
+ovn-nbctl lsp-set-addresses lp1 "50:54:00:00:00:02 20.0.0.10"
+
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up lp0` = xup])
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up lp1` = xup])
+
+# Create two floating IPs, one for each VIF
+ovn-nbctl lr-nat-add lr0 dnat_and_snat 172.24.4.100 10.0.0.10
+ovn-nbctl lr-nat-add lr1 dnat_and_snat 172.24.4.200 20.0.0.10
+
+# Check that the MAC_Binding entries have been properly created
+OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding logical_port="lr0-pub" ip="172.24.4.200" | wc -l` -gt 0])
+OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding logical_port="lr1-pub" ip="172.24.4.100" | wc -l` -gt 0])
+
+# Check that the GARPs went also to the external physical network
+# Wait until at least 4 packets have arrived and copy them to a separate file as
+# more GARPs are expected in the capture in order to avoid race conditions.
+OVS_WAIT_UNTIL([test `$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys-tx.pcap | wc -l` -gt 4])
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys-tx.pcap | head -n4 > hv1/br-phys-tx4.pcap
+
+# GARP for lp0 172.24.4.100 on lr0-pub MAC (f0:00:00:00:00:01)
+echo "fffffffffffff0000000000108060001080006040001f00000000001ac180464000000000000ac180464" > expout
+# GARP for 172.24.4.220 on lr0-pub (f0:00:00:00:00:01)
+echo "fffffffffffff0000000000108060001080006040001f00000000001ac1804dc000000000000ac1804dc" >> expout
+# GARP for lp1 172.24.4.200 on lr1-pub MAC (f0:00:00:00:01:01)
+echo "fffffffffffff0000000010108060001080006040001f00000000101ac1804c8000000000000ac1804c8" >> expout
+# GARP for 172.24.4.221 on lr1-pub (f0:00:00:00:01:01)
+echo "fffffffffffff0000000010108060001080006040001f00000000101ac1804dd000000000000ac1804dd" >> expout
+AT_CHECK([sort hv1/br-phys-tx4.pcap], [0], [expout])
+#OVN_CHECK_PACKETS([hv1/br-phys-tx4.pcap], [br-phys.expected])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP