diff mbox

[ovs-dev] ovs-vtep: vtep-ctl and ovs-vtep support of adding explicit tunnel key

Message ID 1477581155-17986-1-git-send-email-itamar.ofek@huawei.com
State Changes Requested
Delegated to: Justin Pettit
Headers show

Commit Message

Itamar Ofek Oct. 27, 2016, 3:12 p.m. UTC
From: itamarofek <itamar.ofeq@gmail.com>

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" <ofer.benyacov@gmail.com>
Signed-off-by: "Itamar Ofek" <itamar.ofeq@gmail.com>
Co-authored-by: "Darrell Ball" <dlu998@gmail.com>
---
 tests/vtep-ctl.at   | 217 +++++++++++++++++++++++++++++++++++++++++++++++-----
 vtep/ovs-vtep       | 122 ++++++++++++++++++-----------
 vtep/vtep-ctl.c     | 203 +++++++++++++++++++++++++++++++++---------------
 vtep/vtep.ovsschema |   9 ++-
 vtep/vtep.xml       |  12 +++
 5 files changed, 438 insertions(+), 125 deletions(-)

Comments

Justin Pettit Dec. 1, 2016, 2:10 a.m. UTC | #1
> On Oct 27, 2016, at 8:12 AM, itamaro <itamar.ofeq@gmail.com> wrote:
> 
> From: itamarofek <itamar.ofeq@gmail.com>

Sorry for the delay.  I had a bunch of suggested changes in my drafts folder and apparently never hit send.

The previous patches had version numbers.  I assume this is v5.  Can you please add v6 to the next version? It's also helpful to provide a history of change highlights.

The title mentions adding an explicit tunnel key, but the bigger change seem to me is the introduction of levels.  Adding levels probably merits its own commit, but I won't hold you to that.  However, at a minimum, I do think the section describing the commit should explain better what the levels are.

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

s/handeling/handling/

> 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" <ofer.benyacov@gmail.com>
> Signed-off-by: "Itamar Ofek" <itamar.ofeq@gmail.com>
> Co-authored-by: "Darrell Ball" <dlu998@gmail.com>
> ---
> tests/vtep-ctl.at   | 217 +++++++++++++++++++++++++++++++++++++++++++++++-----
> vtep/ovs-vtep       | 122 ++++++++++++++++++-----------
> vtep/vtep-ctl.c     | 203 +++++++++++++++++++++++++++++++++---------------
> vtep/vtep.ovsschema |   9 ++-
> vtep/vtep.xml       |  12 +++
> 5 files changed, 438 insertions(+), 125 deletions(-)


> diff --git a/vtep/vtep-ctl.c b/vtep/vtep-ctl.c
> index 3450deb..6a0a62e 100644
> --- a/vtep/vtep-ctl.c
> +++ b/vtep/vtep-ctl.c
> 
> @@ -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\

The man page should be updated with these changes.

> @@ -450,6 +451,14 @@ struct vtep_ctl_context {
>                              * struct vtep_ctl_lrouter. */
> };
> 
> +struct add_mac_args {
> +    const char *mac;
> +    const char *encap;
> +    const char *dst_ip;
> +    const char *tunnel_key;
> +    const char *tunnel_level;
> +};

I'd put this definition right above parse_add_mac_args(), since the definition isn't need for more than a thousand lines.

> @@ -1647,34 +1659,75 @@ cmd_lr_exists(struct ctl_context *ctx)
>     }
> }
> 
> +inline void
> +static parse_add_mac_args(struct ctl_context *ctx, struct add_mac_args* args)

This code is assuming a specific location for each "arg" argument, so I'd add a comment describing what that is, including which ones are optional.

