From patchwork Sat May 11 01:02:27 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Ankur Sharma
external_ids:ovn-chassis-mac-mappings
physnet1:aa:bb:cc:dd:ee:ff,physnet2:a1:b2:c3:d4:e5:f6
.
+ These are the macs that ovn-controller will replace a router port
+ mac with, if packet is going from a distributed router port on
+ vlan type logical switch.
+
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 69eeee5..90b2d57 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -867,7 +867,7 @@ main(int argc, char *argv[])
struct local_datapath *cur_node, *next_node;
HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node,
&local_datapaths) {
- free(cur_node->peer_dps);
+ free(cur_node->peer_ports);
hmap_remove(&local_datapaths, &cur_node->hmap_node);
free(cur_node);
}
diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h
index 6afd727..a4c1309 100644
--- a/ovn/controller/ovn-controller.h
+++ b/ovn/controller/ovn-controller.h
@@ -59,8 +59,9 @@ struct local_datapath {
/* True if this datapath contains an l3gateway port located on this
* hypervisor. */
bool has_local_l3gateway;
- const struct sbrec_datapath_binding **peer_dps;
- size_t n_peer_dps;
+
+ const struct sbrec_port_binding **peer_ports;
+ size_t n_peer_ports;
};
struct local_datapath *get_local_datapath(const struct hmap *,
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index 7386404..fb4aaa0 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -20,6 +20,7 @@
#include "ha-chassis.h"
#include "lflow.h"
#include "lport.h"
+#include "chassis.h"
#include "lib/bundle.h"
#include "openvswitch/poll-loop.h"
#include "lib/uuid.h"
@@ -30,6 +31,7 @@
#include "openvswitch/ofp-actions.h"
#include "openvswitch/ofpbuf.h"
#include "openvswitch/vlog.h"
+#include "openvswitch/ofp-parse.h"
#include "ovn-controller.h"
#include "ovn/lib/chassis-index.h"
#include "ovn/lib/ovn-sb-idl.h"
@@ -233,6 +235,92 @@ get_zone_ids(const struct sbrec_port_binding *binding,
}
static void
+put_replace_router_port_mac_flows(const struct
+ sbrec_port_binding *localnet_port,
+ const struct sbrec_chassis *chassis,
+ const struct hmap *local_datapaths,
+ struct ofpbuf *ofpacts_p,
+ ofp_port_t ofport,
+ struct hmap *flow_table)
+{
+ struct local_datapath *ld = get_local_datapath(local_datapaths,
+ localnet_port->datapath->
+ tunnel_key);
+ ovs_assert(ld);
+
+ uint32_t dp_key = localnet_port->datapath->tunnel_key;
+ uint32_t port_key = localnet_port->tunnel_key;
+ int tag = localnet_port->tag ? *localnet_port->tag : 0;
+ const char *network = smap_get(&localnet_port->options, "network_name");
+ struct eth_addr chassis_mac;
+
+ if (!network) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&rl, "Physical network not configured for datapath: %ld "
+ "with localnet port",
+ localnet_port->datapath->tunnel_key);
+ return;
+ }
+
+ /* Get chassis mac */
+ if (!chassis_get_mac(chassis, network, &chassis_mac)) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ /* Keeping the log level low for backward compatibility.
+ * Chassis mac is a new configuration.
+ */
+ VLOG_DBG_RL(&rl, "Could not get chassis mac for network: %s", network);
+ return;
+ }
+
+ for (int i = 0; i < ld->n_peer_ports; i++) {
+ const struct sbrec_port_binding *rport_binding = ld->peer_ports[i];
+ struct eth_addr router_port_mac;
+ char *err_str = NULL;
+ struct match match;
+ struct ofpact_mac *replace_mac;
+
+ /* Table 65, priority 150.
+ * =======================
+ *
+ * Implements output to localnet port.
+ * a. Flow replaces ingress router port mac with a chassis mac.
+ * b. Flow appends the vlan id localnet port is configured with.
+ */
+ match_init_catchall(&match);
+ ofpbuf_clear(ofpacts_p);
+
+ ovs_assert(rport_binding->n_mac == 1);
+ if ((err_str = str_to_mac(rport_binding->mac[0], &router_port_mac))) {
+ /* Parsing of mac failed. */
+ VLOG_WARN("Parsing or router port mac failed for router port: %s, "
+ "with error: %s", rport_binding->logical_port, err_str);
+ free(err_str);
+ return;
+ }
+
+ /* Replace Router mac flow */
+ match_set_metadata(&match, htonll(dp_key));
+ match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
+ match_set_dl_src(&match, router_port_mac);
+
+ replace_mac = ofpact_put_SET_ETH_SRC(ofpacts_p);
+ replace_mac->mac = chassis_mac;
+
+ if (tag) {
+ struct ofpact_vlan_vid *vlan_vid;
+ vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts_p);
+ vlan_vid->vlan_vid = tag;
+ vlan_vid->push_vlan_if_needed = true;
+ }
+
+ ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
+
+ ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 150, 0,
+ &match, ofpacts_p);
+ }
+}
+
+static void
put_local_common_flows(uint32_t dp_key, uint32_t port_key,
uint32_t parent_port_key,
const struct zone_ids *zone_ids,
@@ -701,6 +789,13 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
}
ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
&match, ofpacts_p);
+
+ if (!strcmp(binding->type, "localnet")) {
+ put_replace_router_port_mac_flows(binding, chassis,
+ local_datapaths, ofpacts_p,
+ ofport, flow_table);
+ }
+
} else if (!tun && !is_ha_remote) {
/* Remote port connected by localnet port */
/* Table 33, priority 100.
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index de0c06d..74d3692 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -86,6 +86,12 @@ enum ovn_datapath_type {
DP_ROUTER /* OVN logical router. */
};
+/* Network type of a datapath */
+enum ovn_datapath_nw_type {
+ DP_NETWORK_OVERLAY,
+ DP_NETWORK_BRIDGED
+};
+
/* Returns an "enum ovn_stage" built from the arguments.
*
* (It's better to use ovn_stage_build() for type-safety reasons, but inline
@@ -445,6 +451,8 @@ struct ovn_datapath {
bool has_unknown;
+ enum ovn_datapath_nw_type network_type;
+
/* IPAM data. */
struct ipam_info ipam_info;
@@ -491,6 +499,27 @@ cleanup_macam(struct hmap *macam_)
}
}
+static void
+ovn_datapath_update_nw_type(struct ovn_datapath *od)
+{
+ if (!od->nbs) {
+ return;
+ }
+
+ if (!od->nbs->network_type ||
+ !strlen(od->nbs->network_type) ||
+ !strcmp(od->nbs->network_type, "overlay")) {
+ /* No value in network_type is taken as OVERLAY. */
+ od->network_type = DP_NETWORK_OVERLAY;
+ } else if (!strcmp(od->nbs->network_type, "bridged")) {
+ od->network_type = DP_NETWORK_BRIDGED;
+ } else {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "bad network type %s, for %s",
+ od->nbs->network_type, od->nbs->name);
+ }
+}
+
static struct ovn_datapath *
ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
const struct nbrec_logical_switch *nbs,
@@ -682,6 +711,13 @@ ovn_datapath_update_external_ids(struct ovn_datapath *od)
if (name2 && name2[0]) {
smap_add(&ids, "name2", name2);
}
+
+ if (od->nbs) {
+ smap_add(&ids, "network-type",
+ (od->nbs->network_type && strlen(od->nbs->network_type)) ?
+ od->nbs->network_type : "overlay");
+ }
+
sbrec_datapath_binding_set_external_ids(od->sb, &ids);
smap_destroy(&ids);
}
@@ -734,9 +770,11 @@ join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
ovs_list_remove(&od->list);
ovs_list_push_back(both, &od->list);
ovn_datapath_update_external_ids(od);
+ ovn_datapath_update_nw_type(od);
} else {
od = ovn_datapath_create(datapaths, &nbs->header_.uuid,
nbs, NULL, NULL);
+ ovn_datapath_update_nw_type(od);
ovs_list_push_back(nb_only, &od->list);
}
diff --git a/ovn/ovn-architecture.7.xml b/ovn/ovn-architecture.7.xml
index 8c9e106..6275db1 100644
--- a/ovn/ovn-architecture.7.xml
+++ b/ovn/ovn-architecture.7.xml
@@ -1407,6 +1407,30 @@
egress pipeline of the destination localnet logical switch datapath
and goes out of the integration bridge to the provider bridge (
belonging to the destination logical switch) via the localnet port.
+ While sending the packet to provider bridge, we also replace router
+ port mac as source mac with a chassis unique mac.
+
+ This chassis unique mac is configured as global ovs config on each
+ chassis (eg. via "ovs-vsctl set open . external-ids:
+ ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
").More
+ details on this config are present in ovn-controller
(8).
+
+ If the above is not configured, then source mac would be the router
+ port mac. This could create problem if we have more than one chassis.
+ This is because, since the router port is distributed, hence same
+ mac,vlan tuple will seen by physical network from other chassis
+ as well. This could cause some/all of these issues:
+
+ Whether logical switch will fully virtualize the network (i.e overlay) + or it simply connects to the physical network (i.e bridged). + This field will take either of the following values: "overlay" or + "bridged". +
+ ++ An "overlay" type logical switch means that 24 bit virtual network + identifier defines its broadcast domain and hence packets leaving + the chassis will be encapsulated. A "bridged" logical switch means that + it uses 12 bit vlan id as broadcast domain and packets leaving the + chassis would not be encapsulated, but would have a vlan header + instead (logical switches with vlan zero are also to be assigned the + type as "bridged"). For a "bridged" type logical switch, a localnet + port MUST be created. +
+ovn-controller
(8) for more information.
ovn-controller
populates this key with the set of options
+ configured in the column of the
+ Open_vSwitch database's
+ table. See ovn-controller
(8) for more information.
+ Common
Columns
at the beginning of this document.
@@ -2162,6 +2170,13 @@ tcp.flags = RST;
the database.
+ ovn-northd
stores in this key the network type from
+ corresponding row in
+ the database.
+ The following happens when a VM sends an external traffic (which requires @@ -1607,6 +1607,91 @@ +
+ The following happens when a VM sends an external traffic (i.e to non + logical router connected network), but there is not need for NATing. +
+ +
+ Since, there is no NATing required, hence we need not redirect the packet
+ to a gateway chassis. As a result, this packet flow is same as East-West.
+ In order to ensure that OVN will not redirect the packet over a tunnel
+ to gateway-chassis, "network_type" of destination localnet logical switch,
+ should be set as "bridged". A "bridged" logical switch ensures that there
+ is no tunnel encapsulation done while forwarding the packet on it.
+ Please refer to ovn-nb
(5) for more details.
+
+ The following happens for the reverse external traffic. +
+ ++ One thing to note here is that, while VM to External traffic did not + require redirection to gateway chassis, the reverse traffic is through + gateway chassis only. This is because, for external router, OVN logical + router port IP will be the next hop to reach the endpoints behind it. + As a result, we need a centralized chassis, which will respond to ARP + requests coming from external network. This centralized chassis, is the + gateway chassis which is attached to corresponding router port. +
+diff --git a/tests/ovn.at b/tests/ovn.at index f93f8f9..621361d 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -14022,7 +14022,7 @@ ovn-hv4-0 OVN_CLEANUP([hv1], [hv2], [hv3]) AT_CLEANUP -AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR chassis mac]) +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR E-W chassis mac]) ovn_start @@ -14032,6 +14032,8 @@ ovn_start # of VIF port name indicates the hypervisor it is bound to, e.g. # lp23 means VIF 3 on hv2. # +# Both the switches are connected to a logical router "router". +# # Each switch's VLAN tag and their logical switch ports are: # - ls1: # - tagged with VLAN 101 @@ -14189,6 +14191,7 @@ test_ip() { echo "------ OVN dump ------" ovn-nbctl show ovn-sbctl show +ovn-sbctl list port_binding echo "------ hv1 dump ------" as hv1 ovs-vsctl show @@ -14215,6 +14218,308 @@ as hv2 ovs-appctl fdb/show br-phys OVN_CHECK_PACKETS([hv2/vif22-tx.pcap], [vif22.expected]) + +# Associate a chassis as gateway chassis and validate garp. + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP + + +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S GARP]) +ovn_start + + +# In this test cases we create 2 switches, all connected to same +# physical network (through br-phys on each HV). Each switch has +# 1 VIF. Each HV has 1 VIF port. The first digit +# of VIF port name indicates the hypervisor it is bound to, e.g. +# lp23 means VIF 3 on hv2. +# +# Both the switches are connected to a logical router "router". +# +# Additionally, we create a logical switch (ls-underlay) for N-S traffic. +# +# Each switch's VLAN tag and their logical switch ports are: +# - ls1: +# - tagged with VLAN 101 +# - ports: lp11 +# - ls2: +# - tagged with VLAN 201 +# - ports: lp22 +# - ls-underlay: +# - tagged with VLAN 1000 +# +# Note: a localnet port is created for each switch to connect to +# physical network. +# lsp_to_ls LSP +# +# Prints the name of the logical switch that contains LSP. + +net_add n1 +for i in 1 2; do + sim_add hv$i + as hv$i + ovs-vsctl add-br br-phys + ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys + ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i" + ovs-vsctl set open . external-ids:system-id="HV$i" + ovn_attach n1 br-phys 192.168.0.$i + ovs-vsctl set-controller br-int ptcp: +done + +ovn-nbctl ls-add ls-underlay bridged +ovn-nbctl lsp-add ls-underlay ln3 "" 1000 +ovn-nbctl lsp-set-addresses ln3 unknown +ovn-nbctl lsp-set-type ln3 localnet +ovn-nbctl lsp-set-options ln3 network_name=phys + +ovn-nbctl lr-add router +ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24 + +ovn-nbctl lsp-add ls-underlay underlay-to-router -- set Logical_Switch_Port \ + underlay-to-router type=router \ + options:router-port=router-to-underlay \ + -- lsp-set-addresses underlay-to-router router + +ovn-nbctl --wait=sb sync + +# Associate hv2 as gateway chassis +ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv2 + +ovn-nbctl show +ovn-sbctl show + +# Dump a bunch of info helpful for debugging if there's a failure. + +echo "------ OVN dump ------" +ovn-nbctl show +ovn-sbctl show + +echo "------ hv1 dump ------" +as hv1 ovs-vsctl show +as hv1 ovs-vsctl list Open_Vswitch + +echo "------ hv2 dump ------" +as hv2 ovs-vsctl show +as hv2 ovs-vsctl list Open_Vswitch + +sleep 1 + +echo "----------- Post Traffic hv1 dump -----------" +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int +as hv1 ovs-appctl fdb/show br-phys + +echo "----------- Post Traffic hv2 dump -----------" +as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int +as hv2 ovs-appctl fdb/show br-phys + +AT_CHECK([as hv2 ovs-appctl fdb/show br-phys | grep 00:00:01:01:02:07 | grep 1000 | wc -l], [0], [[1 +]]) + OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP + + +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S Ping]) +ovn_start + +# In this test cases we create 3 switches, all connected to same +# physical network (through br-phys on each HV). LS1 and LS2 have +# 1 VIF each. Each HV has 1 VIF port. The first digit +# of VIF port name indicates the hypervisor it is bound to, e.g. +# lp23 means VIF 3 on hv2. +# +# All the switches are connected to a logical router "router". +# +# Each switch's VLAN tag and their logical switch ports are: +# - ls1: +# - tagged with VLAN 101 +# - ports: lp11 +# - ls2: +# - tagged with VLAN 201 +# - ports: lp22 +# - ls-underlay: +# - tagged with VLAN 1000 +# Note: a localnet port is created for each switch to connect to +# physical network. + +for i in 1 2; do + ls_name=ls$i + ovn-nbctl ls-add $ls_name bridged + ln_port_name=ln$i + if test $i -eq 1; then + ovn-nbctl lsp-add $ls_name $ln_port_name "" 101 + elif test $i -eq 2; then + ovn-nbctl lsp-add $ls_name $ln_port_name "" 201 + fi + ovn-nbctl lsp-set-addresses $ln_port_name unknown + ovn-nbctl lsp-set-type $ln_port_name localnet + ovn-nbctl lsp-set-options $ln_port_name network_name=phys +done + +# lsp_to_ls LSP +# +# Prints the name of the logical switch that contains LSP. +lsp_to_ls () { + case $1 in dnl ( + lp?[[11]]) echo ls1 ;; dnl ( + lp?[[12]]) echo ls2 ;; dnl ( + *) AT_FAIL_IF([:]) ;; + esac +} + +vif_to_hv () { + case $1 in dnl ( + vif[[1]]?) echo hv1 ;; dnl ( + vif[[2]]?) echo hv2 ;; dnl ( + vif?[[north]]?) echo hv4 ;; dnl ( + *) AT_FAIL_IF([:]) ;; + esac +} + +ip_to_hex() { + printf "%02x%02x%02x%02x" "$@" +} + +net_add n1 +for i in 1 2; do + sim_add hv$i + as hv$i + ovs-vsctl add-br br-phys + ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys + ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i" + ovn_attach n1 br-phys 192.168.0.$i + + ovs-vsctl add-port br-int vif$i$i -- \ + set Interface vif$i$i external-ids:iface-id=lp$i$i \ + options:tx_pcap=hv$i/vif$i$i-tx.pcap \ + options:rxq_pcap=hv$i/vif$i$i-rx.pcap \ + ofport-request=$i$i + + lsp_name=lp$i$i + ls_name=$(lsp_to_ls $lsp_name) + + ovn-nbctl lsp-add $ls_name $lsp_name + ovn-nbctl lsp-set-addresses $lsp_name "f0:00:00:00:00:$i$i 192.168.$i.$i" + ovn-nbctl lsp-set-port-security $lsp_name f0:00:00:00:00:$i$i + + OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup]) + +done + +ovn-nbctl ls-add ls-underlay bridged +ovn-nbctl lsp-add ls-underlay ln3 "" 1000 +ovn-nbctl lsp-set-addresses ln3 unknown +ovn-nbctl lsp-set-type ln3 localnet +ovn-nbctl lsp-set-options ln3 network_name=phys + +ovn-nbctl ls-add ls-north bridged +ovn-nbctl lsp-add ls-north ln4 "" 1000 +ovn-nbctl lsp-set-addresses ln4 unknown +ovn-nbctl lsp-set-type ln4 localnet +ovn-nbctl lsp-set-options ln4 network_name=phys + +# Add a VM on ls-north +ovn-nbctl lsp-add ls-north lp-north +ovn-nbctl lsp-set-addresses lp-north "f0:f0:00:00:00:11 172.31.0.10" +ovn-nbctl lsp-set-port-security lp-north f0:f0:00:00:00:11 + +# Add 3rd hypervisor +sim_add hv3 +as hv3 ovs-vsctl add-br br-phys +as hv3 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys +as hv3 ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:33" +as hv3 ovn_attach n1 br-phys 192.168.0.3 + +# Add 4th hypervisor +sim_add hv4 +as hv4 ovs-vsctl add-br br-phys +as hv4 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys +as hv4 ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:44" +as hv4 ovn_attach n1 br-phys 192.168.0.4 + +as hv4 ovs-vsctl add-port br-int vif-north -- \ + set Interface vif-north external-ids:iface-id=lp-north \ + options:tx_pcap=hv4/vif-north-tx.pcap \ + options:rxq_pcap=hv4/vif-north-rx.pcap \ + ofport-request=44 + +ovn-nbctl lr-add router +ovn-nbctl lrp-add router router-to-ls1 00:00:01:01:02:03 192.168.1.3/24 +ovn-nbctl lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24 +ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24 + +ovn-nbctl lsp-add ls1 ls1-to-router -- set Logical_Switch_Port ls1-to-router type=router \ + options:router-port=router-to-ls1 -- lsp-set-addresses ls1-to-router router +ovn-nbctl lsp-add ls2 ls2-to-router -- set Logical_Switch_Port ls2-to-router type=router \ + options:router-port=router-to-ls2 -- lsp-set-addresses ls2-to-router router +ovn-nbctl lsp-add ls-underlay underlay-to-router -- set Logical_Switch_Port \ + underlay-to-router type=router \ + options:router-port=router-to-underlay \ + -- lsp-set-addresses underlay-to-router router + +ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv3 + +ovn-nbctl --wait=sb sync + +sleep 2 + +OVN_POPULATE_ARP + +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 $inport $packet +} + +# Dump a bunch of info helpful for debugging if there's a failure. + +echo "------ OVN dump ------" +ovn-nbctl show +ovn-sbctl show +ovn-sbctl list port_binding +ovn-sbctl list mac_binding + +echo "------ hv1 dump ------" +as hv1 ovs-vsctl show +as hv1 ovs-vsctl list Open_Vswitch + +echo "------ hv2 dump ------" +as hv2 ovs-vsctl show +as hv2 ovs-vsctl list Open_Vswitch + +echo "Send traffic" +sip=`ip_to_hex 192 168 1 1` +dip=`ip_to_hex 172 31 0 10` +test_ip vif11 f00000000011 000001010203 $sip $dip vif-north + +sleep 1 + +echo "----------- Post Traffic hv1 dump -----------" +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int +as hv1 ovs-appctl fdb/show br-phys + +echo "----------- Post Traffic hv2 dump -----------" +as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int +as hv2 ovs-appctl fdb/show br-phys + +echo "----------- Post Traffic hv3 dump -----------" +as hv3 ovs-ofctl -O OpenFlow13 dump-flows br-int +as hv3 ovs-appctl fdb/show br-phys + +echo "----------- Post Traffic hv4 dump -----------" +as hv4 ovs-ofctl -O OpenFlow13 dump-flows br-int +as hv4 ovs-appctl fdb/show br-phys + +# Confirm that HV1 chassis mac is never seen on Gateway chassis, i.e HV3 +AT_CHECK([as hv3 ovs-appctl fdb/show br-phys | grep aa:bb:cc:dd:ee:11 | wc -l], [0], [[0 +]]) + +OVN_CLEANUP([hv1],[hv2],[hv3],[hv4]) + +AT_CLEANUP