From: itamarofek <[email protected]>

This patch adds support for handeling a per-tunnel tunnel key in the
ovs-vtep and vtep-ctl.

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

Requested-by: "Ofer Ben-Yacov" <[email protected]>
Signed-off-by: "Itamar Ofek" <[email protected]>
Co-authored-by: "Darrell Ball" <[email protected]>
---
 tests/vtep-ctl.at   | 217 ++++++++++++++++++++++++++++++++++++++++----
 vtep/ovs-vtep       | 122 ++++++++++++++++---------
 vtep/vtep-ctl.8.in  |  25 ++++--
 vtep/vtep-ctl.c     | 252 ++++++++++++++++++++++++++++++++++++----------------
 vtep/vtep.ovsschema |   9 +-
 vtep/vtep.xml       |  13 +++
 6 files changed, 488 insertions(+), 150 deletions(-)

diff --git a/tests/vtep-ctl.at b/tests/vtep-ctl.at
index 2b0df67..4290025 100644
--- a/tests/vtep-ctl.at
+++ b/tests/vtep-ctl.at
@@ -433,12 +433,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: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],
+   [add-ucast-local ls1 00:11:22:33:55:88 10.0.0.14 300 level0],
+   [add-ucast-local ls1 00:11:22:33:55:99 vxlan_over_ipv4 10.0.0.15 400 
level1])
 ], [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
+  00:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.14 300 level0
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.15 400 level1
 
 mcast-mac-local
 
@@ -460,11 +468,26 @@ 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],
+   [add-ucast-local ls1 00:11:22:33:55:99 10.0.0.18 500 level0],
+   [add-ucast-local ls1 00:11:22:33:55:99 10.0.0.19 600 level1],
+   [add-ucast-local ls1 00:11:22:33:56:11 10.0.0.20 700 level1],
+   [add-ucast-local ls1 00:11:22:33:56:11 10.0.0.21])
 ], [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
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.19 600 level1
+  00:11:22:33:56:11 -> vxlan_over_ipv4/10.0.0.21
 
 mcast-mac-local
 
@@ -480,22 +503,34 @@ 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],
+   [add-ucast-local ls1 00:11:22:33:55:88 10.0.0.14 300 level0],
+   [add-ucast-local ls1 00:11:22:33:55:99 vxlan_over_ipv4 10.0.0.15 400 
level1])
 ], [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
+  00:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.14 300 level0
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.15 400 level1
 
 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],
+   [del-ucast-local ls1 00:11:22:33:55:88],
+   [del-ucast-local ls1 00:11:22:33:55:99])
 ], [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 +546,20 @@ 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],
+   [add-ucast-remote ls1 00:11:22:33:55:88 10.0.0.14 300 level0],
+   [add-ucast-remote ls1 00:11:22:33:55:99 vxlan_over_ipv4 10.0.0.15 400 
level1])
 ], [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
+  00:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.14 300 level0
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.15 400 level1
 
 mcast-mac-remote
 
@@ -538,11 +581,20 @@ 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],
+   [add-ucast-remote ls1 00:11:22:33:55:99 10.0.0.18 500 level0],
+   [add-ucast-remote ls1 00:11:22:33:55:99 10.0.0.19 600 level1],
+   [add-ucast-remote ls1 00:11:22:33:56:11 10.0.0.20 700 level1],
+   [add-ucast-remote ls1 00:11:22:33:56:11 10.0.0.21])
 ], [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
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.19 600 level1
+  00:11:22:33:56:11 -> vxlan_over_ipv4/10.0.0.21
 
 mcast-mac-remote
 
@@ -558,22 +610,34 @@ 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],
+   [add-ucast-remote ls1 00:11:22:33:55:88 10.0.0.14 300 level0],
+   [add-ucast-remote ls1 00:11:22:33:55:99 vxlan_over_ipv4 10.0.0.15 400 
level1])
 ], [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
+  00:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.14 300 level0
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.15 400 level1
 
 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],
+   [del-ucast-remote ls1 00:11:22:33:55:88],
+   [del-ucast-remote ls1 00:11:22:33:55:99])
 ], [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 +654,25 @@ 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-local ls1 00:11:22:33:55:88 10.0.0.14 300 level0],
+   [add-ucast-local ls1 00:11:22:33:55:99 vxlan_over_ipv4 10.0.0.15 400 
level1],
    [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],
