From: itamaro <itamar.o...@gmail.com>

This patch adds support for handeling a per-tunnel tunnel key in the
ovs-vtep and vtep-ctl to support the usage of neutron L2GW as an
inter-cloud gateway.

The Neutron spec is available here:
https://review.openstack.org/#/c/270786/

The aim of this patch is to support the usage of hardware vtep switch as
an inter-cloud gateway, which is used to connect two separated l2 broadcast
domains. This document will also explain the logic behind the addition of the 
new per-tunnel tunnel-key in the hardware_vtep schema.  

The introduction of the relay tunnel, does not change the current logic of 
hardware_vtep, it does however introduce new logic related to iner-cloud
connectivity.


Network layout
==============

    virtual network 1                 shared  network         virtual network 2 
    +------------+                                                  
+------------+
    |Compute Host|   VNI=1                                    VNI=2 |Compute 
Host|
    |   +--+     <---------+                                +------->   +--+    
 |
    |   |vm|     |         |                                |       |   |vm|    
 |
    |   +--+     |         |           L3 network           |       |   +--+    
 |
    +---^--------+         |                                |       
+---------^--+
        |          +-------v--------+      X     +----------v-----+           | 
  
        |      +---> hardware_vtep  |      X     | hardware_vtep  |           | 
  
        | VNI=1|   | logical switch |      X     | logical switch <-----+     | 
  
        |      |   | (tunnel_key 1) |==<<==X=>>==| (tunnel_key 2) |     |VNI=2| 
  
        |      |   |   +-+     +-+  |      X     |   +-+      +-+ |     |     | 
  
        |      |   |   |-|     |-|  |      X     |   |-|      |-| |     |     | 
  
    +---v------v-+ +----------------+      X     +----------------+     |     | 
  
    |Compute Host| vlan2|       |vlan5           vlan9|        |vlan21  |     | 
  
    |   +--+     |      |       |    relay vxlan      |        |    
+---v-----v--+
    |   |vm|     |      |       |      VNI=100        |        |    |Compute 
Host|
    |   +--+     |      |       |                     |        |    |   +--+    
 |
    +------------+    +-v-+   +-v-+                 +-v-+    +-v-+  |   |vm|    
 |
                      |   |   |   |                 |   |    |   |  |   +--+    
 |
                      |   |   |   |                 |   |    |   |  
+------------+
                      +---+   +---+                 +---+    +---+              
  
                    Bare metal elements             Bare metal elements

Logical switch
===============
In a cloud architecture, there is sometimes need to connect virtual machines
and physical machines to the same L2 broadcast domain.
A logical switch is an entity representing an l2 virtual overlay network,
identified by a shared tunnel key. This tunnel key (VxLAN VNI) is shared among
all overlay virtual tunnel endpoints (VTEP) of the switch.
The logical switch binds physical ports with either identical or different
"VLAN" tags to the "VxLAN overlay" network.

In a multi-cloud architecture, it may be useful to establish a cross-cloud 
l2 broadcast domain. The extended hardware vtep uses a relay l2 tunnel,
which is a tunnel with an explicit tunnel-key property. The tunnel-key propery 
is used to map each overlay network (logical switch tunnel-key) in each cloud to
the tunnel-key of the relay tunnel.

The mapping to a remote logical switch is done by defining the same tunnel key
in both ends of the the relay tunnel. This tunnel key (VxLAN VNI) is a
property of the relay tunnel itself.

To support the above tunnel behevior, a new kind of VTEP port is logic is
introduced, defining two VTEP port groups. One group represents the existing
VTEP ports of the local l2 overlay network, and another new group represents the
individual l2 relay VTEPS.

Multicast and Unknown unicast traffic
=====================================
Currently Broadcast, Unknown unicast, and Multicast,"BUM" traffic to the 
overlay networks
is handled by two replication modes:

  - "source_node" mode: The packets originated from physical port
    are replicated on all the VTEPs ports pointed by unknown-dst, and flooded
    to all the physical bound ports.

  - "service_node" mode: The packets originated from physical port are
    forwarded to only a selected single service node from the unknown-dst ports
    (the service node responsible for "BUM" propagation to the overlay network),
    and flooded to all the physical bound ports.

In either of the replication modes BUM traffic originated from a VTEP port is
flooded only to all physical ports.