> +{
> +    ovs_be32 ip = 0;
> +    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
> +     */
> +    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 prsing is done
> +     */

s/prsing/parsing/

As mentioned in CodingStyle.md, please write full sentences that start with a capital letter and end with a period.  My personal preference is to not have the end of the comment on a new line, but I think it looks especially odd with a one line comment.

> 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;
> +    memset(&args, 0, sizeof(args));

As described CodingStyle.md, "sizeof" shouldn't use parentheses.

> +    int64_t tunnel_scope_key = 0;

It looks like this variable is only needed if "arg.tunnel_key" exists.  I'd move it into that block.

> +
>     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) {
> +            ovs_scan(args.tunnel_key, "%"SCNd64, &tunnel_scope_key);

How about using str_to_llong() instead of ovs_scan()?

> +            vteprec_physical_locator_set_tunnel_key(ploc_cfg,
> +                                                    &tunnel_scope_key, 1);
> +            if (args.tunnel_level){

Put a space between the parenthesis and curly bracket.

> @@ -1789,7 +1842,8 @@ 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,
> +                const char* tunnel_scope, bool local)

Can you make add_mcast_entry() look more like add_ucast_entry()?  For example, call parse_add_mac_args() inside add_mcast_entry() and del_mcast_entry().  It would reduce the number of arguments to those functions and make the code a bit cleaner and more consistent.

> @@ -1838,6 +1892,16 @@ 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_scope_key = 0;
> +            ovs_scan(tunnel_key, "%"SCNd64, &tunnel_scope_key);

Same questions about using str_to_llong() instead of ovs_scan().

> @@ -1907,27 +1971,18 @@ add_del_mcast_entry(struct ctl_context *ctx, bool add, bool local)
> {
> ...
> +    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);

This line is way over 79 characters.

> --- a/vtep/vtep.xml
> +++ b/vtep/vtep.xml
> @@ -1174,6 +1174,18 @@
>       </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 level0 and
> +        level1; this column is optional and the default value if not
> +        configured is level0.

Put <code> blocks around "level0" and "level1".

I still need to review "ovs-vtep", but I wanted to at least get you some feedback, and I know we're waiting on feedback from some of the original authors of the schema on their opinion on this approach.

--Justin
diff mbox

Patch

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 b32a82a..dfb94e6 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 = ""
 
@@ -120,30 +126,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))
@@ -164,14 +194,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)
@@ -185,14 +213,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)
 
@@ -200,17 +228,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"
@@ -231,8 +260,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 +274,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 "
@@ -264,28 +294,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.c b/vtep/vtep-ctl.c
index 3450deb..6a0a62e 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,14 @@  struct vtep_ctl_context {
                              * struct vtep_ctl_lrouter. */
 };
 
+struct add_mac_args {
+    const char *mac;
+    const char *encap;
+    const char *dst_ip;
+    const char *tunnel_key;
+    const char *tunnel_level;
+};
+
 /* Casts 'base' into 'struct vtep_ctl_context'. */
 static struct vtep_ctl_context *
 vtep_ctl_context_cast(struct ctl_context *base)
@@ -886,7 +895,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 +1659,75 @@  cmd_lr_exists(struct ctl_context *ctx)
     }
 }
 
+inline void
+static parse_add_mac_args(struct ctl_context *ctx, struct add_mac_args* args)
+{
+    ovs_be32 ip = 0;
+    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
+     */
+    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 prsing 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;
+    memset(&args, 0, sizeof(args));
+    int64_t tunnel_scope_key = 0;
+
     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) {
+            ovs_scan(args.tunnel_key, "%"SCNd64, &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 +1735,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);
     }
@@ -1789,7 +1842,8 @@  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,
+                const char* tunnel_scope, bool local)
 {
     struct vtep_ctl_context *vtepctl_ctx = vtep_ctl_context_cast(ctx);
     struct shash *mcast_shash;
@@ -1838,6 +1892,16 @@  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_scope_key = 0;
+            ovs_scan(tunnel_key, "%"SCNd64, &tunnel_scope_key);
+            vteprec_physical_locator_set_tunnel_key(ploc_cfg,
+                                                    &tunnel_scope_key, 1);
+            if (tunnel_scope){
+                vteprec_physical_locator_set_tunnel_level(ploc_cfg,
+                                                          tunnel_scope);
+            }
+        }
         vteprec_physical_locator_set_dst_ip(ploc_cfg, dst_ip);
         vteprec_physical_locator_set_encapsulation_type(ploc_cfg, encap);
 
@@ -1907,27 +1971,18 @@  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 +2071,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 +2087,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 +2116,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);
         }
     }
@@ -2507,11 +2588,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},
@@ -2519,11 +2600,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..0d255e7 100644
--- a/vtep/vtep.xml
+++ b/vtep/vtep.xml
@@ -1174,6 +1174,18 @@ 
       </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 level0 and
+        level1; this column is optional and the default value if not
+        configured is level0.
+      </p>
+    </column>
+
   </table>
   <table name="ACL_entry">
     <p>