+   [add-ucast-remote ls1 02:11:22:33:55:88 10.0.0.14 300 level0],
+   [add-ucast-remote ls1 02:11:22:33:55:99 vxlan_over_ipv4 10.0.0.15 400 
level1])
 ], [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
+  00:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.14 300 level0
+  00:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.15 400 level1
 
 mcast-mac-local
 
@@ -605,6 +681,10 @@ 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
+  02:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.14 300 level0
+  02:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.15 400 level1
 
 mcast-mac-remote
 
@@ -621,7 +701,11 @@ 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],
+   [add-mcast-local ls1 01:11:22:33:55:88 10.0.0.15 300 level0],
+   [add-mcast-local ls1 01:11:22:33:55:99 vxlan_over_ipv4 10.0.0.16 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -630,6 +714,10 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.15 300 level0
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.16 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -651,7 +739,11 @@ 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],
+   [add-mcast-local ls1 01:11:22:33:55:88 10.0.0.16 300 level0],
+   [add-mcast-local ls1 01:11:22:33:55:99 vxlan_over_ipv4 10.0.0.17 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -661,10 +753,16 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.16 300 level0
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.17 400 level1
 
 ], [], [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],
+   [del-mcast-local ls1 01:11:22:33:55:88 10.0.0.16])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -673,6 +771,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.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
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.17 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
@@ -687,7 +787,12 @@ 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],
+   [add-mcast-remote ls1 01:11:22:33:55:88 10.0.0.16 300 level0],
+   [add-mcast-remote ls1 01:11:22:33:55:99 vxlan_over_ipv4 10.0.0.17 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
@@ -696,6 +801,11 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.16 300 level0
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.17 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
@@ -717,7 +827,12 @@ 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],
+   [add-mcast-remote ls1 01:11:22:33:55:88 10.0.0.17 300 level0],
+   [add-mcast-remote ls1 01:11:22:33:55:99 vxlan_over_ipv4 10.0.0.18 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
@@ -727,10 +842,17 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.17 300 level0
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.18 400 level1
 
 ], [], [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],
+   [del-mcast-remote ls1 01:11:22:33:55:88 10.0.0.17])         
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
@@ -739,6 +861,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.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
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.18 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
@@ -756,7 +881,15 @@ 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],
+   [add-mcast-local ls1 01:11:22:33:55:88 10.0.0.17 300 level0],
+   [add-mcast-remote ls1 01:11:22:33:55:99 vxlan_over_ipv4 10.0.0.18 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -765,15 +898,23 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.17 300 level0
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
    [ucast-mac-remote
 
 mcast-mac-remote
+  01:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.18 400 level1
   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
@@ -793,7 +934,15 @@ 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],
+   [add-mcast-local ls1 01:11:22:33:55:88 10.0.0.17 300 level0],
+   [add-mcast-remote ls1 03:11:22:33:55:99 vxlan_over_ipv4 10.0.0.18 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -803,6 +952,10 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.17 300 level0
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -813,6 +966,10 @@ 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
+  03:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.18 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
@@ -831,6 +988,10 @@ 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
+  03:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.18 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 VTEP_CTL_CLEANUP
@@ -850,7 +1011,15 @@ 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],
+   [add-mcast-local ls1 01:11:22:33:55:88 10.0.0.17 300 level0],
+   [add-mcast-remote ls1 03:11:22:33:55:99 vxlan_over_ipv4 10.0.0.18 400 
level1])
 ], [0], [], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-local-macs ls1])], [0],
    [ucast-mac-local
@@ -860,6 +1029,10 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.17 300 level0
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
@@ -870,6 +1043,10 @@ 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
+  03:11:22:33:55:99 -> vxlan_over_ipv4/10.0.0.18 400 level1
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL(
@@ -882,6 +1059,10 @@ 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
+  01:11:22:33:55:88 -> vxlan_over_ipv4/10.0.0.17 300 level0
 
 ], [], [VTEP_CTL_CLEANUP])
 AT_CHECK([RUN_VTEP_CTL([list-remote-macs ls1])], [0],
diff --git a/vtep/ovs-vtep b/vtep/ovs-vtep
index fd652d4..e73343b 100755
--- a/vtep/ovs-vtep
+++ b/vtep/ovs-vtep
@@ -33,6 +33,12 @@ import six
 
 
 VERSION = "0.99"
+MACS_MAC_INDEX = 1
+MACS_ENCAP_INDEX = 2
+MACS_DEST_IP_INDEX = 3
+MACS_KEY_INDEX = 4
+MACS_LEVEL_INDEX = 5
+MACS_NUM_OF_FIELDS = 7
 
 root_prefix = ""
 
@@ -124,30 +130,54 @@ 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):
+        level0_ports = []
+        level1_ports = []
+        for tunnel in tunnel_list:
+            if self.tunnels[tunnel][4] is 'level1':
+                level1_ports.append(self.tunnels[tunnel][0])
+            else:
+                level0_ports.append(self.tunnels[tunnel][0])
+        return level1_ports, level0_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())
+        level1_ports, level0_ports = self.vtep_ports(self.tunnels.keys())
+        level1_unknown, level0_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 level1 VTEP ports.
+        # If the level0 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 + level1_unknown
+        if len(level0_unknown) > 0:
             if self.replication_mode == "service_node":