Considering the new l2-relay VTEPs ports group, relay related BUM traffic is 
handled as follows:
  - BUM packets from Physical Port and from local overlay network are replicated
    to the unknown-dst l2-relay ports. 
       The reason is that a relay VTEP is not a part of the local managed
       network and BUM traffic to the relay VTEPs cannot be suppressed by a
       local service node.
  - BUM packets from relay VTEPs are handled according to the replicating mode
    and not forwarded/replicated to the l2-relay ports.
       It is assumed that relay tunnels do not interconnect remote networks.

To sum it up, the role of the l2-relay is merely to connect two distinct 
broadcast domains, it will otherwise never be used as a switching fabric among
the different remote l2 networks.

ovs-vtep manifested changes
===========================

1. The code need to distinguish between overlay (mesh) VTEPs, and relay VTEPs.
2. BUM traffic
    * BUM traffic from either mesh or bare metal network is replicated on all
      relay 'unknown-dst' VTEP.
    * BUM traffic from relay VTEP, is handled according to the replicating mode
      and is not forwarded/replicated to the l2-relay ports.


Requested-by: "Ofer Ben-Yacov" <ofer.benya...@gmail.com>
Signed-off-by: "Itamar Ofek" <itamar.o...@gmail.com>
---
 tests/vtep-ctl.at | 145 +++++++++++++++++++++++++++++++++++++++++++++++-------
 vtep/ovs-vtep     | 102 +++++++++++++++++++++++++-------------
 vtep/vtep-ctl.c   | 138 ++++++++++++++++++++++++++++++++++-----------------
 3 files changed, 286 insertions(+), 99 deletions(-)

