bbaaef
From 7d45e142d6d1d964ff76b66db78d5e47267fe6b2 Mon Sep 17 00:00:00 2001
bbaaef
From: Ankur Sharma <ankur.sharma@nutanix.com>
bbaaef
Date: Sat, 17 Aug 2019 00:36:43 +0000
bbaaef
Subject: [PATCH 01/12] OVN: Do not replace router port mac on gateway chassis.
bbaaef
bbaaef
With 795d7f24ce0e2ed5454e193a059451d237289542 we have added
bbaaef
support for E-W routing on vlan backed networks by replacing
bbaaef
router port macs with chassis macs.
bbaaef
bbaaef
This replacement of router port mac need NOT be done on
bbaaef
gateway chassis for following reasons:
bbaaef
bbaaef
a. For N-S traffic, gateway chassis will respond to ARP
bbaaef
for the router port (to which it is attached) and
bbaaef
traffic will be using router port mac as destination mac.
bbaaef
bbaaef
b. Chassis redirect port is a centralized version of distributed
bbaaef
router port, hence we need not replace its mac with chassis mac
bbaaef
on the resident chassis.
bbaaef
bbaaef
This patch addresses the same.
bbaaef
bbaaef
Signed-off-by: Ankur Sharma <ankur.sharma@nutanix.com>
bbaaef
Signed-off-by: Numan Siddique <nusiddiq@redhat.com>
bbaaef
bbaaef
(cherry-picked from upstream ovn commit 26cdf840108495316f2b53b17b8d3810489e52cb)
bbaaef
bbaaef
Change-Id: I2e0c712595209fb49ae6e5b90a6b0bf096509dc7
bbaaef
---
bbaaef
 ovn/controller/lport.c    |  20 +++
bbaaef
 ovn/controller/lport.h    |   6 +
bbaaef
 ovn/controller/physical.c |  18 ++-
bbaaef
 ovn/controller/pinctrl.c  |  20 +--
bbaaef
 tests/ovn.at              | 320 ++++++++++++++++++++++++++++++++++++++
bbaaef
 5 files changed, 363 insertions(+), 21 deletions(-)
bbaaef
bbaaef
diff --git a/ovn/controller/lport.c b/ovn/controller/lport.c
bbaaef
index cc5c5fbb2..3cf54d16f 100644
bbaaef
--- a/ovn/controller/lport.c
bbaaef
+++ b/ovn/controller/lport.c
bbaaef
@@ -17,6 +17,7 @@
bbaaef
 
bbaaef
 #include "lib/sset.h"
bbaaef
 #include "lport.h"
bbaaef
+#include "ha-chassis.h"
bbaaef
 #include "hash.h"
bbaaef
 #include "openvswitch/vlog.h"
bbaaef
 #include "ovn/lib/ovn-sb-idl.h"
bbaaef
@@ -64,6 +65,25 @@ lport_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
bbaaef
     return retval;
bbaaef
 }
bbaaef
 
bbaaef
+bool
bbaaef
+lport_is_chassis_resident(struct ovsdb_idl_index *sbrec_port_binding_by_name,
bbaaef
+                          const struct sbrec_chassis *chassis,
bbaaef
+                          const struct sset *active_tunnels,
bbaaef
+                          const char *port_name)
bbaaef
+{
bbaaef
+    const struct sbrec_port_binding *pb
bbaaef
+        = lport_lookup_by_name(sbrec_port_binding_by_name, port_name);
bbaaef
+    if (!pb || !pb->chassis) {
bbaaef
+        return false;
bbaaef
+    }
bbaaef
+    if (strcmp(pb->type, "chassisredirect")) {
bbaaef
+        return pb->chassis == chassis;
bbaaef
+    } else {
bbaaef
+        return ha_chassis_group_is_active(pb->ha_chassis_group,
bbaaef
+                                          active_tunnels, chassis);
bbaaef
+    }
bbaaef
+}
bbaaef
+
bbaaef
 const struct sbrec_datapath_binding *