-                break
+                phy_flood_ports += level0_unknown[0]
+            else:
+                phy_flood_ports += level0_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)))
 
-        ovs_ofctl("add-flow %s table=1,priority=0,action=%s"
-                  % (self.short_name, ",".join(flood_ports)))
+        # Traffic flowing from a level0 VTEP should not be flooded to level0
+        # unknown-dst ports
+        level0_flood_ports = phy_ports + level1_unknown
+        for port_no in level0_ports:
+            ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
+                      % (self.short_name, port_no,
+                         ",".join(level0_flood_ports)))
+
+        # Traffic flowing from a level1 VTEP should not be flooded to level1
+        # unknown-dst ports
+        level1_flood_ports = phy_ports + level0_unknown
+        for port_no in level1_ports:
+            ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
+                      % (self.short_name,
+                          port_no, ",".join(level1_flood_ports)))
 
     def add_lbinding(self, lbinding):
         vlog.info("adding %s binding to %s" % (lbinding, self.name))
@@ -168,14 +198,12 @@ class Logical_Switch(object):
         del self.ports[lbinding]
         self.update_flood()
 
-    def add_tunnel(self, tunnel, tunnel_key):
+    def add_tunnel(self, ip, tunnel_key, tunnel_level):
         global tun_id
-        vlog.info("adding tunnel %s" % tunnel)
-        encap, ip = tunnel.split("/")
 
-        if encap != "vxlan_over_ipv4":
-            vlog.warn("unsupported tunnel format %s" % encap)
-            return
+        vlog.info("adding tunnel: ip %s key %s %s" %
+                  (ip, tunnel_key,
+                   'level1' if tunnel_level is 'level1' else 'level0'))
 
         tun_id += 1
         tun_name = "vx" + str(tun_id)
@@ -189,14 +217,14 @@ class Logical_Switch(object):
             if port_no != "-1":
                 break
             elif i == 9:
-                vlog.warn("couldn't create tunnel %s" % tunnel)
+                vlog.warn("couldn't create tunnel %s" % ip)
                 ovs_vsctl("del-port %s %s" % (self.short_name, tun_name))
                 return
 
             # 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_key, tunnel_level)
 
         add_bfd(ip)
 
@@ -204,17 +232,18 @@ 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, tunnel_level) = 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"
@@ -235,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
 
@@ -249,7 +278,8 @@ class Logical_Switch(object):
     def update_remote_macs(self):
         remote_macs = {}
         unknown_dsts = set()
-        tunnels = set()
+        # A map of tunnel ip address to tunnel key and tunnel level
+        tunnels = {}
         parse_ucast = True
 
         column = vtep_ctl("--columns=tunnel_key find logical_switch "
@@ -268,28 +298,32 @@ 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*)\s?(\d+)?\s?(.*)?',
+                             line)
+            if len(entry) != MACS_NUM_OF_FIELDS:
                 continue
 
             if parse_ucast:
-                remote_macs[entry[1]] = entry[2]
+                remote_macs[entry[MACS_MAC_INDEX]] = entry[MACS_ENCAP_INDEX]
             else:
-                if entry[1] != "unknown-dst":
+                if entry[MACS_MAC_INDEX] != "unknown-dst":
                     continue
 
-                unknown_dsts.add(entry[2])
-
-            tunnels.add(entry[2])
+                unknown_dsts.add(entry[MACS_DEST_IP_INDEX])
 