diff --git a/tests/vtep-ctl.at b/tests/vtep-ctl.at
index f0511ad..4178309 100644
--- a/tests/vtep-ctl.at
+++ b/tests/vtep-ctl.at
@@ -433,12 +433,16 @@ AT_CHECK([RUN_VTEP_CTL(
 CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-local ls1 00:11:22:33:44:55 10.0.0.10],
-   [add-ucast-local ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11])
+   [add-ucast-local ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
+   [add-ucast-local ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-local ls1 00:11:22:33:55:77 vxlan_over_ipv4 10.0.0.13 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.12 [[100]]
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-local
 
@@ -460,11 +464,20 @@ AT_CHECK([RUN_VTEP_CTL(
 CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-local ls1 00:11:22:33:44:55 10.0.0.10],
-   [add-ucast-local ls1 00:11:22:33:44:55 10.0.0.11])
+   [add-ucast-local ls1 00:11:22:33:44:55 10.0.0.11],
+   [add-ucast-local ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-local ls1 00:11:22:33:55:66 10.0.0.13 200],
+   [add-ucast-local ls1 00:11:22:33:55:77 10.0.0.14 300],
+   [add-ucast-local ls1 00:11:22:33:55:77 10.0.0.15],
+   [add-ucast-local ls1 00:11:22:33:55:88 10.0.0.16],
+   [add-ucast-local ls1 00:11:22:33:55:88 10.0.0.17 400])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.13 [[200]]
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15
+  00:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.17 [[400]]
 
 mcast-mac-local
 
@@ -480,22 +493,28 @@ AT_CHECK([RUN_VTEP_CTL(
 CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-local ls1 00:11:22:33:44:55 10.0.0.10],
-   [add-ucast-local ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11])
+   [add-ucast-local ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
+   [add-ucast-local ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-local ls1 00:11:22:33:55:77 vxlan_over_ipv4 10.0.0.13 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.12 [[100]]
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-local
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
-   [del-ucast-local ls1 00:11:22:33:44:55])
+   [del-ucast-local ls1 00:11:22:33:44:55],
+   [del-ucast-local ls1 00:11:22:33:55:66])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-local
 
@@ -511,12 +530,16 @@ AT_CHECK([RUN_VTEP_CTL(
 CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.10],
-   [add-ucast-remote ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11])
+   [add-ucast-remote ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
+   [add-ucast-remote ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-remote ls1 00:11:22:33:55:77 10.0.0.13 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.12 [[100]]
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-remote
 
@@ -538,11 +561,14 @@ AT_CHECK([RUN_VTEP_CTL(
 CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.10],
-   [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.11])
+   [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.11],
+   [add-ucast-remote ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-remote ls1 00:11:22:33:55:66 10.0.0.13 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-remote
 
@@ -558,22 +584,28 @@ AT_CHECK([RUN_VTEP_CTL(
 CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.10],
-   [add-ucast-remote ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11])
+   [add-ucast-remote ls1 00:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
+   [add-ucast-remote ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-remote ls1 00:11:22:33:55:77 vxlan_over_ipv4 10.0.0.13 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.12 [[100]]
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-remote
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
-   [del-ucast-remote ls1 00:11:22:33:44:55])
+   [del-ucast-remote ls1 00:11:22:33:44:55],
+   [del-ucast-remote ls1 00:11:22:33:55:66])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-remote
 
@@ -590,13 +622,19 @@ CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-local ls1 00:11:22:33:44:55 10.0.0.10],
    [add-ucast-local ls1 00:11:22:33:44:66 10.0.0.11],
+   [add-ucast-local ls1 00:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-local ls1 00:11:22:33:55:77 vxlan_over_ipv4 10.0.0.13 200],
    [add-ucast-remote ls1 02:11:22:33:44:55 10.0.0.10],
-   [add-ucast-remote ls1 02:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11])
+   [add-ucast-remote ls1 02:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
+   [add-ucast-remote ls1 02:11:22:33:55:66 10.0.0.12 100],
+   [add-ucast-remote ls1 02:11:22:33:55:77 vxlan_over_ipv4 10.0.0.13 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
   00:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   00:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  00:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.12 [[100]]
+  00:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-local
 
@@ -605,6 +643,8 @@ AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
   02:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   02:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  02:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.12 [[100]]
+  02:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.13 [[200]]
 
 mcast-mac-remote
 
@@ -621,7 +661,9 @@ CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.10],
    [add-mcast-local ls1 01:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
-   [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.12])
+   [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.12],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.13 100],
+   [add-mcast-local ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.14 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -630,6 +672,8 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.13 [[100]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.14 [[200]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -651,7 +695,9 @@ AT_CHECK([RUN_VTEP_CTL(
    [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.10],
    [add-mcast-local ls1 01:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
    [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.12],
-   [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.13])
+   [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.13],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-local ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -661,10 +707,13 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.13
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[200]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
-   [del-mcast-local ls1 01:11:22:33:44:55 10.0.0.12])
+   [del-mcast-local ls1 01:11:22:33:44:55 10.0.0.12],
+   [del-mcast-local ls1 01:11:22:33:55:66 10.0.0.14])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -673,6 +722,7 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.13
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[200]]
 
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
@@ -687,7 +737,10 @@ CHECK_LSWITCHES([ls1])
 AT_CHECK([RUN_VTEP_CTL(
    [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 01:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
-   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12])
+   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12],
+   [add-mcast-remote ls1 01:11:22:33:55:66 10.0.0.13 100],
+   [add-mcast-remote ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.14 300],
+   [add-mcast-remote ls1 01:11:22:33:55:66 10.0.0.15 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
@@ -696,6 +749,9 @@ mcast-mac-remote
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.13 [[100]]
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.15 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.14 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
@@ -717,7 +773,10 @@ AT_CHECK([RUN_VTEP_CTL(
    [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 01:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
    [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12],
-   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.13])
+   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.13],
+   [add-mcast-remote ls1 01:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-remote ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-remote ls1 01:11:22:33:55:66 10.0.0.16 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
@@ -727,10 +786,14 @@ mcast-mac-remote
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.13
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
-   [del-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12])
+   [del-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12],
+   [del-mcast-remote ls1 01:11:22:33:55:66 10.0.0.14])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
@@ -739,6 +802,8 @@ mcast-mac-remote
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.13
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
@@ -756,7 +821,13 @@ AT_CHECK([RUN_VTEP_CTL(
    [add-mcast-local ls1 01:11:22:33:44:55 10.0.0.12],
    [add-mcast-remote ls1 03:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 03:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
-   [add-mcast-remote ls1 03:11:22:33:44:55 10.0.0.12])
+   [add-mcast-remote ls1 03:11:22:33:44:55 10.0.0.12],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-local ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.16 200],
+   [add-mcast-remote ls1 03:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-remote ls1 03:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-remote ls1 03:11:22:33:55:66 10.0.0.16 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -765,6 +836,9 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -774,7 +848,10 @@ mcast-mac-remote
   03:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   03:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   03:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
-
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  03:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
+  
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
 AT_CLEANUP
@@ -793,7 +870,13 @@ AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 01:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
-   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12])
+   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-local ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.16 200],
+   [add-mcast-remote ls1 03:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-remote ls1 03:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-remote ls1 03:11:22:33:55:66 10.0.0.16 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -803,6 +886,9 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -813,6 +899,9 @@ mcast-mac-remote
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  03:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
@@ -831,6 +920,9 @@ mcast-mac-remote
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  03:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
@@ -850,7 +942,13 @@ AT_CHECK([RUN_VTEP_CTL(
    [add-ucast-remote ls1 00:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.10],
    [add-mcast-remote ls1 01:11:22:33:44:66 vxlan_over_ipv4 10.0.0.11],
-   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12])
+   [add-mcast-remote ls1 01:11:22:33:44:55 10.0.0.12],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-local ls1 01:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-local ls1 01:11:22:33:55:66 10.0.0.16 200],
+   [add-mcast-remote ls1 03:11:22:33:55:66 10.0.0.14 100],
+   [add-mcast-remote ls1 03:11:22:33:55:77 vxlan_over_ipv4 10.0.0.15 300],
+   [add-mcast-remote ls1 03:11:22:33:55:66 10.0.0.16 200])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -860,6 +958,9 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -870,6 +971,9 @@ mcast-mac-remote
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  03:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  03:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
@@ -882,6 +986,9 @@ mcast-mac-local
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.10
   01:11:22:33:44:55 -> vxlan_over_ipv4/10.0.0.12
   01:11:22:33:44:66 -> vxlan_over_ipv4/10.0.0.11
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.14 [[100]]
+  01:11:22:33:55:66 -> vxlan_over_ipv4/10.0.0.16 [[200]]
+  01:11:22:33:55:77 -> vxlan_over_ipv4/10.0.0.15 [[300]]
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
diff --git a/vtep/ovs-vtep b/vtep/ovs-vtep
index b32a82a..360f9fd 100755
--- a/vtep/ovs-vtep
+++ b/vtep/ovs-vtep
@@ -120,30 +120,52 @@ class Logical_Switch(object):
         for port_no, tun_name, remote_ip in six.itervalues(self.tunnels):
             del_bfd(remote_ip)
 
-    def update_flood(self):
-        flood_ports = list(self.ports.values())
+    def vtep_ports(self, tunnel_list):
+        relay_ports, mesh_ports = list(), list()
+        for tunnel in tunnel_list:
+            if self.tunnels[tunnel][3]:
+                relay_ports.append(self.tunnels[tunnel][0])
+                continue
+            mesh_ports.append(self.tunnels[tunnel][0])
+        return relay_ports, mesh_ports
 
-        # Traffic flowing from one 'unknown-dst' should not be flooded to
-        # port belonging to another 'unknown-dst'.
-        for tunnel in self.unknown_dsts:
-            port_no = self.tunnels[tunnel][0]
-            ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
-                      % (self.short_name, port_no, ",".join(flood_ports)))
+    def update_flood(self):
+        phy_ports = list(self.ports.values())
+        relay_ports, mesh_ports = self.vtep_ports(self.tunnels.keys())
+        relay_unknown, mesh_unknown = self.vtep_ports(self.unknown_dsts)
 
         # Traffic coming from a VTEP physical port should always be flooded to
         # all the other physical ports that belong to that VTEP device and
-        # this logical switch.  If the replication mode is service node then
+        # this logical switch and all relay VTEP ports.
+        # If the replication mode is service node then
         # send to one unknown_dst node (the first one here); else we assume the
         # replication mode is source node and we send the packet to all
         # unknown_dst nodes.
-        for tunnel in self.unknown_dsts:
-            port_no = self.tunnels[tunnel][0]
-            flood_ports.append(port_no)
+
+        phy_flood_ports = phy_ports + relay_unknown
+        if len(mesh_unknown) > 0:
             if self.replication_mode == "service_node":
-                break
+                phy_flood_ports += mesh_unknown[0]
+            else:
+                phy_flood_ports += mesh_unknown
+        for port_no in phy_ports:
+            ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
+                      % (self.short_name, port_no, ",".join(phy_flood_ports)))
+
+        # Traffic flowing from a mesh VTEP should not be flooded to mesh
+        # unknown-dst ports
+        mesh_flood_ports = phy_ports + relay_unknown
+        for port_no in mesh_ports:
+            ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
+                      % (self.short_name, port_no, ",".join(mesh_flood_ports)))
 
-        ovs_ofctl("add-flow %s table=1,priority=0,action=%s"
-                  % (self.short_name, ",".join(flood_ports)))
+        # Traffic flowing from a relay VTEP should not be flooded to relay
+        # unknown-dst ports
+        relay_flood_ports = phy_ports + mesh_unknown
+        for port_no in relay_ports:
+            ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
+                      % (self.short_name,
+                          port_no, ",".join(relay_flood_ports)))
 
     def add_lbinding(self, lbinding):
         vlog.info("adding %s binding to %s" % (lbinding, self.name))
@@ -164,11 +186,22 @@ class Logical_Switch(object):
         del self.ports[lbinding]
         self.update_flood()
 
+    def tunnel_dict(self, entry):
+        return {
+                'tunnel_type': entry[2],
+                'dest_ip': entry[3],
+                'tunnel_key': entry[5],
+               }
+
     def add_tunnel(self, tunnel, tunnel_key):
         global tun_id
-        vlog.info("adding tunnel %s" % tunnel)
-        encap, ip = tunnel.split("/")
+        if tunnel['tunnel_key']:
+            tunnel_key = tunnel['tunnel_key']
+        vlog.info("adding tunnel %s key %s" % (tunnel['dest_ip'],
+                   tunnel_key))
 
+        encap = tunnel['tunnel_type']
+        ip = tunnel['dest_ip']
         if encap != "vxlan_over_ipv4":
             vlog.warn("unsupported tunnel format %s" % encap)
             return
@@ -192,7 +225,7 @@ class Logical_Switch(object):
             # Give the system a moment to allocate the port number
             time.sleep(0.5)
 
-        self.tunnels[tunnel] = (port_no, tun_name, ip)
+        self.tunnels[ip] = (port_no, tun_name, ip, tunnel['tunnel_key'])
 
         add_bfd(ip)
 
@@ -200,17 +233,17 @@ class Logical_Switch(object):
                   "actions=resubmit(,1)"
                   % (self.short_name, port_no))
 
-    def del_tunnel(self, tunnel):
-        vlog.info("removing tunnel %s" % tunnel)
+    def del_tunnel(self, tunnel_ip):
+        vlog.info("removing tunnel %s" % tunnel_ip)
 
-        port_no, tun_name, remote_ip = self.tunnels[tunnel]
+        port_no, tun_name, remote_ip, tunnel_key = self.tunnels[tunnel_ip]
         ovs_ofctl("del-flows %s table=0,in_port=%s"
                   % (self.short_name, port_no))
         ovs_vsctl("del-port %s %s" % (self.short_name, tun_name))
 
         del_bfd(remote_ip)
 
-        del self.tunnels[tunnel]
+        del self.tunnels[tunnel_ip]
 
     def update_local_macs(self):
         flows = ovs_ofctl("dump-flows %s cookie=0x5000/-1,table=1"
@@ -231,8 +264,8 @@ class Logical_Switch(object):
 
         self.local_macs = macs
 
-    def add_remote_mac(self, mac, tunnel):
-        port_no = self.tunnels.get(tunnel, (0, ""))[0]
+    def add_remote_mac(self, mac, tunnel_ip):
+        port_no = self.tunnels.get(tunnel_ip, (0, ""))[0]
         if not port_no:
             return
 
@@ -245,7 +278,7 @@ class Logical_Switch(object):
     def update_remote_macs(self):
         remote_macs = {}
         unknown_dsts = set()
-        tunnels = set()
+        tunnels = {}
         parse_ucast = True
 
         column = vtep_ctl("--columns=tunnel_key find logical_switch "
@@ -264,27 +297,26 @@ class Logical_Switch(object):
             if (line.find("mcast-mac-remote") != -1):
                 parse_ucast = False
                 continue
-
-            entry = re.split(r'  (.*) -> (.*)', line)
-            if len(entry) != 4:
+            entry = re.split(r'  (.*) -> ([^/]*)/(\S*)( \[(.*)\])?', line)
+            if len(entry) != 7:
                 continue
 
             if parse_ucast:
-                remote_macs[entry[1]] = entry[2]
+                remote_macs[entry[1]] = self.tunnel_dict(entry)['tunnel_type']
             else:
                 if entry[1] != "unknown-dst":
                     continue
 
-                unknown_dsts.add(entry[2])
+                unknown_dsts.add(entry[3])
 
-            tunnels.add(entry[2])
+            tunnels[entry[3]] = self.tunnel_dict(entry)
 
         old_tunnels = set(self.tunnels.keys())
+        tunnels_keys = set(tunnels.keys())
+        for tunnel in tunnels_keys.difference(old_tunnels):
+            self.add_tunnel(tunnels[tunnel], tunnel_key)
 
-        for tunnel in tunnels.difference(old_tunnels):
-            self.add_tunnel(tunnel, tunnel_key)
-
-        for tunnel in old_tunnels.difference(tunnels):
+        for tunnel in old_tunnels.difference(tunnels_keys):
             self.del_tunnel(tunnel)
 
         for mac in six.iterkeys(remote_macs):
diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
index 759150f..1904a71 100644
--- a/vtep/vtep-ctl.c
+++ b/vtep/vtep-ctl.c
@@ -37,6 +37,7 @@
 #include "json.h"
 #include "ovsdb-data.h"
 #include "ovsdb-idl.h"
+#include "lib/packets.h"
 #include "poll-loop.h"
 #include "process.h"
 #include "stream.h"
@@ -345,18 +346,18 @@ Logical Router commands:\n\
   lr-exists LR                exit 2 if LR does not exist\n\
 \n\
 MAC binding commands:\n\
-  add-ucast-local LS MAC [ENCAP] IP   add ucast local entry in LS\n\
-  del-ucast-local LS MAC              del ucast local entry from LS\n\
-  add-mcast-local LS MAC [ENCAP] IP   add mcast local entry in LS\n\
-  del-mcast-local LS MAC [ENCAP] IP   del mcast local entry from LS\n\
-  clear-local-macs LS                 clear local mac entries\n\
-  list-local-macs LS                  list local mac entries\n\
-  add-ucast-remote LS MAC [ENCAP] IP  add ucast remote entry in LS\n\
-  del-ucast-remote LS MAC             del ucast remote entry from LS\n\
-  add-mcast-remote LS MAC [ENCAP] IP  add mcast remote entry in LS\n\
-  del-mcast-remote LS MAC [ENCAP] IP  del mcast remote entry from LS\n\
-  clear-remote-macs LS                clear remote mac entries\n\
-  list-remote-macs LS                 list remote mac entries\n\
+  add-ucast-local LS MAC [ENCAP] IP [KEY]   add ucast local entry in LS\n\
+  del-ucast-local LS MAC                    del ucast local entry from LS\n\
+  add-mcast-local LS MAC [ENCAP] IP [KEY]   add mcast local entry in LS\n\
+  del-mcast-local LS MAC [ENCAP] IP         del mcast local entry from LS\n\
+  clear-local-macs LS                       clear local mac entries\n\
+  list-local-macs LS                        list local mac entries\n\
+  add-ucast-remote LS MAC [ENCAP] IP [KEY]  add ucast remote entry in LS\n\
+  del-ucast-remote LS MAC                   del ucast remote entry from LS\n\
+  add-mcast-remote LS MAC [ENCAP] IP [KEY]  add mcast remote entry in LS\n\
+  del-mcast-remote LS MAC [ENCAP] IP        del mcast remote entry from LS\n\
+  clear-remote-macs LS                      clear remote mac entries\n\
+  list-remote-macs LS                       list remote mac entries\n\
 \n\
 %s\
 \n\
@@ -887,7 +888,8 @@ pre_get_info(struct ctl_context *ctx)
                          &vteprec_physical_locator_col_dst_ip);
     ovsdb_idl_add_column(ctx->idl,
                          &vteprec_physical_locator_col_encapsulation_type);
-
+    ovsdb_idl_add_column(ctx->idl,
+                         &vteprec_physical_locator_col_tunnel_key);
     ovsdb_idl_add_column(ctx->idl, &vteprec_tunnel_col_local);
     ovsdb_idl_add_column(ctx->idl, &vteprec_tunnel_col_remote);
 }
@@ -1653,27 +1655,46 @@ add_ucast_entry(struct ctl_context *ctx, bool local)
 {
     struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
     struct vtep_ctl_lswitch *ls;
-    const char *mac;
-    const char *encap;
-    const char *dst_ip;
+    const char *mac = 0;
+    const char *encap = 0;
+    const char *dst_ip = 0;
+    const char *tunnel_key = 0;
     struct vteprec_physical_locator *ploc_cfg;
+    ovs_be32 ip = 0;
 
     vtep_ctl_context_populate_cache(ctx);
 
     ls = find_lswitch(vtepctl_ctx, ctx->argv[1], true);
     mac = ctx->argv[2];
-
-    if (ctx->argc == 4) {
-        encap = "vxlan_over_ipv4";
-        dst_ip = ctx->argv[3];
-    } else {
-        encap = ctx->argv[3];
-        dst_ip = ctx->argv[4];
+    switch (ctx->argc)
+    {
+        case 6:
+            tunnel_key = ctx->argv[5];
+        case 5:
+            if (ip_parse(ctx->argv[4],&ip)){
+                dst_ip = ctx->argv[4];
+                encap = ctx->argv[3];
+                break;
+            }
+            tunnel_key = ctx->argv[4];
+        case 4:
+            if (ip_parse(ctx->argv[3],&ip)){
+                dst_ip = ctx->argv[3];
+                encap = "vxlan_over_ipv4";
+            }
+            break;
+        default:
+            break;
     }
 
     ploc_cfg = find_ploc(vtepctl_ctx, encap, dst_ip);
     if (!ploc_cfg) {
         ploc_cfg = vteprec_physical_locator_insert(ctx->txn);
+        if (tunnel_key) {
+            int64_t segement_value = 0;
+            ovs_scan(tunnel_key,"%ld",&segement_value);
+            
vteprec_physical_locator_set_tunnel_key(ploc_cfg,&segement_value,1);
+        }
         vteprec_physical_locator_set_dst_ip(ploc_cfg, dst_ip);
         vteprec_physical_locator_set_encapsulation_type(ploc_cfg, encap);
 
@@ -1790,7 +1811,7 @@ commit_mcast_entries(struct vtep_ctl_mcast_mac *mcast_mac)
 static void
 add_mcast_entry(struct ctl_context *ctx,
                 struct vtep_ctl_lswitch *ls, const char *mac,
-                const char *encap, const char *dst_ip, bool local)
+                const char *encap, const char *dst_ip, const char* 
tunnel_key,bool local)
 {
     struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
     struct shash *mcast_shash;
@@ -1839,6 +1860,11 @@ add_mcast_entry(struct ctl_context *ctx,
     ploc_cfg = find_ploc(vtepctl_ctx, encap, dst_ip);
     if (!ploc_cfg) {
         ploc_cfg = vteprec_physical_locator_insert(ctx->txn);
+        if (tunnel_key) {
+            int64_t tunnel_id = 0;
+            ovs_scan(tunnel_key,"%ld",&tunnel_id);
+            vteprec_physical_locator_set_tunnel_key(ploc_cfg,&tunnel_id,1);
+        }
         vteprec_physical_locator_set_dst_ip(ploc_cfg, dst_ip);
         vteprec_physical_locator_set_encapsulation_type(ploc_cfg, encap);
 
@@ -1908,25 +1934,39 @@ add_del_mcast_entry(struct ctl_context *ctx, bool add, 
bool local)
 {
     struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
     struct vtep_ctl_lswitch *ls;
-    const char *mac;
-    const char *encap;
-    const char *dst_ip;
-
+    const char *mac = 0;
+    const char *encap = 0;
+    const char *dst_ip = 0;
+    const char *tunnel_key = 0;
+    ovs_be32 ip = 0;
     vtep_ctl_context_populate_cache(ctx);
 
     ls = find_lswitch(vtepctl_ctx, ctx->argv[1], true);
     mac = ctx->argv[2];
 
-    if (ctx->argc == 4) {
-        encap = "vxlan_over_ipv4";
-        dst_ip = ctx->argv[3];
-    } else {
-        encap = ctx->argv[3];
-        dst_ip = ctx->argv[4];
+    switch (ctx->argc)
+    {
+        case 6:
+            tunnel_key = ctx->argv[5];
+        case 5:
+            if (ip_parse(ctx->argv[4],&ip)){
+                dst_ip = ctx->argv[4];
+                encap = ctx->argv[3];
+                break;
+            }
+            tunnel_key = ctx->argv[4];
+        case 4:
+            if (ip_parse(ctx->argv[3],&ip)){
+                dst_ip = ctx->argv[3];
+                encap = "vxlan_over_ipv4";
+            }
+            break;
+        default:
+            break;
     }
 
     if (add) {
-        add_mcast_entry(ctx, ls, mac, encap, dst_ip, local);
+        add_mcast_entry(ctx, ls, mac, encap, dst_ip, tunnel_key, local);
     } else {
         del_mcast_entry(ctx, ls, mac, encap, dst_ip, local);
     }
@@ -2017,7 +2057,7 @@ list_macs(struct ctl_context *ctx, bool local)
     struct svec ucast_macs;
     struct shash *mcast_shash;
     struct svec mcast_macs;
-
+    char tunnel_key[8];
     vtep_ctl_context_populate_cache(ctx);
     ls = find_lswitch(vtepctl_ctx, ctx->argv[1], true);
 
@@ -2032,9 +2072,13 @@ list_macs(struct ctl_context *ctx, bool local)
         char *entry;
 
         ploc_cfg = local ? ucast_local->locator : ucast_remote->locator;
-
-        entry = xasprintf("  %s -> %s/%s", node->name,
-                          ploc_cfg->encapsulation_type, ploc_cfg->dst_ip);
+        tunnel_key[0] = 0;
+        if (ploc_cfg->tunnel_key)
+            snprintf(&tunnel_key[0],8," 
[%d]",(uint32_t)(*ploc_cfg->tunnel_key));
+        entry = xasprintf("  %s -> %s/%s%s", node->name,
+                          ploc_cfg->encapsulation_type,
+                          ploc_cfg->dst_ip,
+                          tunnel_key );
         svec_add_nocopy(&ucast_macs, entry);
     }
     ds_put_format(&ctx->output, "ucast-mac-%s\n", local ? "local" : "remote");
@@ -2049,9 +2093,13 @@ list_macs(struct ctl_context *ctx, bool local)
         char *entry;
 
         LIST_FOR_EACH (ploc, locators_node, &mcast_mac->locators) {
-            entry = xasprintf("  %s -> %s/%s", node->name,
+            tunnel_key[0] = 0;
+            if (ploc->ploc_cfg->tunnel_key)
+                snprintf(tunnel_key,8," 
[%d]",(uint32_t)(*ploc->ploc_cfg->tunnel_key));
+            entry = xasprintf("  %s -> %s/%s%s", node->name,
                               ploc->ploc_cfg->encapsulation_type,
-                              ploc->ploc_cfg->dst_ip);
+                              ploc->ploc_cfg->dst_ip,
+                              tunnel_key);
             svec_add_nocopy(&mcast_macs, entry);
         }
     }
@@ -2508,11 +2556,11 @@ static const struct ctl_command_syntax vtep_commands[] 
= {
     {"lr-exists", 1, 1, NULL, pre_get_info, cmd_lr_exists, NULL, "", RO},
 
     /* MAC binding commands. */
-    {"add-ucast-local", 3, 4, NULL, pre_get_info, cmd_add_ucast_local, NULL,
+    {"add-ucast-local", 3, 5, NULL, pre_get_info, cmd_add_ucast_local, NULL,
      "", RW},
     {"del-ucast-local", 2, 2, NULL, pre_get_info, cmd_del_ucast_local, NULL,
      "", RW},
-    {"add-mcast-local", 3, 4, NULL, pre_get_info, cmd_add_mcast_local, NULL,
+    {"add-mcast-local", 3, 5, NULL, pre_get_info, cmd_add_mcast_local, NULL,
      "", RW},
     {"del-mcast-local", 3, 4, NULL, pre_get_info, cmd_del_mcast_local, NULL,
      "", RW},
@@ -2520,11 +2568,11 @@ static const struct ctl_command_syntax vtep_commands[] 
= {
      "", RO},
     {"list-local-macs", 1, 1, NULL, pre_get_info, cmd_list_local_macs, NULL,
      "", RO},
-    {"add-ucast-remote", 3, 4, NULL, pre_get_info, cmd_add_ucast_remote, NULL,
+    {"add-ucast-remote", 3, 5, NULL, pre_get_info, cmd_add_ucast_remote, NULL,
      "", RW},
     {"del-ucast-remote", 2, 2, NULL, pre_get_info, cmd_del_ucast_remote, NULL,
      "", RW},
-    {"add-mcast-remote", 3, 4, NULL, pre_get_info, cmd_add_mcast_remote, NULL,
+    {"add-mcast-remote", 3, 5, NULL, pre_get_info, cmd_add_mcast_remote, NULL,
      "", RW},
     {"del-mcast-remote", 3, 4, NULL, pre_get_info, cmd_del_mcast_remote, NULL,
      "", RW},
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to