+OVN_CONTROLLER_VTEP_STOP([/Chassis for VTEP physical switch (br-vtep) disappears/d])
+AT_CLEANUP
+
+
+# Tests binding updates.
+AT_SETUP([ovn-controller-vtep - test binding 1])
+OVN_CONTROLLER_VTEP_START
+
+# adds logical switch 'lswitch0' and vlan_bindings.
+AT_CHECK([vtep-ctl add-ls lswitch0 -- bind-ls br-vtep p0 100 lswitch0 -- bind-ls br-vtep p1 300 lswitch0])
+# adds lport in ovn-nb database, and sets the type and options.
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0], [br-vtep], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep br-vtep_lswitch0`"])
+# should see one binding, associated to chassis of 'br-vtep'.
+chassis_uuid=$(ovn-sbctl --columns=_uuid list Chassis br-vtep | cut -d ':' -f2 | tr -d ' ')
+AT_CHECK_UNQUOTED([ovn-sbctl --columns=chassis list Port_Binding br-vtep_lswitch0 | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+${chassis_uuid}
+])
+
+# adds another logical switch 'lswitch1' and vlan_bindings.
+AT_CHECK([vtep-ctl add-ls lswitch1 -- bind-ls br-vtep p0 200 lswitch1])
+# adds lport in ovn-nb database for lswitch1.
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch1], [br-vtep], [lswitch1])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep -- br-vtep_lswitch1`"])
+# This is allowed, but not recommended, to have two vlan_bindings (to different vtep logical switches)
+# from one vtep gateway physical port in one ovn-nb logical swithch.
+AT_CHECK_UNQUOTED([ovn-sbctl --columns=chassis list Port_Binding | cut -d ':' -f2 | tr -d ' ' | sort -d], [0], [dnl
+
+${chassis_uuid}
+${chassis_uuid}
+])
+
+# adds another lport in ovn-nb database for lswitch0.
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0_dup], [br-vtep], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep -- br-vtep_lswitch0_dup`"])
+# it is not allowed to have more than one ovn-nb logical port for the same
+# vtep logical switch on a vtep gateway chassis, so should still see only
+# two port_binding entries bound.
+AT_CHECK_UNQUOTED([ovn-sbctl --columns=chassis list Port_Binding | cut -d ':' -f2 | tr -d ' ' | sort -d], [0], [dnl
+
+
+[[]]
+${chassis_uuid}
+${chassis_uuid}
+])
+# confirms the warning log.
+AT_CHECK([sed -n 's/^.*\(|WARN|.*\)$/\1/p' ovn-controller-vtep.log | sed 's/([[-_0-9a-z]][[-_0-9a-z]]*)/()/g' | uniq], [0], [dnl
+|WARN|logical switch (), on vtep gateway chassis () has already been associated with logical port (), ignore logical port ()
+])
+
+# deletes physical ports from vtep.
+AT_CHECK([ovs-vsctl del-port p0 -- del-port p1])
+AT_CHECK([vtep-ctl del-port br-vtep p0 -- del-port br-vtep p1])
+OVS_WAIT_UNTIL([test -z "`ovn-sbctl list Chassis | grep -- br-vtep_lswitch`"])
+# should see empty chassis column in both binding entries.
+AT_CHECK_UNQUOTED([ovn-sbctl --columns=chassis list Port_Binding | cut -d ':' -f2 | tr -d ' ' | sort], [0], [dnl
+
+
+[[]]
+[[]]
+[[]]
+])
+
+OVN_CONTROLLER_VTEP_STOP([/has already been associated with logical port/d])
+AT_CLEANUP
+
+
+# Tests corner case: Binding the vtep logical switch from two different
+# datapath.
+AT_SETUP([ovn-controller-vtep - test binding 2])
+OVN_CONTROLLER_VTEP_START
+
+# adds logical switch 'lswitch0' and vlan_bindings.
+AT_CHECK([vtep-ctl add-ls lswitch0 -- bind-ls br-vtep p0 100 lswitch0])
+# adds lport in ovn-nb database, and sets the type and options.
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0], [br-vtep], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep br-vtep_lswitch0`"])
+
+# adds another lswitch 'br-void' in ovn-nb database.
+AT_CHECK([ovn-nbctl lswitch-add br-void])
+# adds another vtep pswitch 'br-vtep-void' in vtep database.
+AT_CHECK([vtep-ctl add-ps br-vtep-void -- add-port br-vtep-void p0-void -- bind-ls br-vtep-void p0-void 100 lswitch0])
+# adds a conflicting logical port (both br-vtep_lswitch0 and br-vtep-void_lswitch0
+# are bound to the same logical switch, but they are on different datapath).
+OVN_NB_ADD_VTEP_PORT([br-void], [br-vtep-void_lswitch0], [br-vtep-void], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep br-vtep-void_lswitch0`"])
+OVS_WAIT_UNTIL([test -n "`grep WARN ovn-controller-vtep.log`"])
+# confirms the warning log.
+AT_CHECK([sed -n 's/^.*\(|WARN|.*\)$/\1/p' ovn-controller-vtep.log | sed 's/([[-_0-9a-z]][[-_0-9a-z]]*)/()/g;s/(with tunnel key [[0-9]][[0-9]]*)/()/g' | uniq], [0], [dnl
+|WARN|logical switch (), on vtep gateway chassis () has already been associated with logical datapath (), ignore logical port () which belongs to logical datapath ()
+])
+
+# then deletes 'br-void' and 'br-vtep-void', should see 'br-vtep_lswitch0'
+# bound correctly.
+AT_CHECK([ovn-nbctl lswitch-del br-void])
+# adds another vtep pswitch 'br-vtep-void' in vtep database.
+AT_CHECK([vtep-ctl del-ps br-vtep-void])
+OVS_WAIT_UNTIL([test -z "`ovn-sbctl list Port_Binding | grep br-vtep-void_lswitch0`"])
+chassis_uuid=$(ovn-sbctl --columns=_uuid list Chassis br-vtep | cut -d ':' -f2 | tr -d ' ')
+AT_CHECK_UNQUOTED([ovn-sbctl --columns=chassis list Port_Binding br-vtep_lswitch0 | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+${chassis_uuid}
+])
+
+OVN_CONTROLLER_VTEP_STOP([/has already been associated with logical datapath/d])
+AT_CLEANUP
+
+
+# Tests vtep module vtep logical switch tunnel key update.
+AT_SETUP([ovn-controller-vtep - test vtep-lswitch])
+OVN_CONTROLLER_VTEP_START
+
+# creates the logical switch in vtep and adds the corresponding logical
+# port to 'br-test'.
+AT_CHECK([vtep-ctl add-ls lswitch0 -- bind-ls br-vtep p0 100 lswitch0])
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0], [br-vtep], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep -- br-vtep_lswitch0`"])
+
+# retrieves the expected tunnel key.
+datapath_uuid=$(ovn-sbctl --columns=datapath list Port_Binding br-vtep_lswitch0 | cut -d ':' -f2 | tr -d ' ')
+tunnel_key=$(ovn-sbctl --columns=tunnel_key list Datapath_Binding ${datapath_uuid} | cut -d ':' -f2 | tr -d ' ')
+OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=tunnel_key list Logical_Switch | grep 0`"])
+# checks the vtep logical switch tunnel key configuration.
+AT_CHECK_UNQUOTED([vtep-ctl --columns=tunnel_key list Logical_Switch | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+${tunnel_key}
+])
+
+# creates a second physical switch in vtep database, and binds its p0 vlan-100
+# to the same logical switch 'lswitch0'.
+AT_CHECK([vtep-ctl add-ps br-vtep-void -- add-port br-vtep-void p0 -- bind-ls br-vtep-void p0 100 lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl --columns=name list Chassis | grep -- br-vtep-void`"])
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep-void_lswitch0], [br-vtep-void], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep -- br-vtep-void_lswitch0`"])
+
+# checks the vtep logical switch tunnel key configuration.
+AT_CHECK_UNQUOTED([vtep-ctl --columns=tunnel_key list Logical_Switch | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+${tunnel_key}
+])
+
+# now, deletes br-vtep-void.
+AT_CHECK([vtep-ctl del-ps br-vtep-void])
+OVS_WAIT_UNTIL([test -z "`ovn-sbctl --columns=name list Chassis | grep -- br-vtep-void`"])
+# checks the vtep logical switch tunnel key configuration.
+AT_CHECK_UNQUOTED([vtep-ctl --columns=tunnel_key list Logical_Switch | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+${tunnel_key}
+])
+
+# changes the ovn-nb logical port type so that it is no longer
+# vtep port.
+AT_CHECK([ovn-nbctl lport-set-type br-vtep_lswitch0 void])
+OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=tunnel_key list Logical_Switch | grep 1`"])
+# now should see the tunnel key reset.
+AT_CHECK([vtep-ctl --columns=tunnel_key list Logical_Switch | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+0
+])
+
+OVN_CONTROLLER_VTEP_STOP
+AT_CLEANUP
+
+
+# Tests vtep module 'Ucast_Macs_Remote's.
+AT_SETUP([ovn-controller-vtep - test vtep-macs 1])
+OVN_CONTROLLER_VTEP_START
+
+# creates a simple logical network with the vtep device and a fake hv chassis
+# 'ch0'.
+AT_CHECK([ovn-nbctl lport-add br-test vif0])
+AT_CHECK([ovn-nbctl lport-set-addresses vif0 f0:ab:cd:ef:01:02])
+AT_CHECK([ovn-sbctl chassis-add ch0 vxlan 1.2.3.5])
+AT_CHECK([ovn-sbctl lport-bind vif0 ch0])
+
+# creates the logical switch in vtep and adds the corresponding logical
+# port to 'br-test'.
+AT_CHECK([vtep-ctl add-ls lswitch0 -- bind-ls br-vtep p0 100 lswitch0])
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0], [br-vtep], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep br-vtep_lswitch0`"])
+
+# adds another lswitch 'br-void' in ovn-nb database.
+AT_CHECK([ovn-nbctl lswitch-add br-void])
+# adds fake hv chassis 'ch1'.
+AT_CHECK([ovn-nbctl lport-add br-void vif1])
+AT_CHECK([ovn-nbctl lport-set-addresses vif1 f0:ab:cd:ef:01:02])
+AT_CHECK([ovn-sbctl chassis-add ch1 vxlan 1.2.3.6])
+AT_CHECK([ovn-sbctl lport-bind vif1 ch1])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep vif1`"])
+
+# checks Ucast_Macs_Remote creation.
+OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Remote | grep _uuid`"])
+AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' '], [0], [dnl
+"f0:ab:cd:ef:01:02"
+])
+
+# checks physical locator creation.
+OVS_WAIT_UNTIL([test -n "`vtep-ctl list Physical_Locator | grep _uuid`"])
+AT_CHECK([vtep-ctl --columns=dst_ip list Physical_Locator | cut -d ':' -f2 | tr -d ' ' | grep -v 1.2.3.4 | sed '/^$/d'], [0], [dnl
+"1.2.3.5"
+])
+
+# checks tunnel creation by ovs-vtep.
+OVS_WAIT_UNTIL([test -n "`ovs-vsctl list Interface bfd1.2.3.5`"])
+AT_CHECK([ovs-vsctl --columns=options list Interface bfd1.2.3.5 | cut -d ':' -f2 | tr -d ' '], [0], [dnl
+{remote_ip="1.2.3.5"}
+])
+
+# adds another mac to lport.
+AT_CHECK([ovn-nbctl lport-set-addresses vif0 f0:ab:cd:ef:01:02 f0:ab:cd:ef:01:03])
+OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Remote | grep 03`"])
+AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
+
+"f0:ab:cd:ef:01:02"
+"f0:ab:cd:ef:01:03"
+])
+
+# removes one mac to lport.
+AT_CHECK([ovn-nbctl lport-set-addresses vif0 f0:ab:cd:ef:01:03])
+OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=MAC list Ucast_Macs_Remote | grep 02`"])
+AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
+"f0:ab:cd:ef:01:03"
+])
+
+# migrates mac to lport vif1 on 'br-void'.
+AT_CHECK([ovn-nbctl lport-set-addresses vif0])
+AT_CHECK([ovn-nbctl lport-set-addresses vif1 f0:ab:cd:ef:01:03])
+OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=MAC list Ucast_Macs_Remote | grep 03`"])
+AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
+])
+
+OVN_CONTROLLER_VTEP_STOP
+AT_CLEANUP
+
+
+# Tests vtep module 'Ucast_Macs_Remote's (corner cases).
+AT_SETUP([ovn-controller-vtep - test vtep-macs 2])
+OVN_CONTROLLER_VTEP_START
+
+# creates a simple logical network with the vtep device and a fake hv chassis
+# 'ch0'.
+AT_CHECK([ovn-nbctl lport-add br-test vif0])
+AT_CHECK([ovn-nbctl lport-set-addresses vif0 f0:ab:cd:ef:01:02])
+AT_CHECK([ovn-sbctl chassis-add ch0 vxlan 1.2.3.5])
+AT_CHECK([ovn-sbctl lport-bind vif0 ch0])
+
+# creates another vif in the same logical switch with duplicate mac.
+AT_CHECK([ovn-nbctl lport-add br-test vif1])
+AT_CHECK([ovn-nbctl lport-set-addresses vif1 f0:ab:cd:ef:01:02])
+AT_CHECK([ovn-sbctl lport-bind vif1 ch0])
+
+# creates the logical switch in vtep and adds the corresponding logical
+# port to 'br-test'.
+AT_CHECK([vtep-ctl add-ls lswitch0 -- bind-ls br-vtep p0 100 lswitch0])
+OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0], [br-vtep], [lswitch0])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep br-vtep_lswitch0`"])
+
+# checks Ucast_Macs_Remote creation. Should still only be one entry, since duplicate
+# mac in the same logical switch is not allowed.
+OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Remote | grep _uuid`"])
+AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' '], [0], [dnl
+"f0:ab:cd:ef:01:02"
+])
+# confirms the warning log.
+OVS_WAIT_UNTIL([test -n "`grep WARN ovn-controller-vtep.log`"])
+AT_CHECK([sed -n 's/^.*\(|WARN|.*\)$/\1/p' ovn-controller-vtep.log | sed 's/([[-_:0-9a-z]][[-_:0-9a-z]]*)/()/g' | uniq], [0], [dnl
+|WARN|MAC address () has already been known to be on logical port () in the same logical datapath, so just ignore this logical port ()
+])
+
+# deletes vif1.
+AT_CHECK([ovn-nbctl lport-del vif1])
+
+# adds another lswitch 'br-void' in ovn-nb database.
+AT_CHECK([ovn-nbctl lswitch-add br-void])
+# adds fake hv chassis 'ch1' and vif1 with same mac address as vif0.
+AT_CHECK([ovn-nbctl lport-add br-void vif1])
+AT_CHECK([ovn-nbctl lport-set-addresses vif1 f0:ab:cd:ef:01:02])
+AT_CHECK([ovn-sbctl chassis-add ch1 vxlan 1.2.3.6])
+AT_CHECK([ovn-sbctl lport-bind vif1 ch1])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep vif1`"])
+
+# creates another logical switch in vtep and adds the corresponding logical
+# port to 'br-void'.
+AT_CHECK([vtep-ctl add-ls lswitch1 -- bind-ls br-vtep p0 200 lswitch1])
+OVN_NB_ADD_VTEP_PORT([br-void], [br-void_lswitch1], [br-vtep], [lswitch1])
+OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep br-void_lswitch1`"])
+
+# checks Ucast_Macs_Remote creation. Should see two entries since it is allowed
+# to have duplicate macs in different logical switches.
+OVS_WAIT_UNTIL([test `vtep-ctl --columns=MAC list Ucast_Macs_Remote | grep 02 | wc -l` -gt 1])
+AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
+
+"f0:ab:cd:ef:01:02"
+"f0:ab:cd:ef:01:02"
+])
+
+OVN_CONTROLLER_VTEP_STOP([/has already been known to be on logical port/d])