-        old_tunnels = set(self.tunnels.keys())
-
-        for tunnel in tunnels.difference(old_tunnels):
-            self.add_tunnel(tunnel, tunnel_key)
+            tunnels[entry[MACS_DEST_IP_INDEX]] = (entry[MACS_KEY_INDEX],
+                                                  entry[MACS_LEVEL_INDEX])
+        old_tunnel_ips = set(self.tunnels.keys())
+        tunnel_ips = set(tunnels.keys())
+        for tunnel_ip in tunnel_ips.difference(old_tunnel_ips):
+            if tunnels[tunnel_ip][0]:
+                tunnel_scope_key = tunnels[tunnel_ip][0]
+            else:
+                tunnel_scope_key = tunnel_key
+            self.add_tunnel(tunnel_ip, tunnel_scope_key, tunnels[tunnel_ip][1])
 
-        for tunnel in old_tunnels.difference(tunnels):
-            self.del_tunnel(tunnel)
+        for tunnel_ip in old_tunnel_ips.difference(tunnel_ips):
+            self.del_tunnel(tunnel_ip)
 
         for mac in six.iterkeys(remote_macs):
             if (self.remote_macs.get(mac) != remote_macs[mac]):
diff --git a/vtep/vtep-ctl.8.in b/vtep/vtep-ctl.8.in
index 1901356..eca795c 100644
--- a/vtep/vtep-ctl.8.in
+++ b/vtep/vtep-ctl.8.in
@@ -263,12 +263,16 @@ Remove the local unicast Ethernet address \fImac\fR map 
from
 \fIlswitch\fR.  The local mappings are used by the VTEP to refer to MACs
 learned on its physical ports.
 .
-.IP "\fBadd\-mcast\-local \fIlswitch mac\fR [\fIencap\fR] \fIip\fR"
+.IP "\fBadd\-mcast\-local \fIlswitch mac\fR [\fIencap\fR] \fIip\fR [\fIkey\fR
+[\fIlevel\fR]]"
 Add physical location \fIip\fR using encapsulation \fIencap\fR to the
 local mac binding table for multicast Ethernet address \fImac\fR on
-\fIlswitch\fR.  If \fIencap\fR is not specified, the default is
-"vxlan_over_ipv4".  The local mappings are used by the VTEP to refer to
-MACs learned on its physical ports.
+\fIlswitch\fR with tunnel identifier equals to \fIkey\fR at BUM 
+unknown unicast and multicast distribution level [\fIlevel\fR. If \fIencap\fR
+is not specified, the default is "vxlan_over_ipv4". If \fIkey\fR is not
+specified the default is \fIlswitch\fR tunnel key. If [\fIlevel\fR is not
+specified the default is "level0". The local mappings are used by the VTEP
+to refer to MACs learned on its physical ports.
 .
 .IP "\fBdel\-mcast\-local \fIlswitch mac\fR [\fIencap\fR] \fIip\fR"
 Remove physical location \fIip\fR using encapsulation \fIencap\fR from
@@ -288,12 +292,15 @@ These commands examine and manipulate local and remote 
MAC bindings for
 the logical switch.  The remote maps are written by the network
 virtualization controller to refer to MACs that it has learned.
 .
-.IP "\fBadd\-ucast\-remote \fIlswitch mac\fR [\fIencap\fR] \fIip\fR"
+.IP "\fBadd\-ucast\-remote \fIlswitch mac\fR [\fIencap\fR] \fIip\fR [\fIkey\fR
+[\fIlevel\fR]]"
 Map the unicast Ethernet address \fImac\fR to the physical location
-\fIip\fR using encapsulation \fIencap\fR on \fIlswitch\fR.  If
-\fIencap\fR is not specified, the default is "vxlan_over_ipv4".  The
-remote mappings are used by the network virtualization platform to refer
-to MACs that it has learned.
+\fIip\fR using encapsulation \fIencap\fR on \fIlswitch\fR with tunnel
+identifier equals to \fIkey\fR at distribution level [\fIlevel\fR. 
+If \fIencap\fR is not specified, the default is "vxlan_over_ipv4". If \fIkey\fR
+is not specified the default is \fIlswitch\fR tunnel key. If [\fIlevel\fR is 
not
+specified the default is "level0". The remote mappings are used by the network
+virtualization platform to refer to MACs that it has learned.
 .
 .IP "\fBdel\-ucast\-remote \fIlswitch mac\fR"
 Remove the remote unicast Ethernet address \fImac\fR map from
diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
index e23c987..712a9d0 100644
--- a/vtep/vtep-ctl.c
+++ b/vtep/vtep-ctl.c
@@ -37,6 +37,7 @@
 #include "openvswitch/json.h"
 #include "ovsdb-data.h"
 #include "ovsdb-idl.h"
+#include "lib/packets.h"
 #include "poll-loop.h"
 #include "process.h"
 #include "stream.h"
@@ -344,18 +345,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 [LEVEL]]  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 [LEVEL]]  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 [LEVEL]] 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 [LEVEL]] 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\
@@ -450,6 +451,7 @@ struct vtep_ctl_context {
                              * struct vtep_ctl_lrouter. */
 };
 