bbaaef
 datapath_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
bbaaef
                        uint64_t dp_key)
bbaaef
diff --git a/ovn/controller/lport.h b/ovn/controller/lport.h
bbaaef
index 7dcd5bee0..89e3b85eb 100644
bbaaef
--- a/ovn/controller/lport.h
bbaaef
+++ b/ovn/controller/lport.h
bbaaef
@@ -23,6 +23,7 @@ struct sbrec_chassis;
bbaaef
 struct sbrec_datapath_binding;
bbaaef
 struct sbrec_multicast_group;
bbaaef
 struct sbrec_port_binding;
bbaaef
+struct sset;
bbaaef
 
bbaaef
 
bbaaef
 /* Database indexes.
bbaaef
@@ -49,4 +50,9 @@ const struct sbrec_multicast_group *mcgroup_lookup_by_dp_name(
bbaaef
     struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
bbaaef
     const struct sbrec_datapath_binding *, const char *name);
bbaaef
 
bbaaef
+bool
bbaaef
+lport_is_chassis_resident(struct ovsdb_idl_index *sbrec_port_binding_by_name,
bbaaef
+                          const struct sbrec_chassis *chassis,
bbaaef
+                          const struct sset *active_tunnels,
bbaaef
+                          const char *port_name);
bbaaef
 #endif /* ovn/lport.h */
bbaaef
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
bbaaef
index 7ad3e6f8f..425110d0b 100644
bbaaef
--- a/ovn/controller/physical.c
bbaaef
+++ b/ovn/controller/physical.c
bbaaef
@@ -228,9 +228,12 @@ get_zone_ids(const struct sbrec_port_binding *binding,
bbaaef
 }
bbaaef
 
bbaaef
 static void