+
 /* Casts 'base' into 'struct vtep_ctl_context'. */
 static struct vtep_ctl_context *
 vtep_ctl_context_cast(struct ctl_context *base)
@@ -886,7 +888,10 @@ 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_physical_locator_col_tunnel_level);
     ovsdb_idl_add_column(ctx->idl, &vteprec_tunnel_col_local);
     ovsdb_idl_add_column(ctx->idl, &vteprec_tunnel_col_remote);
 }
@@ -1647,34 +1652,88 @@ cmd_lr_exists(struct ctl_context *ctx)
     }
 }
 
+struct add_mac_args {
+    const char *mac;
+    const char *encap;
+    const char *dst_ip;
+    const char *tunnel_key;
+    const char *tunnel_level;
+};
+
+inline static void
+parse_add_mac_args(struct ctl_context *ctx, struct add_mac_args* args)
+{
+    /* This code is assumes a specific location for each "arg" argument,
+     * with a minumim argument list of 4 according to the following format.
+     * arg[0]: Command, arg[1]:LogicalSwitch, arg[2]: MAC 
+     * arg[3] optionally tunnel ENCAP or peer IP.
+     * When there are 5 arguments,If arg[3] is ENCAP  arg[4] must be IP,
+     * else arg[4] is tunnel key.
+     * When there are 6 arguments, if arg[4] is ip, arg[5] is the tunnel key,
+     * else it is the tunnel level.
+     * When there are 7 arguments, arg[6] is the tunnel level. */ 
+    if (ctx->argc < 4 ) {
+      ctl_fatal("invalid argument set only %d args supplied",ctx->argc);
+  
+    }
+    int index = 2;
+    args->mac = ctx->argv[index];
+    /* Check 3rd argument if its ip assume vxlan_over_ipv4
+     * else take the encapsulation from supplied argument */
+    ovs_be32 ip = 0;
+    if (!ip_parse(ctx->argv[++index], &ip)) {
+        args->encap = ctx->argv[index++];
+    } else {
+        args->encap = "vxlan_over_ipv4";
+    }
+    args->dst_ip = ctx->argv[index];
+    /* If no more arguments supplied parsing is done */
+    if (ctx->argc == ++index) {
+        return;
+    }
+    /* Check for optional tunnel_key */
+    args->tunnel_key = ctx->argv[index];
+    if (ctx->argc == ++index) {
+        return;
+    }
+    /* Tunnel level can be given only if tunnel key is provided */
+    args->tunnel_level = ctx->argv[index];
+    if (ctx->argc == ++index) {
+        return;
+    }
+    ctl_fatal("Unexpected number of argument %d", index);
+}
+
 static void
 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;
+    struct add_mac_args args = {0};
+   /* memset(&args,0,sizeof args);*/
+
     struct vteprec_physical_locator *ploc_cfg;
 
     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];
-    }
-
-    ploc_cfg = find_ploc(vtepctl_ctx, encap, dst_ip);
+    parse_add_mac_args(ctx,&args);
+    ploc_cfg = find_ploc(vtepctl_ctx, args.encap, args.dst_ip);
     if (!ploc_cfg) {
         ploc_cfg = vteprec_physical_locator_insert(ctx->txn);
-        vteprec_physical_locator_set_dst_ip(ploc_cfg, dst_ip);
-        vteprec_physical_locator_set_encapsulation_type(ploc_cfg, encap);
+        if (args.tunnel_key) {
+            int64_t tunnel_scope_key = 0;
+            ovs_scan(args.tunnel_key,"%ld",&tunnel_scope_key);
+            vteprec_physical_locator_set_tunnel_key(ploc_cfg,
+                                                    &tunnel_scope_key,1);
+            if (args.tunnel_level) {
+                vteprec_physical_locator_set_tunnel_level(ploc_cfg,
+                                                          args.tunnel_level);
+            }
+
+        }
+        vteprec_physical_locator_set_dst_ip(ploc_cfg,args.dst_ip);
+        vteprec_physical_locator_set_encapsulation_type(ploc_cfg, args.encap);
 
         add_ploc_to_cache(vtepctl_ctx, ploc_cfg);
     }
@@ -1682,23 +1741,23 @@ add_ucast_entry(struct ctl_context *ctx, bool local)
     if (local) {
         struct vteprec_ucast_macs_local *ucast_cfg;
 
-        ucast_cfg = shash_find_data(&ls->ucast_local, mac);
+        ucast_cfg = shash_find_data(&ls->ucast_local, args.mac);
         if (!ucast_cfg) {
             ucast_cfg = vteprec_ucast_macs_local_insert(ctx->txn);
-            vteprec_ucast_macs_local_set_MAC(ucast_cfg, mac);
+            vteprec_ucast_macs_local_set_MAC(ucast_cfg, args.mac);
             vteprec_ucast_macs_local_set_logical_switch(ucast_cfg, ls->ls_cfg);
-            shash_add(&ls->ucast_local, mac, ucast_cfg);
+            shash_add(&ls->ucast_local, args.mac, ucast_cfg);
         }
         vteprec_ucast_macs_local_set_locator(ucast_cfg, ploc_cfg);
     } else {
         struct vteprec_ucast_macs_remote *ucast_cfg;
 
-        ucast_cfg = shash_find_data(&ls->ucast_remote, mac);
+        ucast_cfg = shash_find_data(&ls->ucast_remote, args.mac);
         if (!ucast_cfg) {
             ucast_cfg = vteprec_ucast_macs_remote_insert(ctx->txn);
-            vteprec_ucast_macs_remote_set_MAC(ucast_cfg, mac);
+            vteprec_ucast_macs_remote_set_MAC(ucast_cfg, args.mac);
             vteprec_ucast_macs_remote_set_logical_switch(ucast_cfg, 
ls->ls_cfg);
-            shash_add(&ls->ucast_remote, mac, ucast_cfg);
+            shash_add(&ls->ucast_remote, args.mac, ucast_cfg);
         }
         vteprec_ucast_macs_remote_set_locator(ucast_cfg, ploc_cfg);
     }