bbaaef
-put_replace_router_port_mac_flows(const struct
bbaaef
+put_replace_router_port_mac_flows(struct ovsdb_idl_index
bbaaef
+                                  *sbrec_port_binding_by_name,
bbaaef
+                                  const struct
bbaaef
                                   sbrec_port_binding *localnet_port,
bbaaef
                                   const struct sbrec_chassis *chassis,
bbaaef
+                                  const struct sset *active_tunnels,
bbaaef
                                   const struct hmap *local_datapaths,
bbaaef
                                   struct ofpbuf *ofpacts_p,
bbaaef
                                   ofp_port_t ofport,
bbaaef
@@ -270,6 +273,16 @@ put_replace_router_port_mac_flows(const struct
bbaaef
         struct eth_addr router_port_mac;
bbaaef
         struct match match;
bbaaef
         struct ofpact_mac *replace_mac;
bbaaef
+        char *cr_peer_name = xasprintf("cr-%s", rport_binding->logical_port);
bbaaef
+        if (lport_is_chassis_resident(sbrec_port_binding_by_name,
bbaaef
+                                      chassis, active_tunnels,
bbaaef
+                                      cr_peer_name)) {
bbaaef
+            /* If a router port's chassisredirect port is
bbaaef
+             * resident on this chassis, then we need not do mac replace. */
bbaaef
+            free(cr_peer_name);
bbaaef
+            continue;
bbaaef
+        }
bbaaef
+        free(cr_peer_name);
bbaaef
 
bbaaef
         /* Table 65, priority 150.
bbaaef
          * =======================
bbaaef
@@ -787,7 +800,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
bbaaef
                         &match, ofpacts_p, &binding->header_.uuid);
bbaaef
 
bbaaef
         if (!strcmp(binding->type, "localnet")) {
bbaaef
-            put_replace_router_port_mac_flows(binding, chassis,
bbaaef
+            put_replace_router_port_mac_flows(sbrec_port_binding_by_name,
bbaaef
+                                              binding, chassis, active_tunnels,
bbaaef
                                               local_datapaths, ofpacts_p,
bbaaef
                                               ofport, flow_table);
bbaaef
         }
bbaaef
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
bbaaef
index 25b18789e..c6dd69fb3 100644
bbaaef
--- a/ovn/controller/pinctrl.c
bbaaef
+++ b/ovn/controller/pinctrl.c
bbaaef
@@ -3950,24 +3950,6 @@ get_localnet_vifs_l3gwports(
bbaaef
     sbrec_port_binding_index_destroy_row(target);
bbaaef
 }
bbaaef
 
bbaaef
-static bool
bbaaef
-pinctrl_is_chassis_resident(struct ovsdb_idl_index *sbrec_port_binding_by_name,
bbaaef
-                            const struct sbrec_chassis *chassis,
bbaaef
-                            const struct sset *active_tunnels,
bbaaef
-                            const char *port_name)
bbaaef
-{
bbaaef
-    const struct sbrec_port_binding *pb
bbaaef
-        = lport_lookup_by_name(sbrec_port_binding_by_name, port_name);
bbaaef
-    if (!pb || !pb->chassis) {
bbaaef
-        return false;
bbaaef
-    }
bbaaef
-    if (strcmp(pb->type, "chassisredirect")) {
bbaaef
-        return pb->chassis == chassis;
bbaaef
-    } else {
bbaaef
-        return ha_chassis_group_is_active(pb->ha_chassis_group,
bbaaef
-                                          active_tunnels, chassis);
bbaaef
-    }
bbaaef
-}
bbaaef
 
bbaaef
 /* Extracts the mac, IPv4 and IPv6 addresses, and logical port from
bbaaef
  * 'addresses' which should be of the format 'MAC [IP1 IP2 ..]
bbaaef
@@ -4048,7 +4030,7 @@ consider_nat_address(struct ovsdb_idl_index *sbrec_port_binding_by_name,
bbaaef
     char *lport = NULL;
bbaaef
     if (!extract_addresses_with_port(nat_address, laddrs, &lport)
bbaaef
         || (!lport && !strcmp(pb->type, "patch"))
bbaaef
-        || (lport && !pinctrl_is_chassis_resident(
bbaaef
+        || (lport && !lport_is_chassis_resident(
bbaaef
                 sbrec_port_binding_by_name, chassis,
bbaaef
                 active_tunnels, lport))) {
bbaaef
         destroy_lport_addresses(laddrs);
bbaaef
diff --git a/tests/ovn.at b/tests/ovn.at
bbaaef
index 335ccd8c5..b7ee7beed 100644
bbaaef
--- a/tests/ovn.at
bbaaef
+++ b/tests/ovn.at
bbaaef
@@ -29,6 +29,22 @@ m4_define([OVN_CHECK_PACKETS],
bbaaef
   [ovn_check_packets__ "$1" "$2"
bbaaef
    AT_CHECK([sort $rcv_text], [0], [expout])])
bbaaef
 
bbaaef
+m4_define([OVN_CHECK_PACKETS_REMOVE_BROADCAST],
bbaaef
+  [ovn_check_packets__ () {
bbaaef
+   echo "checking packets in $1 against $2:"
bbaaef
+   rcv_pcap=$1
bbaaef
+   exp_text=$2
bbaaef
+   exp_n=`wc -l < "$exp_text"`
bbaaef
+   OVS_WAIT_UNTIL(
bbaaef
+     [$PYTHON "$top_srcdir/ovs/utilities/ovs-pcap.in" $rcv_pcap > $rcv_text
bbaaef
+      sed -i '/ffffffffffff/d' $rcv_text
bbaaef
+      rcv_n=`wc -l < "$rcv_text"`
bbaaef
+      echo "rcv_n=$rcv_n exp_n=$exp_n"
bbaaef
+      test $rcv_n -ge $exp_n])
bbaaef
+   sort $exp_text > expout
bbaaef
+ }
bbaaef
+])
bbaaef
+
bbaaef
 AT_BANNER([OVN components])
bbaaef
 
bbaaef
 AT_SETUP([ovn -- lexer])
bbaaef
@@ -15976,3 +15992,307 @@ OVS_WAIT_UNTIL([
bbaaef
 
bbaaef
 OVN_CLEANUP([hv1])
bbaaef
 AT_CLEANUP
bbaaef
+
bbaaef
+
bbaaef
+AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S ARP handling])
bbaaef
+ovn_start
bbaaef
+
bbaaef
+# In this test cases we create 3 switches, all connected to same
bbaaef
+# physical network (through br-phys on each HV). LS1 and LS2 have
bbaaef
+# 1 VIF each. Each HV has 1 VIF port. The first digit
bbaaef
+# of VIF port name indicates the hypervisor it is bound to, e.g.
bbaaef
+# lp23 means VIF 3 on hv2.
bbaaef
+#
bbaaef
+# All the switches are connected to a logical router "router".
bbaaef
+#
bbaaef
+# Each switch's VLAN tag and their logical switch ports are:
bbaaef
+#   - ls1:
bbaaef
+#       - tagged with VLAN 101
bbaaef
+#       - ports: lp11
bbaaef
+#   - ls2:
bbaaef
+#       - tagged with VLAN 201
bbaaef
+#       - ports: lp22
bbaaef
+#   - ls-underlay:
bbaaef
+#       - tagged with VLAN 1000
bbaaef
+# Note: a localnet port is created for each switch to connect to
bbaaef
+# physical network.
bbaaef
+
bbaaef
+for i in 1 2; do
bbaaef
+    ls_name=ls$i
bbaaef
+    ovn-nbctl ls-add $ls_name
bbaaef
+    ln_port_name=ln$i
bbaaef
+    if test $i -eq 1; then
bbaaef
+        ovn-nbctl lsp-add $ls_name $ln_port_name "" 101
bbaaef
+    elif test $i -eq 2; then
bbaaef
+        ovn-nbctl lsp-add $ls_name $ln_port_name "" 201
bbaaef
+    fi
bbaaef
+    ovn-nbctl lsp-set-addresses $ln_port_name unknown
bbaaef
+    ovn-nbctl lsp-set-type $ln_port_name localnet
bbaaef
+    ovn-nbctl lsp-set-options $ln_port_name network_name=phys
bbaaef
+done
bbaaef
+
bbaaef
+# lsp_to_ls LSP
bbaaef
+#
bbaaef
+# Prints the name of the logical switch that contains LSP.
bbaaef
+lsp_to_ls () {
bbaaef
+    case $1 in dnl (
bbaaef
+        lp?[[11]]) echo ls1 ;; dnl (
bbaaef
+        lp?[[12]]) echo ls2 ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+vif_to_hv () {
bbaaef
+    case $1 in dnl (
bbaaef
+        vif[[1]]?) echo hv1 ;; dnl (
bbaaef
+        vif[[2]]?) echo hv2 ;; dnl (
bbaaef
+        vif?[[north]]?) echo hv4 ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+ip_to_hex() {
bbaaef
+       printf "%02x%02x%02x%02x" "$@"
bbaaef
+}
bbaaef
+
bbaaef
+net_add n1
bbaaef
+for i in 1 2; do
bbaaef
+    sim_add hv$i
bbaaef
+    as hv$i
bbaaef
+    ovs-vsctl add-br br-phys
bbaaef
+    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
bbaaef
+    ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
bbaaef
+    ovn_attach n1 br-phys 192.168.0.$i
bbaaef
+
bbaaef
+    ovs-vsctl add-port br-int vif$i$i -- \
bbaaef
+        set Interface vif$i$i external-ids:iface-id=lp$i$i \
bbaaef
+                              options:tx_pcap=hv$i/vif$i$i-tx.pcap \
bbaaef
+                              options:rxq_pcap=hv$i/vif$i$i-rx.pcap \
bbaaef
+                              ofport-request=$i$i
bbaaef
+
bbaaef
+    lsp_name=lp$i$i
bbaaef
+    ls_name=$(lsp_to_ls $lsp_name)
bbaaef
+
bbaaef
+    ovn-nbctl lsp-add $ls_name $lsp_name
bbaaef
+    ovn-nbctl lsp-set-addresses $lsp_name "f0:00:00:00:00:$i$i 192.168.$i.$i"
bbaaef
+    ovn-nbctl lsp-set-port-security $lsp_name f0:00:00:00:00:$i$i
bbaaef
+
bbaaef
+    OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup])
bbaaef
+
bbaaef
+done
bbaaef
+
bbaaef
+ovn-nbctl ls-add ls-underlay
bbaaef
+ovn-nbctl lsp-add ls-underlay ln3 "" 1000
bbaaef
+ovn-nbctl lsp-set-addresses ln3 unknown
bbaaef
+ovn-nbctl lsp-set-type ln3 localnet
bbaaef
+ovn-nbctl lsp-set-options ln3 network_name=phys
bbaaef
+
bbaaef
+ovn-nbctl ls-add ls-north
bbaaef
+ovn-nbctl lsp-add ls-north ln4 "" 1000
bbaaef
+ovn-nbctl lsp-set-addresses ln4 unknown
bbaaef
+ovn-nbctl lsp-set-type ln4 localnet
bbaaef
+ovn-nbctl lsp-set-options ln4 network_name=phys
bbaaef
+
bbaaef
+# Add a VM on ls-north
bbaaef
+ovn-nbctl lsp-add ls-north lp-north
bbaaef
+ovn-nbctl lsp-set-addresses lp-north "f0:f0:00:00:00:11 172.31.0.10"
bbaaef
+ovn-nbctl lsp-set-port-security lp-north f0:f0:00:00:00:11
bbaaef
+
bbaaef
+# Add 3rd hypervisor
bbaaef
+sim_add hv3
bbaaef
+as hv3 ovs-vsctl add-br br-phys
bbaaef
+as hv3 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
bbaaef
+as hv3 ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:33"
bbaaef
+as hv3 ovn_attach n1 br-phys 192.168.0.3
bbaaef
+
bbaaef
+# Add 4th hypervisor
bbaaef
+sim_add hv4
bbaaef
+as hv4 ovs-vsctl add-br br-phys
bbaaef
+as hv4 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
bbaaef
+as hv4 ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:44"
bbaaef
+as hv4 ovn_attach n1 br-phys 192.168.0.4
bbaaef
+
bbaaef
+as hv4 ovs-vsctl add-port br-int vif-north -- \
bbaaef
+        set Interface vif-north external-ids:iface-id=lp-north \
bbaaef
+                              options:tx_pcap=hv4/vif-north-tx.pcap \
bbaaef
+                              options:rxq_pcap=hv4/vif-north-rx.pcap \
bbaaef
+                              ofport-request=44
bbaaef
+
bbaaef
+ovn-nbctl lr-add router
bbaaef
+ovn-nbctl lrp-add router router-to-ls1 00:00:01:01:02:03 192.168.1.3/24
bbaaef
+ovn-nbctl lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
bbaaef
+ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
bbaaef
+
bbaaef
+ovn-nbctl lsp-add ls1 ls1-to-router -- set Logical_Switch_Port ls1-to-router type=router \
bbaaef
+          options:router-port=router-to-ls1 -- lsp-set-addresses ls1-to-router router
bbaaef
+ovn-nbctl lsp-add ls2 ls2-to-router -- set Logical_Switch_Port ls2-to-router type=router \
bbaaef
+          options:router-port=router-to-ls2 -- lsp-set-addresses ls2-to-router router
bbaaef
+ovn-nbctl lsp-add ls-underlay underlay-to-router -- set Logical_Switch_Port \
bbaaef
+                              underlay-to-router type=router \
bbaaef
+                              options:router-port=router-to-underlay \
bbaaef
+                              -- lsp-set-addresses underlay-to-router router
bbaaef
+
bbaaef
+
bbaaef
+OVN_POPULATE_ARP
bbaaef
+
bbaaef
+# lsp_to_ls LSP
bbaaef
+#
bbaaef
+# Prints the name of the logical switch that contains LSP.
bbaaef
+lsp_to_ls () {
bbaaef
+    case $1 in dnl (
bbaaef
+        lp?[[11]]) echo ls1 ;; dnl (
bbaaef
+        lp?[[12]]) echo ls2 ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+vif_to_ls () {
bbaaef
+    case $1 in dnl (
bbaaef
+        vif?[[11]]) echo ls1 ;; dnl (
bbaaef
+        vif?[[12]]) echo ls2 ;; dnl (
bbaaef
+        vif-north) echo ls-north ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+hv_to_num () {
bbaaef
+    case $1 in dnl (
bbaaef
+        hv1) echo 1 ;; dnl (
bbaaef
+        hv2) echo 2 ;; dnl (
bbaaef
+        hv3) echo 3 ;; dnl (
bbaaef
+        hv4) echo 4 ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+vif_to_num () {
bbaaef
+    case $1 in dnl (
bbaaef
+        vif22) echo 22 ;; dnl (
bbaaef
+        vif21) echo 21 ;; dnl (
bbaaef
+        vif11) echo 11 ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+vif_to_hv () {
bbaaef
+    case $1 in dnl (
bbaaef
+        vif[[1]]?) echo hv1 ;; dnl (
bbaaef
+        vif[[2]]?) echo hv2 ;; dnl (
bbaaef
+        vif-north) echo hv4 ;; dnl (
bbaaef
+        *) AT_FAIL_IF([:]) ;;
bbaaef
+    esac
bbaaef
+}
bbaaef
+
bbaaef
+vif_to_lrp () {
bbaaef
+    echo router-to-`vif_to_ls $1`
bbaaef
+}
bbaaef
+
bbaaef
+ip_to_hex() {
bbaaef
+       printf "%02x%02x%02x%02x" "$@"
bbaaef
+}
bbaaef
+
bbaaef
+# test_arp INPORT SHA SPA TPA [REPLY_HA]
bbaaef
+#
bbaaef
+# Causes a packet to be received on INPORT.  The packet is an ARP
bbaaef
+# request with SHA, SPA, and TPA as specified.  If REPLY_HA is provided, then
bbaaef
+# it should be the hardware address of the target to expect to receive in an
bbaaef
+# ARP reply; otherwise no reply is expected.
bbaaef
+#
bbaaef
+# INPORT is an logical switch port number, e.g. 11 for vif11.
bbaaef
+# SHA and REPLY_HA are each 12 hex digits.
bbaaef
+# SPA and TPA are each 8 hex digits.
bbaaef
+test_arp() {
bbaaef
+    local inport=$1 sha=$2 spa=$3 tpa=$4 reply_ha=$5
bbaaef
+    local request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
bbaaef
+    hv=`vif_to_hv $inport`
bbaaef
+    as $hv ovs-appctl netdev-dummy/receive $inport $request
bbaaef
+
bbaaef
+    if test X$reply_ha = X; then
bbaaef
+        # Expect to receive the broadcast ARP on the other logical switch ports
bbaaef
+        # if no reply is expected.
bbaaef
+        local i j
bbaaef
+        for i in 1 2 3; do
bbaaef
+            for j in 1 2 3; do
bbaaef
+                if test $i$j != $inport; then
bbaaef
+                    echo $request >> $i$j.expected
bbaaef
+                fi
bbaaef
+            done
bbaaef
+        done
bbaaef
+    else
bbaaef
+        # Expect to receive the reply, if any.
bbaaef
+        local reply=${sha}${reply_ha}08060001080006040002${reply_ha}${tpa}${sha}${spa}
bbaaef
+        local reply_vid=${sha}${reply_ha}810003e808060001080006040002${reply_ha}${tpa}${sha}${spa}
bbaaef
+        echo $reply_vid >> ${inport}_vid.expected
bbaaef
+        echo $reply >> $inport.expected
bbaaef
+    fi
bbaaef
+}
bbaaef
+
bbaaef
+sip=`ip_to_hex 172 31 0 10`
bbaaef
+tip=`ip_to_hex 172 31 0 1`
bbaaef
+
bbaaef
+# Set a hypervisor as gateway chassis, for router port 172.31.0.1
bbaaef
+ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv3
bbaaef
+ovn-nbctl --wait=sb sync
bbaaef
+
bbaaef
+# Dump a bunch of info helpful for debugging if there's a failure.
bbaaef
+
bbaaef
+echo "------ OVN dump ------"
bbaaef
+ovn-nbctl show
bbaaef
+ovn-sbctl show
bbaaef
+ovn-sbctl list port_binding
bbaaef
+ovn-sbctl list mac_binding
bbaaef
+
bbaaef
+echo "------ hv1 dump ------"
bbaaef
+as hv1 ovs-vsctl show
bbaaef
+as hv1 ovs-vsctl list Open_Vswitch
bbaaef
+
bbaaef
+echo "------ hv2 dump ------"
bbaaef
+as hv2 ovs-vsctl show
bbaaef
+as hv2 ovs-vsctl list Open_Vswitch
bbaaef
+
bbaaef
+echo "------ hv3 dump ------"
bbaaef
+as hv3 ovs-vsctl show
bbaaef
+as hv3 ovs-vsctl list Open_Vswitch
bbaaef
+
bbaaef
+echo "------ hv4 dump ------"
bbaaef
+as hv4 ovs-vsctl show
bbaaef
+as hv4 ovs-vsctl list Open_Vswitch
bbaaef
+
bbaaef
+OVS_WAIT_UNTIL([test x`ovn-sbctl --bare --columns chassis find port_binding  logical_port=cr-router-to-underlay | wc -l` = x1])
bbaaef
+
bbaaef
+test_arp vif-north f0f000000011 $sip $tip 000001010207
bbaaef
+
bbaaef
+# Confirm that vif-north gets a single ARP reply
bbaaef
+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap], [vif-north.expected])
bbaaef
+
bbaaef
+# Confirm that only redirect chassis allowed arp resolution.
bbaaef
+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv3/br-phys_n1-tx.pcap], [vif-north_vid.expected])
bbaaef
+
bbaaef
+# Confirm that other OVN chassis did not generate ARP reply.
bbaaef
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys_n1-tx.pcap > hv1/br-phys_n1-tx.packets
bbaaef
+$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap > hv2/br-phys_n1-tx.packets
bbaaef
+
bbaaef
+AT_CHECK([grep 000001010207 hv1/br-phys_n1-tx.packets | wc -l], [0], [[0
bbaaef
+]])
bbaaef
+AT_CHECK([grep 000001010207 hv2/br-phys_n1-tx.packets | wc -l], [0], [[0
bbaaef
+]])
bbaaef
+
bbaaef
+echo "----------- Post Traffic hv1 dump -----------"
bbaaef
+as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int
bbaaef
+as hv1 ovs-appctl fdb/show br-phys
bbaaef
+
bbaaef
+echo "----------- Post Traffic hv2 dump -----------"
bbaaef
+as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int
bbaaef
+as hv2 ovs-appctl fdb/show br-phys
bbaaef
+
bbaaef
+echo "----------- Post Traffic hv3 dump -----------"
bbaaef
+as hv3 ovs-ofctl -O OpenFlow13 dump-flows br-int
bbaaef
+as hv3 ovs-appctl fdb/show br-phys
bbaaef
+
bbaaef
+echo "----------- Post Traffic hv4 dump -----------"
bbaaef
+as hv4 ovs-ofctl -O OpenFlow13 dump-flows br-int
bbaaef
+as hv4 ovs-appctl fdb/show br-phys
bbaaef
+
bbaaef
+OVN_CLEANUP([hv1],[hv2],[hv3],[hv4])
bbaaef
+
bbaaef
+AT_CLEANUP
bbaaef
-- 
bbaaef
2.23.0
bbaaef