@@ -1788,8 +1847,11 @@ 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)
+                struct vtep_ctl_lswitch *ls, 
+                /*
+                const char *mac,
+                const char *encap, const char *dst_ip, const char* tunnel_key,
+                const char* tunnel_scope,*/ bool local)
 {
     struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
     struct shash *mcast_shash;
@@ -1801,15 +1863,17 @@ add_mcast_entry(struct ctl_context *ctx,
 
     /* Physical locator sets are immutable, so allocate a new one. */
     ploc_set_cfg = vteprec_physical_locator_set_insert(ctx->txn);
-
-    mcast_mac = shash_find_data(mcast_shash, mac);
+    struct add_mac_args args = {0};
+    /* memset(&args,0,sizeof args); */
+    parse_add_mac_args(ctx,&args);
+    mcast_mac = shash_find_data(mcast_shash, args.mac);
     if (!mcast_mac) {
-        mcast_mac = add_mcast_mac_to_cache(vtepctl_ctx, ls, mac, ploc_set_cfg,
-                                           local);
+        mcast_mac = add_mcast_mac_to_cache(vtepctl_ctx, ls, args.mac,
+                                           ploc_set_cfg, local);
 
         if (local) {
             mcast_mac->local_cfg = vteprec_mcast_macs_local_insert(ctx->txn);
-            vteprec_mcast_macs_local_set_MAC(mcast_mac->local_cfg, mac);
+            vteprec_mcast_macs_local_set_MAC(mcast_mac->local_cfg, args.mac);
             vteprec_mcast_macs_local_set_locator_set(mcast_mac->local_cfg,
                                                      ploc_set_cfg);
             vteprec_mcast_macs_local_set_logical_switch(mcast_mac->local_cfg,
@@ -1817,7 +1881,7 @@ add_mcast_entry(struct ctl_context *ctx,
             mcast_mac->remote_cfg = NULL;
         } else {
             mcast_mac->remote_cfg = vteprec_mcast_macs_remote_insert(ctx->txn);
-            vteprec_mcast_macs_remote_set_MAC(mcast_mac->remote_cfg, mac);
+            vteprec_mcast_macs_remote_set_MAC(mcast_mac->remote_cfg,args.mac);
             vteprec_mcast_macs_remote_set_locator_set(mcast_mac->remote_cfg,
                                                       ploc_set_cfg);
             vteprec_mcast_macs_remote_set_logical_switch(mcast_mac->remote_cfg,
@@ -1835,11 +1899,21 @@ add_mcast_entry(struct ctl_context *ctx,
         }
     }
 
-    ploc_cfg = find_ploc(vtepctl_ctx, encap, dst_ip);
+    ploc_cfg = find_ploc(vtepctl_ctx, args.encap, args.dst_ip);
     if (!ploc_cfg) {
         ploc_cfg = vteprec_physical_locator_insert(ctx->txn);
-        vteprec_physical_locator_set_dst_ip(ploc_cfg, dst_ip);
-        vteprec_physical_locator_set_encapsulation_type(ploc_cfg, encap);
+        if (args.tunnel_key) {
+            int64_t tunnel_scope_key = 0;
+            ovs_scan(args.tunnel_key,"%ld",&tunnel_scope_key);
+            vteprec_physical_locator_set_tunnel_key(ploc_cfg,
+                                                    &tunnel_scope_key,1);
+            if (args.tunnel_level){
+                vteprec_physical_locator_set_tunnel_level(ploc_cfg,
+                                                          args.tunnel_level);
+            }
+        }
+        vteprec_physical_locator_set_dst_ip(ploc_cfg, args.dst_ip);
+        vteprec_physical_locator_set_encapsulation_type(ploc_cfg, args.encap);
 
         add_ploc_to_cache(vtepctl_ctx, ploc_cfg);
     }
@@ -1850,23 +1924,29 @@ add_mcast_entry(struct ctl_context *ctx,
 
 static void
 del_mcast_entry(struct ctl_context *ctx,
-                struct vtep_ctl_lswitch *ls, const char *mac,
-                const char *encap, const char *dst_ip, bool local)
+                struct vtep_ctl_lswitch *ls,
+                /*
+                const char *mac,
+                const char *encap, const char *dst_ip,
+                */
+                bool local)
 {
     struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
     struct vtep_ctl_mcast_mac *mcast_mac;
     struct shash *mcast_shash;
     struct vteprec_physical_locator *ploc_cfg;
     struct vteprec_physical_locator_set *ploc_set_cfg;
+    struct add_mac_args args = {0};
 
     mcast_shash = local ? &ls->mcast_local : &ls->mcast_remote;
-
-    mcast_mac = shash_find_data(mcast_shash, mac);
+    
+    parse_add_mac_args(ctx,&args);
+    mcast_mac = shash_find_data(mcast_shash, args.mac);
     if (!mcast_mac) {
         return;
     }
 
-    ploc_cfg = find_ploc(vtepctl_ctx, encap, dst_ip);
+    ploc_cfg = find_ploc(vtepctl_ctx, args.encap, args.dst_ip);
     if (!ploc_cfg) {
         /* Couldn't find the physical locator, so just ignore. */
         return;
@@ -1878,7 +1958,7 @@ del_mcast_entry(struct ctl_context *ctx,
 
     del_ploc_from_mcast_mac(mcast_mac, ploc_cfg);
     if (ovs_list_is_empty(&mcast_mac->locators)) {
-        struct shash_node *node = shash_find(mcast_shash, mac);
+        struct shash_node *node = shash_find(mcast_shash, args.mac);
 
         vteprec_physical_locator_set_delete(ploc_set_cfg);
 
@@ -1907,27 +1987,19 @@ 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;
+    /*
+    struct add_mac_args args;
+    memset(&args,0,sizeof(args));
+    */
 
     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];
-    }
-
+    /*parse_add_mac_args(ctx,&args);*/
     if (add) {
-        add_mcast_entry(ctx, ls, mac, encap, dst_ip, local);
+        add_mcast_entry(ctx, ls/*, args.mac, args.encap, args.dst_ip, 
args.tunnel_key,args.tunnel_level*/, local);
     } else {
-        del_mcast_entry(ctx, ls, mac, encap, dst_ip, local);
+        del_mcast_entry(ctx, ls/*, args.mac, args.encap, args.dst_ip*/, local);
     }
 
     vtep_ctl_context_invalidate_cache(ctx);
@@ -2016,7 +2088,8 @@ list_macs(struct ctl_context *ctx, bool local)
     struct svec ucast_macs;
     struct shash *mcast_shash;
     struct svec mcast_macs;
-
+    char tunnel_key[10];
+    char tunnel_level[10];
     vtep_ctl_context_populate_cache(ctx);
     ls = find_lswitch(vtepctl_ctx, ctx->argv[1], true);
 
@@ -2031,9 +2104,21 @@ 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], 10, " %d",
+                     (uint32_t)(*ploc_cfg->tunnel_key));
+        }
+        if (ploc_cfg->tunnel_level) {
+            snprintf(tunnel_level, 10, " %s", ploc_cfg->tunnel_level);
+        } else {
+            tunnel_level[0] = '\0';
+        }
+        entry = xasprintf("  %s -> %s/%s%s%s", node->name,
+                          ploc_cfg->encapsulation_type,
+                          ploc_cfg->dst_ip,
+                          tunnel_key,
+                          tunnel_level);
         svec_add_nocopy(&ucast_macs, entry);
     }
     ds_put_format(&ctx->output, "ucast-mac-%s\n", local ? "local" : "remote");
@@ -2048,9 +2133,22 @@ 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, 10, " %d",
+                         (uint32_t)(*ploc->ploc_cfg->tunnel_key));
+            }
+            if (ploc->ploc_cfg->tunnel_level) {
+                snprintf(tunnel_level, 10, " %s",
+                         ploc->ploc_cfg->tunnel_level);
+            } else {
+                tunnel_level[0] = '\0';
+            }
+            entry = xasprintf("  %s -> %s/%s%s%s", node->name,
                               ploc->ploc_cfg->encapsulation_type,
-                              ploc->ploc_cfg->dst_ip);
+                              ploc->ploc_cfg->dst_ip,
+                              tunnel_key,
+                              tunnel_level);
             svec_add_nocopy(&mcast_macs, entry);
         }
     }
@@ -2457,11 +2555,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, 6, 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, 6, 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},
@@ -2469,11 +2567,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, 6, 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, 6, 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},
diff --git a/vtep/vtep.ovsschema b/vtep/vtep.ovsschema
index 3a24318..35c3fd2 100644
--- a/vtep/vtep.ovsschema
+++ b/vtep/vtep.ovsschema
@@ -1,6 +1,6 @@
 {
   "name": "hardware_vtep",
-  "cksum": "353943336 11434",
+  "cksum": "2728111540 11603",
   "tables": {
     "Global": {
       "columns": {
@@ -209,7 +209,12 @@
               "type": "string"}},
           "mutable": false},
         "dst_ip": {"type": "string", "mutable": false},
-        "tunnel_key": {"type": {"key": "integer", "min": 0, "max": 1}}},
+        "tunnel_key": {"type": {"key": "integer", "min": 0, "max": 1}},
+        "tunnel_level": {
+          "type": {
+           "key": {
+            "enum": ["set", ["level0", "level1"]],
+            "type": "string"},"min": 0, "max": 1}}},
       "indexes": [["encapsulation_type", "dst_ip", "tunnel_key"]]},
     "ACL_entry": {
       "columns": {
diff --git a/vtep/vtep.xml b/vtep/vtep.xml
index 62075ca..b450838 100644
--- a/vtep/vtep.xml
+++ b/vtep/vtep.xml
@@ -1174,6 +1174,19 @@
       </p>
     </column>
 
+    <column name="tunnel_level">
+      <p>
+        For <code>vxlan_over_ipv4</code> encapsulation, represents the
+        hierarchy level of the <ref table="Physical_Locator"/>.
+        Broadcast, unknown unicast and multicast (BUM) traffic received
+        at one level is never sent to another <ref table="Physical_Locator"/>
+       of the same level.  The only valid values supported are <code>level0
+       </code> and <code> level1 </code>;
+       this column is optional and the default value if not
+        configured is level0.
+      </p>
+    </column>
+
   </table>
   <table name="ACL_entry">
     <p>
-- 
1.9.1

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to