Convert lisp-gpe encap to interface tx node 48/848/2
authorFlorin Coras <[email protected]>
Wed, 20 Apr 2016 22:45:40 +0000 (00:45 +0200)
committerDave Barach <[email protected]>
Mon, 25 Apr 2016 13:05:49 +0000 (13:05 +0000)
With this change, one lisp-gpe interface is created per vrf/overlay
tenant and its tx node is used as encapsulator (or tunnel ingress). For
all intents and purposes, the tx node inherits all functions previously
performed by the lisp-gpe-encap node and it maintains said node's
position in lisp-gpe's data-path graph. Chiefly, this opens the
possibility to chain interface features, like IPSec, transparently with
LISP. Furthermore, it brings basic data plane support for vrfs and LISP
instance-ids (or virtual network instances as per RFC7364).

Other changes include improvements to lisp-gpe enable and disable
sequences and corresponding API/VAT fixes.

Change-Id: I085500450660a976b587b1a720e282f6e728d580
Signed-off-by: Florin Coras <[email protected]>
12 files changed:
vnet/Makefile.am
vnet/vnet/lisp-cp/control.c
vnet/vnet/lisp-cp/control.h
vnet/vnet/lisp-gpe/decap.c
vnet/vnet/lisp-gpe/encap.c [deleted file]
vnet/vnet/lisp-gpe/interface.c [new file with mode: 0644]
vnet/vnet/lisp-gpe/lisp_gpe.c
vnet/vnet/lisp-gpe/lisp_gpe.h
vnet/vnet/lisp-gpe/lisp_gpe_error.def
vpp-api-test/vat/api_format.c
vpp/api/api.c
vpp/api/vpe.api

index 2ce40f3..f7c1f30 100644 (file)
@@ -477,7 +477,7 @@ endif
 
 libvnet_la_SOURCES +=                          \
  vnet/lisp-gpe/lisp_gpe.c                      \
- vnet/lisp-gpe/encap.c                         \
+ vnet/lisp-gpe/interface.c                     \
  vnet/lisp-gpe/decap.c                         
 
 nobase_include_HEADERS +=                      \
index 3448fb3..f067cf6 100644 (file)
@@ -18,7 +18,8 @@
 #include <vnet/lisp-cp/lisp_msg_serdes.h>
 #include <vnet/lisp-gpe/lisp_gpe.h>
 
-/* Adds mapping to map-cache but does NOT program LISP forwarding */
+/* Stores mapping in map-cache. It does NOT program data plane forwarding for
+ * remote/learned mappings. */
 int
 vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
                            u32 * map_index_result)
@@ -32,11 +33,12 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
   if (a->is_add)
     {
       /* TODO check if overwriting and take appropriate actions */
-      if (mi != GID_LOOKUP_MISS) {
+      if (mi != GID_LOOKUP_MISS)
+        {
           clib_warning("eid %U found in the eid-table", format_ip_address,
                        &a->deid);
           return VNET_API_ERROR_VALUE_EXIST;
-      }
+        }
 
       pool_get(lcm->mapping_pool, m);
       m->eid = a->deid;
@@ -65,18 +67,17 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
         {
           /* mark as local */
           vec_add1(lcm->local_mappings_indexes, map_index);
-
-          /* XXX do something else? */
         }
       map_index_result[0] = map_index;
     }
   else
     {
-      if (mi == GID_LOOKUP_MISS) {
+      if (mi == GID_LOOKUP_MISS)
+        {
           clib_warning("eid %U not found in the eid-table", format_ip_address,
                        &a->deid);
           return VNET_API_ERROR_INVALID_VALUE;
-      }
+        }
 
       /* clear locator-set to eids binding */
       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
@@ -115,6 +116,66 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
   return 0;
 }
 
+/* Stores mapping in map-cache and programs data plane for local mappings. */
+int
+vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
+                                 u32 * map_index_result)
+{
+  uword * table_id, * refc;
+  u32 rv;
+  vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+
+  /* store/remove mapping from map-cache */
+  rv = vnet_lisp_add_del_mapping (a, map_index_result);
+  if (rv)
+    return rv;
+
+  table_id = hash_get(lcm->table_id_by_vni, /* default for now */ 0);
+
+  if (!table_id)
+    {
+      clib_warning ("vni %d not associated to a vrf!", 0);
+      return VNET_API_ERROR_INVALID_VALUE;
+    }
+
+  refc = hash_get(lcm->dp_if_refcount_by_vni, 0);
+
+  /* enable/disable data-plane interface */
+  if (a->is_add)
+    {
+      /* create interface or update refcount */
+      if (!refc)
+        {
+          ai->is_add = 1;
+          ai->vni = 0; /* default for now, pass vni as parameter */
+          ai->table_id = table_id[0];
+          vnet_lisp_gpe_add_del_iface (ai, 0);
+        }
+      else
+        {
+          refc[0]++;
+        }
+    }
+  else
+    {
+      /* since this is a remove for an existing eid, the iface should exist */
+      ASSERT(refc != 0);
+      refc[0]--;
+
+      /* remove iface if needed */
+      if (refc[0] == 0)
+        {
+          ai->is_add = 0;
+          ai->vni = 0; /* default for now, pass vni as parameter */
+          ai->table_id = table_id[0];
+          vnet_lisp_gpe_add_del_iface (ai, 0);
+        }
+    }
+
+  return rv;
+}
+
 static clib_error_t *
 lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
                                    vlib_cli_command_t * cmd)
@@ -171,7 +232,7 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
   a->locator_set_index = locator_set_index;
   a->local = 1;
 
-  vnet_lisp_add_del_mapping (a, &map_index);
+  vnet_lisp_add_del_local_mapping (a, &map_index);
  done:
   vec_free(eids);
   return error;
@@ -650,7 +711,8 @@ lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
 
 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
     .path = "lisp locator-set",
-    .short_help = "lisp locator-set add/del <name> <iface-name> <priority> <weight>",
+    .short_help = "lisp locator-set add/del <name> iface <iface-name> "
+        "<priority> <weight>",
     .function = lisp_add_del_locator_set_command_fn,
 };
 
@@ -1251,7 +1313,7 @@ del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
   a->is_add = 0;
   a->dlocator = fe->dst_loc;
   a->slocator = fe->src_loc;
-  a->iid = 0; // XXX should be part of mapping/eid
+  a->vni = 0; // XXX should be part of mapping/eid
   gid_address_copy(&a->deid, &fe->deid);
 
   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
@@ -1268,8 +1330,9 @@ add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
   locator_set_t * dst_ls, * src_ls;
   u32 i, minp = ~0;
   locator_t * dl = 0;
-  uword * feip = 0;
+  uword * feip = 0, * tidp;
   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
+
   memset (a, 0, sizeof(*a));
 
   /* remove entry if it already exists */
@@ -1334,10 +1397,20 @@ add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
     }
 
   gid_address_copy (&a->deid, &dst_map->eid);
-  a->iid = 0; // XXX should be part of mapping/eid
+  a->vni = 0; // XXX should be part of mapping/eid
+
+  tidp = hash_get(lcm->table_id_by_vni, a->vni);
+  if (!tidp)
+    {
+      clib_warning("vni %d not associated to a vrf!", a->vni);
+      return;
+    }
+  a->table_id = tidp[0];
+
   u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
   a->decap_next_index = (ipver == IP4) ?
           LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
+
   /* XXX tunnels work only with IP4 now */
   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
 
@@ -1611,6 +1684,9 @@ lisp_cp_init (vlib_main_t *vm)
   gid_dictionary_init (&lcm->mapping_index_by_gid);
   gid_dictionary_init (&lcm->mapping_index_by_gid);
 
+  /* default vrf mapped to vni 0 */
+  hash_set(lcm->table_id_by_vni, 0, 0);
+
   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
                          lisp_cp_input_node.index, 1 /* is_ip4 */);
   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
index 53d90fc..f87a6d5 100644 (file)
@@ -91,6 +91,12 @@ typedef struct
   /* vector of map-resolver addresses */
   ip_address_t * map_resolvers;
 
+  /* Lookup vrf by vni */
+  uword * table_id_by_vni;
+
+  /* Number of src prefixes in a vni that use an interface */
+  uword * dp_if_refcount_by_vni;
+
   /* commodity */
   ip4_main_t * im4;
   ip6_main_t * im6;
@@ -122,7 +128,6 @@ typedef struct
 int
 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
                               u32 * ls_index);
-
 int
 vnet_lisp_add_del_locator_set_name (vnet_lisp_add_del_locator_set_args_t * a,
                                     u32 * ls_index);
@@ -146,6 +151,9 @@ typedef struct
 int
 vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t *a,
                           u32 * map_index);
+int
+vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
+                                 u32 * map_index_result);
 
 typedef struct
 {
index 356dbf2..5d88462 100644 (file)
@@ -52,7 +52,6 @@ next_proto_to_next_index[LISP_GPE_NEXT_PROTOS] ={
     LISP_GPE_INPUT_NEXT_DROP,
     LISP_GPE_INPUT_NEXT_IP4_INPUT,
     LISP_GPE_INPUT_NEXT_IP6_INPUT,
-    LISP_GPE_INPUT_NEXT_DROP,
     LISP_GPE_INPUT_NEXT_DROP
 };
 
@@ -85,6 +84,7 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
   u32 n_left_from, next_index, * from, * to_next;
   lisp_gpe_tunnel_key_t last_key;
   u32 pkts_decapsulated = 0;
+  lisp_gpe_main_t * lgm = &lisp_gpe_main;
 
   memset (&last_key, 0xff, sizeof (last_key));
 
@@ -104,8 +104,8 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
           u32 bi0, bi1;
           vlib_buffer_t * b0, * b1;
           ip4_udp_lisp_gpe_header_t * iul0, * iul1;
-          u32 error0, error1;
-          u32 next0, next1;
+          u32 next0, next1, error0, error1;
+          uword * si0, * si1;
 
           next0 = next1 = LISP_GPE_INPUT_NEXT_IP4_INPUT;
 
@@ -156,14 +156,35 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
           vnet_update_l2_len (b0);
           vnet_update_l2_len (b1);
 
-          /* TODO hash to map iid to fib */
-          vnet_buffer(b0)->sw_if_index[VLIB_TX] = iul0->lisp.iid;
-          vnet_buffer(b1)->sw_if_index[VLIB_TX] = iul1->lisp.iid;
+          /* map iid/vni to lisp-gpe sw_if_index which is used by ipx_input to
+           * decide the rx vrf and the input features to be applied */
+          si0 = hash_get(lgm->tunnel_term_sw_if_index_by_vni, iul0->lisp.iid);
+          si1 = hash_get(lgm->tunnel_term_sw_if_index_by_vni, iul1->lisp.iid);
 
-          pkts_decapsulated += 2;
+          if (si0)
+            {
+              vnet_buffer(b0)->sw_if_index[VLIB_RX] = si0[0];
+              pkts_decapsulated++;
+              error0 = 0;
+            }
+          else
+            {
+              next0 = LISP_GPE_INPUT_NEXT_DROP;
+              error0 = LISP_GPE_ERROR_NO_SUCH_TUNNEL;
+            }
+
+          if (si1)
+            {
+              vnet_buffer(b1)->sw_if_index[VLIB_RX] = si1[0];
+              pkts_decapsulated++;
+              error0 = 0;
+            }
+          else
+            {
+              next1 = LISP_GPE_INPUT_NEXT_DROP;
+              error1 = LISP_GPE_ERROR_NO_SUCH_TUNNEL;
+            }
 
-          /* TODO error handling if security is implemented */
-          error0 = error1 = 0;
           b0->error = error0 ? node->errors[error0] : 0;
           b1->error = error1 ? node->errors[error1] : 0;
 
@@ -197,6 +218,7 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
           u32 next0;
           ip4_udp_lisp_gpe_header_t * iul0;
           u32 error0;
+          uword * si0;
 
           bi0 = from[0];
           to_next[0] = bi0;
@@ -228,18 +250,29 @@ lisp_gpe_input (vlib_main_t * vm, vlib_node_runtime_t * node,
           /* Required to make the l2 tag push / pop code work on l2 subifs */
           vnet_update_l2_len (b0);
 
-          /* TODO hash to map iid to fib */
-          vnet_buffer(b0)->sw_if_index[VLIB_TX] = iul0->lisp.iid;
-          pkts_decapsulated ++;
+          /* map iid/vni to lisp-gpe sw_if_index which is used by ipx_input to
+           * decide the rx vrf and the input features to be applied */
+          si0 = hash_get(lgm->tunnel_term_sw_if_index_by_vni, iul0->lisp.iid);
+
+          if (si0)
+            {
+              vnet_buffer(b0)->sw_if_index[VLIB_RX] = si0[0];
+              pkts_decapsulated++;
+              error0 = 0;
+            }
+          else
+            {
+              next0 = LISP_GPE_INPUT_NEXT_DROP;
+              error0 = LISP_GPE_ERROR_NO_SUCH_TUNNEL;
+            }
 
           /* TODO error handling if security is implemented */
-          error0 = 0;
           b0->error = error0 ? node->errors[error0] : 0;
 
-          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
+          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
             {
-              lisp_gpe_rx_trace_t *tr 
-                = vlib_add_trace (vm, node, b0, sizeof (*tr));
+              lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b0,
+                                                        sizeof(*tr));
               tr->next_index = next0;
               tr->error = error0;
               tr->h = iul0->lisp;
diff --git a/vnet/vnet/lisp-gpe/encap.c b/vnet/vnet/lisp-gpe/encap.c
deleted file mode 100644 (file)
index a815878..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vppinfra/error.h>
-#include <vppinfra/hash.h>
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ip/udp.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vnet/lisp-gpe/lisp_gpe.h>
-
-/* Statistics (not really errors) */
-#define foreach_lisp_gpe_encap_error    \
-_(ENCAPSULATED, "good packets encapsulated")
-
-static char * lisp_gpe_encap_error_strings[] = {
-#define _(sym,string) string,
-  foreach_lisp_gpe_encap_error
-#undef _
-};
-
-typedef enum {
-#define _(sym,str) LISP_GPE_ENCAP_ERROR_##sym,
-  foreach_lisp_gpe_encap_error
-#undef _
-  LISP_GPE_ENCAP_N_ERROR,
-} lisp_gpe_encap_error_t;
-
-typedef enum
-{
-  LISP_GPE_ENCAP_NEXT_DROP,
-  LISP_GPE_ENCAP_NEXT_IP4_LOOKUP,
-  LISP_GPE_ENCAP_N_NEXT,
-} lisp_gpe_encap_next_t;
-
-typedef struct
-{
-  u32 tunnel_index;
-} lisp_gpe_encap_trace_t;
-
-u8 *
-format_lisp_gpe_encap_trace (u8 * s, va_list * args)
-{
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  lisp_gpe_encap_trace_t * t = va_arg (*args, lisp_gpe_encap_trace_t *);
-
-  s = format (s, "LISP-GPE-ENCAP: tunnel %d", t->tunnel_index);
-  return s;
-}
-
-static uword
-lisp_gpe_encap (vlib_main_t * vm, vlib_node_runtime_t * node,
-                vlib_frame_t * from_frame)
-{
-  u32 n_left_from, next_index, * from, * to_next;
-  lisp_gpe_main_t * lgm = &lisp_gpe_main;
-  u32 pkts_encapsulated = 0;
-
-  from = vlib_frame_vector_args (from_frame);
-  n_left_from = from_frame->n_vectors;
-
-  next_index = node->cached_next_index;
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index,
-                           to_next, n_left_to_next);
-
-      while (n_left_from >= 4 && n_left_to_next >= 2)
-        {
-          u32 bi0, bi1;
-          vlib_buffer_t * b0, * b1;
-          u32 next0, next1;
-          u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
-          ip_adjacency_t * adj0, * adj1;
-          lisp_gpe_tunnel_t * t0, * t1;
-
-          next0 = next1 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP;
-
-          /* Prefetch next iteration. */
-            {
-              vlib_buffer_t * p2, *p3;
-
-              p2 = vlib_get_buffer (vm, from[2]);
-              p3 = vlib_get_buffer (vm, from[3]);
-
-              vlib_prefetch_buffer_header(p2, LOAD);
-              vlib_prefetch_buffer_header(p3, LOAD);
-
-              CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
-              CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
-            }
-
-          bi0 = from[0];
-          bi1 = from[1];
-          to_next[0] = bi0;
-          to_next[1] = bi1;
-          from += 2;
-          to_next += 2;
-          n_left_to_next -= 2;
-          n_left_from -= 2;
-
-          b0 = vlib_get_buffer (vm, bi0);
-          b1 = vlib_get_buffer (vm, bi1);
-
-          /* Get adjacency and from it the tunnel_index */
-          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
-          adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
-
-          adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
-          adj1 = ip_get_adjacency (lgm->lookup_main, adj_index1);
-
-          tunnel_index0 = adj0->rewrite_header.sw_if_index;
-          tunnel_index1 = adj1->rewrite_header.sw_if_index;
-
-          t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
-          t1 = pool_elt_at_index (lgm->tunnels, tunnel_index1);
-
-          ASSERT(t0 != 0);
-          ASSERT(t1 != 0);
-
-          ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
-          ip4_udp_encap_two (vm, b0, b1, t0->rewrite, t1->rewrite, 36);
-
-          /* Reset to look up tunnel partner in the configured FIB */
-          vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
-          vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index;
-
-          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0,
-                                                           sizeof(*tr));
-              tr->tunnel_index = t0 - lgm->tunnels;
-            }
-          if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
-            {
-              lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b1,
-                                                           sizeof(*tr));
-              tr->tunnel_index = t1 - lgm->tunnels;
-            }
-
-          pkts_encapsulated += 2;
-
-          vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, bi1, next0,
-                                          next1);
-        }
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-        {
-          vlib_buffer_t * b0;
-          u32 bi0, adj_index0, tunnel_index0;
-          u32 next0 = LISP_GPE_ENCAP_NEXT_IP4_LOOKUP;
-          lisp_gpe_tunnel_t * t0 = 0;
-          ip_adjacency_t * adj0;
-
-          bi0 = from[0];
-          to_next[0] = bi0;
-          from += 1;
-          to_next += 1;
-          n_left_from -= 1;
-          n_left_to_next -= 1;
-
-          b0 = vlib_get_buffer (vm, bi0);
-
-          /* Get adjacency and from it the tunnel_index */
-          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
-          adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
-
-          tunnel_index0 = adj0->rewrite_header.sw_if_index;
-          t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
-
-          ASSERT(t0 != 0);
-
-          ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
-          ip4_udp_encap_one (vm, b0, t0->rewrite, 36);
-
-          /* Reset to look up tunnel partner in the configured FIB */
-          vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
-
-          pkts_encapsulated++;
-
-          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
-            {
-              lisp_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0,
-                                                           sizeof(*tr));
-              tr->tunnel_index = t0 - lgm->tunnels;
-            }
-          vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
-                                          n_left_to_next, bi0, next0);
-        }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-  vlib_node_increment_counter (vm, node->node_index, 
-                               LISP_GPE_ENCAP_ERROR_ENCAPSULATED, 
-                               pkts_encapsulated);
-  return from_frame->n_vectors;
-}
-
-VLIB_REGISTER_NODE (lisp_gpe_encap_node) = {
-  .function = lisp_gpe_encap,
-  .name = "lisp-gpe-encap",
-  .vector_size = sizeof (u32),
-  .format_trace = format_lisp_gpe_encap_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-
-  .n_errors = ARRAY_LEN(lisp_gpe_encap_error_strings),
-  .error_strings = lisp_gpe_encap_error_strings,
-
-  .n_next_nodes = LISP_GPE_ENCAP_N_NEXT,
-
-  .next_nodes = {
-      [LISP_GPE_ENCAP_NEXT_DROP] = "error-drop",
-      [LISP_GPE_ENCAP_NEXT_IP4_LOOKUP] = "ip4-lookup",
-  },
-};
diff --git a/vnet/vnet/lisp-gpe/interface.c b/vnet/vnet/lisp-gpe/interface.c
new file mode 100644 (file)
index 0000000..0f7f6fc
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vppinfra/error.h>
+#include <vppinfra/hash.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ip/udp.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/lisp-gpe/lisp_gpe.h>
+
+#define foreach_lisp_gpe_tx_next        \
+  _(DROP, "error-drop")                 \
+  _(IP4_LOOKUP, "ip4-lookup")
+
+typedef enum
+{
+#define _(sym,str) LISP_GPE_TX_NEXT_##sym,
+  foreach_lisp_gpe_tx_next
+#undef _
+  LISP_GPE_TX_N_NEXT,
+} lisp_gpe_tx_next_t;
+
+typedef struct
+{
+  u32 tunnel_index;
+} lisp_gpe_tx_trace_t;
+
+u8 *
+format_lisp_gpe_tx_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  lisp_gpe_tx_trace_t * t = va_arg (*args, lisp_gpe_tx_trace_t *);
+
+  s = format (s, "LISP-GPE-TX: tunnel %d", t->tunnel_index);
+  return s;
+}
+
+static uword
+lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
+                       vlib_frame_t * from_frame)
+{
+  u32 n_left_from, next_index, * from, * to_next;
+  lisp_gpe_main_t * lgm = &lisp_gpe_main;
+  u32 pkts_encapsulated = 0;
+
+  from = vlib_frame_vector_args (from_frame);
+  n_left_from = from_frame->n_vectors;
+
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index,
+                           to_next, n_left_to_next);
+
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+        {
+          u32 bi0, bi1;
+          vlib_buffer_t * b0, * b1;
+          u32 next0, next1;
+          u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
+          ip_adjacency_t * adj0, * adj1;
+          lisp_gpe_tunnel_t * t0, * t1;
+
+          next0 = next1 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+
+          /* Prefetch next iteration. */
+            {
+              vlib_buffer_t * p2, *p3;
+
+              p2 = vlib_get_buffer (vm, from[2]);
+              p3 = vlib_get_buffer (vm, from[3]);
+
+              vlib_prefetch_buffer_header(p2, LOAD);
+              vlib_prefetch_buffer_header(p3, LOAD);
+
+              CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
+              CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
+            }
+
+          bi0 = from[0];
+          bi1 = from[1];
+          to_next[0] = bi0;
+          to_next[1] = bi1;
+          from += 2;
+          to_next += 2;
+          n_left_to_next -= 2;
+          n_left_from -= 2;
+
+          b0 = vlib_get_buffer (vm, bi0);
+          b1 = vlib_get_buffer (vm, bi1);
+
+          /* Get adjacency and from it the tunnel_index */
+          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+          adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+
+          adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
+          adj1 = ip_get_adjacency (lgm->lookup_main, adj_index1);
+
+          tunnel_index0 = adj0->rewrite_header.node_index;
+          tunnel_index1 = adj1->rewrite_header.node_index;
+
+          t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
+          t1 = pool_elt_at_index (lgm->tunnels, tunnel_index1);
+
+          ASSERT(t0 != 0);
+          ASSERT(t1 != 0);
+
+          ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
+          ip4_udp_encap_two (vm, b0, b1, t0->rewrite, t1->rewrite, 36);
+
+          /* Reset to look up tunnel partner in the configured FIB */
+          vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
+          vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index;
+
+          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+            {
+              lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+                                                           sizeof(*tr));
+              tr->tunnel_index = t0 - lgm->tunnels;
+            }
+          if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
+            {
+              lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b1,
+                                                           sizeof(*tr));
+              tr->tunnel_index = t1 - lgm->tunnels;
+            }
+
+          pkts_encapsulated += 2;
+
+          vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, bi1, next0,
+                                          next1);
+        }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+        {
+          vlib_buffer_t * b0;
+          u32 bi0, adj_index0, tunnel_index0;
+          u32 next0 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+          lisp_gpe_tunnel_t * t0 = 0;
+          ip_adjacency_t * adj0;
+
+          bi0 = from[0];
+          to_next[0] = bi0;
+          from += 1;
+          to_next += 1;
+          n_left_from -= 1;
+          n_left_to_next -= 1;
+
+          b0 = vlib_get_buffer (vm, bi0);
+
+          /* Get adjacency and from it the tunnel_index */
+          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+          adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
+
+          tunnel_index0 = adj0->rewrite_header.node_index;
+          t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
+
+          ASSERT(t0 != 0);
+
+          ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
+          ip4_udp_encap_one (vm, b0, t0->rewrite, 36);
+
+          /* Reset to look up tunnel partner in the configured FIB */
+          vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
+
+          pkts_encapsulated++;
+
+          if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
+            {
+              lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+                                                           sizeof(*tr));
+              tr->tunnel_index = t0 - lgm->tunnels;
+            }
+          vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+        }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+  vlib_node_increment_counter (vm, node->node_index,
+                               LISP_GPE_ERROR_ENCAPSULATED, pkts_encapsulated);
+  return from_frame->n_vectors;
+}
+
+static u8 *
+format_lisp_gpe_name (u8 * s, va_list * args)
+{
+  u32 dev_instance = va_arg (*args, u32);
+  return format (s, "lisp_gpe%d", dev_instance);
+}
+
+VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = {
+  .name = "LISP_GPE",
+  .format_device_name = format_lisp_gpe_name,
+  .format_tx_trace = format_lisp_gpe_tx_trace,
+  .tx_function = lisp_gpe_interface_tx,
+  .no_flatten_output_chains = 1,
+};
+
+static uword
+dummy_set_rewrite (vnet_main_t * vnm, u32 sw_if_index, u32 l3_type,
+                   void * dst_address, void * rewrite, uword max_rewrite_bytes)
+{
+  return 0;
+}
+
+u8 *
+format_lisp_gpe_header_with_length (u8 * s, va_list * args)
+{
+  lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *);
+  u32 max_header_bytes = va_arg (*args, u32);
+  u32 header_bytes;
+
+  header_bytes = sizeof (h[0]);
+  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
+    return format (s, "lisp-gpe header truncated");
+
+  s = format (s, "flags: ");
+#define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
+  foreach_lisp_gpe_flag_bit;
+#undef _
+
+  s = format (s, "\n  ver_res %d res %d next_protocol %d iid %d(%x)",
+              h->ver_res, h->res, h->next_protocol,
+              clib_net_to_host_u32 (h->iid),
+              clib_net_to_host_u32 (h->iid));
+  return s;
+}
+
+VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
+  .name = "LISP_GPE",
+  .format_header = format_lisp_gpe_header_with_length,
+  .set_rewrite = dummy_set_rewrite,
+};
+
+int
+add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
+                         ip_adjacency_t * add_adj, u8 is_add, u32 * adj_index)
+{
+  uword * p;
+
+  if (ip_prefix_version(dst_prefix) == IP4)
+    {
+      ip4_main_t * im4 = &ip4_main;
+      ip4_add_del_route_args_t a;
+      ip4_address_t addr = ip_prefix_v4(dst_prefix);
+
+      memset(&a, 0, sizeof(a));
+      a.flags = IP4_ROUTE_FLAG_TABLE_ID;
+      a.table_index_or_table_id = table_id;
+      a.adj_index = ~0;
+      a.dst_address_length = ip_prefix_len(dst_prefix);
+      a.dst_address = addr;
+      a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
+      a.add_adj = add_adj;
+      a.n_add_adj = 1;
+      ip4_add_del_route (im4, &a);
+
+      if (is_add)
+        {
+          p = ip4_get_route (im4, table_id, 0, addr.as_u8,
+                             ip_prefix_len(dst_prefix));
+          if (p == 0)
+            {
+              clib_warning("Failed to insert route for eid %U!",
+                           format_ip4_address_and_length, addr.as_u8,
+                           ip_prefix_len(dst_prefix));
+              return -1;
+            }
+          adj_index[0] = p[0];
+        }
+    }
+  else
+    {
+      ip6_main_t * im6 = &ip6_main;
+      ip6_add_del_route_args_t a;
+      ip6_address_t addr = ip_prefix_v6(dst_prefix);
+
+      memset(&a, 0, sizeof(a));
+      a.flags = IP6_ROUTE_FLAG_TABLE_ID;
+      a.table_index_or_table_id = table_id;
+      a.adj_index = ~0;
+      a.dst_address_length = ip_prefix_len(dst_prefix);
+      a.dst_address = addr;
+      a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
+      a.add_adj = add_adj;
+      a.n_add_adj = 1;
+
+      ip6_add_del_route (im6, &a);
+
+      if (is_add)
+        {
+          adj_index[0] = ip6_get_route (im6, table_id, 0, &addr,
+                                        ip_prefix_len(dst_prefix));
+          if (adj_index[0] == 0)
+            {
+              clib_warning("Failed to insert route for eid %U!",
+                           format_ip6_address_and_length, addr.as_u8,
+                           ip_prefix_len(dst_prefix));
+              return -1;
+            }
+        }
+    }
+  return 0;
+}
+
+static void
+add_del_lisp_gpe_default_route (u32 table_id, u8 is_v4, u8 is_add)
+{
+  lisp_gpe_main_t * lgm = &lisp_gpe_main;
+  ip_adjacency_t adj;
+  ip_prefix_t prefix;
+  u32 adj_index = 0;
+
+  /* setup adjacency */
+  memset (&adj, 0, sizeof(adj));
+
+  adj.n_adj = 1;
+  adj.explicit_fib_index = ~0;
+  adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup;
+  /* default route has tunnel_index ~0 */
+  adj.rewrite_header.sw_if_index = ~0;
+
+  /* set prefix to 0/0 */
+  memset(&prefix, 0, sizeof(prefix));
+  ip_prefix_version(&prefix) = is_v4 ? IP4 : IP6;
+
+  /* add/delete route for prefix */
+  add_del_ip_prefix_route (&prefix, table_id, &adj, is_add, &adj_index);
+}
+
+static void
+lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id, u8 is_ip4)
+{
+  if (is_ip4)
+    {
+      ip4_main_t * im4 = &ip4_main;
+      ip4_fib_t * fib;
+      fib = find_ip4_fib_by_table_index_or_id (im4, table_id,
+                                               IP4_ROUTE_FLAG_TABLE_ID);
+
+      /* fib's created if it doesn't exist */
+      ASSERT(fib != 0);
+
+      vec_validate(im4->fib_index_by_sw_if_index, sw_if_index);
+      im4->fib_index_by_sw_if_index[sw_if_index] = fib->index;
+    }
+  else
+    {
+      ip6_main_t * im6 = &ip6_main;
+      ip6_fib_t * fib;
+      fib = find_ip6_fib_by_table_index_or_id (im6, table_id,
+                                               IP6_ROUTE_FLAG_TABLE_ID);
+
+      /* fib's created if it doesn't exist */
+      ASSERT(fib != 0);
+
+      vec_validate(im6->fib_index_by_sw_if_index, sw_if_index);
+      im6->fib_index_by_sw_if_index[sw_if_index] = fib->index;
+    }
+}
+
+void
+vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
+                             u32 * hw_if_indexp)
+{
+  lisp_gpe_main_t * lgm = &lisp_gpe_main;
+  vnet_main_t * vnm = lgm->vnet_main;
+  vnet_hw_interface_t * hi;
+  u32 hw_if_index = ~0, lookup_next_index, flen;
+  uword * hip, * vni;
+
+  hip = hash_get(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id);
+
+  if (a->is_add)
+    {
+      if (hip)
+        {
+          clib_warning ("Interface for vrf %d already exists", a->table_id);
+          return;
+        }
+
+      /* create hw lisp_gpeX iface if needed, otherwise reuse existing */
+      flen = vec_len(lgm->free_lisp_gpe_tunnel_hw_if_indices);
+      if (flen > 0)
+        {
+          hw_if_index = lgm->free_lisp_gpe_tunnel_hw_if_indices[flen - 1];
+          _vec_len(lgm->free_lisp_gpe_tunnel_hw_if_indices) -= 1;
+        }
+      else
+        {
+          hw_if_index = vnet_register_interface (vnm,
+                                                 lisp_gpe_device_class.index,
+                                                 a->table_id,
+                                                 lisp_gpe_hw_class.index, 0);
+        }
+
+      hi = vnet_get_hw_interface (vnm, hw_if_index);
+      hash_set(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id, hw_if_index);
+
+      /* set tunnel termination: post decap, packets are tagged as having been
+       * originated by lisp-gpe interface */
+      hash_set(lgm->tunnel_term_sw_if_index_by_vni, a->vni, hi->sw_if_index);
+      hash_set(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index, a->vni);
+
+      /* set ingress arc from lgpe_ip4_lookup */
+      lookup_next_index = vlib_node_add_next (lgm->vlib_main,
+                                              lgpe_ip4_lookup_node.index,
+                                              hi->output_node_index);
+      hash_set(lgm->lgpe_ip4_lookup_next_index_by_table_id, a->table_id,
+               lookup_next_index);
+
+      /* insert default routes that point to lgpe-ipx-lookup */
+      add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 1);
+      add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 1);
+
+      /* set egress arcs */
+#define _(sym,str) vlib_node_add_named_next_with_slot (vnm->vlib_main, \
+                    hi->tx_node_index, str, LISP_GPE_TX_NEXT_##sym);
+          foreach_lisp_gpe_tx_next
+#undef _
+
+      /* set interface in appropriate v4 and v6 FIBs */
+      lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id, 1);
+      lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id, 0);
+
+      /* enable interface */
+      vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
+                                   VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+      vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
+                                   VNET_HW_INTERFACE_FLAG_LINK_UP);
+    }
+  else
+    {
+      if (hip == 0)
+        {
+          clib_warning("The interface for vrf %d doesn't exist", a->table_id);
+          return;
+        }
+      hi = vnet_get_hw_interface (vnm, hip[0]);
+
+      /* disable interface */
+      vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0/* down */);
+      vnet_hw_interface_set_flags (vnm, hi->hw_if_index, 0/* down */);
+      hash_unset(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id);
+      vec_add1(lgm->free_lisp_gpe_tunnel_hw_if_indices, hi->hw_if_index);
+
+      /* clean tunnel termination and vni to sw_if_index binding */
+      vni = hash_get(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index);
+      hash_unset(lgm->tunnel_term_sw_if_index_by_vni, vni[0]);
+      hash_unset(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index);
+
+      /* unset default routes */
+      add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 0);
+      add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 0);
+    }
+}
+
+static clib_error_t *
+lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
+                                   vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, * line_input = &_line_input;
+  u8 is_add = 1;
+  u32 table_id;
+
+  vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
+
+  /* Get a line of input. */
+  if (! unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "add"))
+        is_add = 1;
+      else if (unformat (line_input, "del"))
+        is_add = 0;
+      else if (unformat (line_input, "vrf %d", &table_id))
+        ;
+      else
+        {
+          return clib_error_return (0, "parse error: '%U'",
+                                   format_unformat_error, line_input);
+        }
+    }
+
+  a->is_add = is_add;
+  a->table_id = table_id;
+  vnet_lisp_gpe_add_del_iface (a, 0);
+  return 0;
+}
+
+VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
+  .path = "lisp gpe iface",
+  .short_help = "lisp gpe iface add/del table-index <table_index> vrf <vrf>",
+  .function = lisp_gpe_add_del_iface_command_fn,
+};
index b807249..fd1e1a4 100644 (file)
@@ -177,7 +177,7 @@ ip4_sd_fib_clear_src_fib (lisp_gpe_main_t * lgm, ip4_fib_t * fib)
 
 int
 ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
-                          ip_prefix_t * src_prefix, u32 table_index,
+                          ip_prefix_t * src_prefix, u32 table_id,
                           ip_adjacency_t * add_adj, u8 is_add)
 {
   uword * p;
@@ -196,7 +196,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
     memset(&src, 0, sizeof(src));
 
   /* lookup dst adj */
-  p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, dst_address_length);
+  p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length);
 
   if (is_add)
     {
@@ -209,7 +209,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
 
           memset(&a, 0, sizeof(a));
           a.flags = IP4_ROUTE_FLAG_TABLE_ID;
-          a.table_index_or_table_id = table_index; /* vrf */
+          a.table_index_or_table_id = table_id; /* vrf */
           a.adj_index = ~0;
           a.dst_address_length = dst_address_length;
           a.dst_address = dst;
@@ -220,7 +220,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
           ip4_add_del_route (lgm->im4, &a);
 
           /* lookup dst adj to obtain the adj index */
-          p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8,
+          p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8,
                              dst_address_length);
           if (p == 0)
             {
@@ -283,7 +283,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
       /* .. and remove dst route */
       memset(&a, 0, sizeof(a));
       a.flags = IP4_ROUTE_FLAG_TABLE_ID;
-      a.table_index_or_table_id = table_index; /* vrf */
+      a.table_index_or_table_id = table_id; /* vrf */
       a.adj_index = ~0;
       a.dst_address_length = dst_address_length;
       a.dst_address = dst;
@@ -297,7 +297,7 @@ ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
 
 static void *
 ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
-                      ip_prefix_t * src_prefix, u32 table_index)
+                      ip_prefix_t * src_prefix, u32 table_id)
 {
   uword * p;
   ip4_address_t dst = ip_prefix_v4(dst_prefix), src;
@@ -313,7 +313,7 @@ ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix,
     memset(&src, 0, sizeof(src));
 
   /* lookup dst adj */
-  p = ip4_get_route (lgm->im4, table_index, 0, dst.as_u8, dst_address_length);
+  p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length);
   if (p == 0)
       return p;
 
@@ -326,7 +326,6 @@ typedef enum
 {
   LGPE_IP4_LOOKUP_NEXT_DROP,
   LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP,
-  LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP,
   LGPE_IP4_LOOKUP_N_NEXT,
 } lgpe_ip4_lookup_next_t;
 
@@ -468,6 +467,12 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
 
               next0 = src_adj0->lookup_next_index;
               next1 = src_adj1->lookup_next_index;
+
+              /* prepare buffer for lisp-gpe output node */
+              vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+                  src_adj0->rewrite_header.sw_if_index;
+              vnet_buffer (b1)->sw_if_index[VLIB_TX] =
+                  src_adj1->rewrite_header.sw_if_index;
             }
           else
             {
@@ -479,6 +484,7 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
                   src_adj0 = ip_get_adjacency (lgm->lookup_main,
                                                src_adj_index0);
                   next0 = src_adj0->lookup_next_index;
+                  vnet_buffer (b0)->sw_if_index[VLIB_TX] = src_adj_index0;
                 }
               if (src_fib_index1 != (u32) ~0)
                 {
@@ -488,6 +494,7 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
                   src_adj1 = ip_get_adjacency (lgm->lookup_main,
                                                src_adj_index1);
                   next1 = src_adj1->lookup_next_index;
+                  vnet_buffer (b1)->sw_if_index[VLIB_TX] = src_adj_index1;
                 }
             }
 
@@ -530,6 +537,9 @@ lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
           src_adj0 = ip_get_adjacency (lgm->lookup_main, src_adj_index0);
           next0 = src_adj0->lookup_next_index;
 
+          /* prepare packet for lisp-gpe output node */
+          vnet_buffer (b0)->sw_if_index[VLIB_TX] =
+              src_adj0->rewrite_header.sw_if_index;
         done:
           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
                                           n_left_to_next, bi0, next0);
@@ -551,7 +561,6 @@ VLIB_REGISTER_NODE (lgpe_ip4_lookup_node) = {
   .next_nodes = {
       [LGPE_IP4_LOOKUP_NEXT_DROP] = "error-drop",
       [LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP] = "lisp-cp-lookup",
-      [LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP] = "lisp-gpe-encap",
   },
 };
 
@@ -592,7 +601,7 @@ lisp_gpe_rewrite (lisp_gpe_tunnel_t * t)
   lisp0->ver_res = t->ver_res;
   lisp0->res = t->res;
   lisp0->next_protocol = t->next_protocol;
-  lisp0->iid = clib_host_to_net_u32 (t->iid);
+  lisp0->iid = clib_host_to_net_u32 (t->vni);
 
   t->rewrite = rw;
   return 0;
@@ -615,7 +624,7 @@ _(flags)                                        \
 _(next_protocol)                                \
 _(ver_res)                                      \
 _(res)                                          \
-_(iid)
+_(vni)
 
 static u32
 add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res)
@@ -629,7 +638,7 @@ add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res)
   memset(&key, 0, sizeof(key));
   gid_address_copy(&key.eid, &a->deid);
   key.dst_loc = ip_addr_v4(&a->dlocator).as_u32;
-  key.iid = clib_host_to_net_u32 (a->iid);
+  key.iid = clib_host_to_net_u32 (a->vni);
 
   p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key);
 
@@ -688,6 +697,41 @@ add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res)
   return 0;
 }
 
+static int
+add_del_negative_fwd_entry (lisp_gpe_main_t * lgm,
+                            vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+{
+  ip_adjacency_t adj;
+  /* setup adjacency for eid */
+  memset (&adj, 0, sizeof(adj));
+  adj.n_adj = 1;
+  adj.explicit_fib_index = ~0;
+
+  ip_prefix_t * dpref = &gid_address_ippref(&a->deid);
+  ip_prefix_t * spref = &gid_address_ippref(&a->seid);
+
+  switch (a->action)
+    {
+    case NO_ACTION:
+      /* TODO update timers? */
+    case FORWARD_NATIVE:
+      /* TODO check if route/next-hop for eid exists in fib and add
+       * more specific for the eid with the next-hop found */
+    case SEND_MAP_REQUEST:
+      /* TODO insert tunnel that always sends map-request */
+    case DROP:
+      /* for drop fwd entries, just add route, no need to add encap tunnel */
+      adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_DROP;
+
+      /* add/delete route for prefix */
+      return ip4_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj,
+                                       a->is_add);
+      break;
+    default:
+      return -1;
+    }
+}
+
 int
 vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
                                  u32 * hw_if_indexp)
@@ -695,66 +739,59 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
   lisp_gpe_main_t * lgm = &lisp_gpe_main;
   ip_adjacency_t adj, * adjp;
   u32 * adj_index, rv, tun_index = ~0;
-  ip_prefix_t * dpref = &gid_address_ippref(&a->deid);
-  ip_prefix_t * spref = &gid_address_ippref(&a->seid);
+  ip_prefix_t * dpref, * spref;
+  uword * lookup_next_index, * lgpe_sw_if_index;
+
+  /* treat negative fwd entries separately */
+  if (a->is_negative)
+    return add_del_negative_fwd_entry (lgm, a);
+
+  /* add/del tunnel to tunnels pool and prepares rewrite */
+  rv = add_del_tunnel (a, &tun_index);
+  if (rv)
+    return rv;
+
+  dpref = &gid_address_ippref(&a->deid);
+  spref = &gid_address_ippref(&a->seid);
 
   /* setup adjacency for eid */
   memset (&adj, 0, sizeof(adj));
   adj.n_adj = 1;
   adj.explicit_fib_index = ~0;
 
-  /* treat negative fwd entries separately */
-  if (a->is_negative)
+  if (a->is_add)
     {
-      switch (a->action)
-        {
-        case NO_ACTION:
-          /* TODO update timers? */
-        case FORWARD_NATIVE:
-          /* TODO check if route/next-hop for eid exists in fib and add
-           * more specific for the eid with the next-hop found */
-        case SEND_MAP_REQUEST:
-          /* TODO insert tunnel that always sends map-request */
-        case DROP:
-          /* for drop fwd entries, just add route, no need to add encap tunnel */
-          adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_DROP;
-
-          /* add/delete route for prefix */
-          rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->iid, &adj,
-                                         a->is_add);
-          return rv;
-          break;
-        default:
-          return -1;
-        }
+      /* send packets that hit this adj to lisp-gpe interface output node in
+       * requested vrf. */
+      lookup_next_index = hash_get(lgm->lgpe_ip4_lookup_next_index_by_table_id,
+                                   a->table_id);
+      lgpe_sw_if_index = hash_get(lgm->lisp_gpe_hw_if_index_by_table_id,
+                                  a->table_id);
+
+      /* the assumption is that the interface must've been created before
+       * programming the dp */
+      ASSERT(lookup_next_index != 0);
+      ASSERT(lgpe_sw_if_index != 0);
+
+      adj.lookup_next_index = lookup_next_index[0];
+      adj.rewrite_header.node_index = tun_index;
+      adj.rewrite_header.sw_if_index = lgpe_sw_if_index[0];
     }
 
-  /* send packets that hit this adj to lisp-gpe encap */
-  adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_LGPE_ENCAP;
+  /* add/delete route for prefix */
+  rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj,
+                                 a->is_add);
 
-  /* add/delete route for prefix
-   * TODO use hash to decide fib instead of using iid in clear */
-  rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->iid, &adj, a->is_add);
-
-  if (rv)
-    return rv;
-
-  /* add/del tunnel to tunnels pool */
-  rv = add_del_tunnel (a, &tun_index);
-
-  /* reuse sw_if_index for storing the tunnel index */
-  if (a->is_add)
+  /* check that everything worked */
+  if (CLIB_DEBUG && a->is_add)
     {
-      adj_index = ip4_sd_fib_get_route(lgm, dpref, spref, a->iid);
-      if (!adj_index)
-        {
-          clib_warning("Failed to insert fwd entry! For %U",
-                       format_ip4_address_and_length, ip_prefix_v4(dpref),
-                       ip_prefix_len(dpref));
-          return -1;
-        }
+      adj_index = ip4_sd_fib_get_route (lgm, dpref, spref, a->table_id);
+      ASSERT(adj_index != 0);
+
       adjp = ip_get_adjacency (lgm->lookup_main, adj_index[0]);
-      adjp->rewrite_header.sw_if_index = tun_index;
+
+      ASSERT(adjp != 0);
+      ASSERT(adjp->rewrite_header.node_index == tun_index);
     }
 
   return rv;
@@ -810,7 +847,8 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
 
   if (vec_len (eids) != vec_len (slocators))
     {
-      error = clib_error_return (0, "number of eids not equal to that of locators.");
+      error = clib_error_return (0, "number of eids not equal to that of "
+          "locators.");
       goto done;
     }
 
@@ -837,105 +875,11 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
 
 VLIB_CLI_COMMAND (add_del_lisp_gpe_mapping_tunnel_command, static) = {
   .path = "lisp gpe maptunnel",
-  .short_help = "lisp gpe maptunnel eid <eid> sloc <src-locator> dloc <dst-locator> [del]",
+  .short_help = "lisp gpe maptunnel eid <eid> sloc <src-locator> "
+      "dloc <dst-locator> [del]",
   .function = lisp_gpe_add_del_fwd_entry_command_fn,
 };
 
-int
-add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
-                         ip_adjacency_t * add_adj, u8 is_add, u32 * adj_index)
-{
-  uword * p;
-
-  if (ip_prefix_version(dst_prefix) == IP4)
-    {
-      ip4_main_t * im4 = &ip4_main;
-      ip4_add_del_route_args_t a;
-      ip4_address_t addr = ip_prefix_v4(dst_prefix);
-
-      memset(&a, 0, sizeof(a));
-      a.flags = IP4_ROUTE_FLAG_TABLE_ID;
-      a.table_index_or_table_id = table_id;
-      a.adj_index = ~0;
-      a.dst_address_length = ip_prefix_len(dst_prefix);
-      a.dst_address = addr;
-      a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
-      a.add_adj = add_adj;
-      a.n_add_adj = 1;
-      ip4_add_del_route (im4, &a);
-
-      if (is_add)
-        {
-          p = ip4_get_route (im4, table_id, 0, addr.as_u8,
-                             ip_prefix_len(dst_prefix));
-          if (p == 0)
-            {
-              clib_warning("Failed to insert route for eid %U!",
-                           format_ip4_address_and_length, addr.as_u8,
-                           ip_prefix_len(dst_prefix));
-              return -1;
-            }
-          adj_index[0] = p[0];
-        }
-    }
-  else
-    {
-      ip6_main_t * im6 = &ip6_main;
-      ip6_add_del_route_args_t a;
-      ip6_address_t addr = ip_prefix_v6(dst_prefix);
-
-      memset(&a, 0, sizeof(a));
-      a.flags = IP6_ROUTE_FLAG_TABLE_ID;
-      a.table_index_or_table_id = table_id;
-      a.adj_index = ~0;
-      a.dst_address_length = ip_prefix_len(dst_prefix);
-      a.dst_address = addr;
-      a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
-      a.add_adj = add_adj;
-      a.n_add_adj = 1;
-
-      ip6_add_del_route (im6, &a);
-
-      if (is_add)
-        {
-          adj_index[0] = ip6_get_route (im6, table_id, 0, &addr,
-                                        ip_prefix_len(dst_prefix));
-          if (adj_index[0] == 0)
-            {
-              clib_warning("Failed to insert route for eid %U!",
-                           format_ip6_address_and_length, addr.as_u8,
-                           ip_prefix_len(dst_prefix));
-              return -1;
-            }
-        }
-    }
-  return 0;
-}
-
-static void
-add_del_lisp_gpe_default_route (u8 is_v4, u8 is_add)
-{
-  lisp_gpe_main_t * lgm = &lisp_gpe_main;
-  ip_adjacency_t adj;
-  ip_prefix_t prefix;
-  u32 adj_index = 0;
-
-  /* setup adjacency */
-  memset (&adj, 0, sizeof(adj));
-  adj.n_adj = 1;
-  adj.explicit_fib_index = ~0;
-  adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup;
-  /* default route has tunnel_index ~0 */
-  adj.rewrite_header.sw_if_index = ~0;
-
-  /* set prefix to 0/0 */
-  memset(&prefix, 0, sizeof(prefix));
-  ip_prefix_version(&prefix) = is_v4 ? IP4 : IP6;
-
-  /* add/delete route for prefix XXX default table only */
-  add_del_ip_prefix_route (&prefix, 0, &adj, is_add, &adj_index);
-}
-
 static u8 *
 format_decap_next (u8 * s, va_list * args)
 {
@@ -949,8 +893,6 @@ format_decap_next (u8 * s, va_list * args)
       return format (s, "ip4");
     case LISP_GPE_INPUT_NEXT_IP6_INPUT:
       return format (s, "ip6");
-    case LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP:
-      return format (s, "nsh-lisp-gpe");
     default:
       return format (s, "unknown %d", next_index);
     }
@@ -981,7 +923,7 @@ format_lisp_gpe_tunnel (u8 * s, va_list * args)
   s = format (s, "next_protocol %d ver_res %x res %x\n",
               t->next_protocol, t->ver_res, t->res);
 
-  s = format (s, "iid %d (0x%x)\n", t->iid, t->iid);
+  s = format (s, "iid %d (0x%x)\n", t->vni, t->vni);
   return s;
 }
 
@@ -1009,106 +951,74 @@ VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) = {
     .function = show_lisp_gpe_tunnel_command_fn,
 };
 
-static u8 *
-format_lisp_gpe_name (u8 * s, va_list * args)
-{
-  u32 dev_instance = va_arg (*args, u32);
-  return format (s, "lisp_gpe_tunnel%d", dev_instance);
-}
-
-static uword
-dummy_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
-                    vlib_frame_t * frame)
-{
-  clib_warning("you shouldn't be here, leaking buffers...");
-  return frame->n_vectors;
-}
-
-VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = {
-  .name = "LISP_GPE",
-  .format_device_name = format_lisp_gpe_name,
-  .format_tx_trace = format_lisp_gpe_encap_trace,
-  .tx_function = dummy_interface_tx,
-};
-
-static uword
-dummy_set_rewrite (vnet_main_t * vnm, u32 sw_if_index, u32 l3_type,
-                   void * dst_address, void * rewrite, uword max_rewrite_bytes)
-{
-  return 0;
-}
-
-u8 *
-format_lisp_gpe_header_with_length (u8 * s, va_list * args)
-{
-  lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *);
-  u32 max_header_bytes = va_arg (*args, u32);
-  u32 header_bytes;
-
-  header_bytes = sizeof (h[0]);
-  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
-    return format (s, "gre-nsh header truncated");
-
-  s = format (s, "flags: ");
-#define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
-  foreach_lisp_gpe_flag_bit;
-#undef _
-
-  s = format (s, "\n  ver_res %d res %d next_protocol %d iid %d(%x)",
-              h->ver_res, h->res, h->next_protocol,
-              clib_net_to_host_u32 (h->iid),
-              clib_net_to_host_u32 (h->iid));
-  return s;
-}
-
-VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
-  .name = "LISP_GPE",
-  .format_header = format_lisp_gpe_header_with_length,
-  .set_rewrite = dummy_set_rewrite,
-};
-
-void
-vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
-                             u32 * hw_if_indexp)
+clib_error_t *
+vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a)
 {
   lisp_gpe_main_t * lgm = &lisp_gpe_main;
   vnet_main_t * vnm = lgm->vnet_main;
-  vnet_hw_interface_t * hi;
-  u32 hw_if_index = ~0;
 
-  if (a->is_add)
+  if (a->is_en)
     {
-      /* create hw lisp_gpe0 iface */
-      hw_if_index = vnet_register_interface (vnm, lisp_gpe_device_class.index, 0,
-                                             lisp_gpe_hw_class.index, 0);
-
-      hi = vnet_get_hw_interface (vnm, hw_if_index);
-      hi->output_node_index = lisp_gpe_encap_node.index;
-      lgm->lisp_gpe_hw_if_index = hw_if_index;
-
       /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */
-      lgm->ip4_lookup_next_lgpe_ip4_lookup = vlib_node_add_next (
-          vnm->vlib_main, ip4_lookup_node.index, lgpe_ip4_lookup_node.index);
-
-      /* insert default routes that points at lisp-gpe-encap */
-      add_del_lisp_gpe_default_route(/* is_v4 */1, 1);
-      add_del_lisp_gpe_default_route(/* is_v4 */0, 1);
+      if (lgm->ip4_lookup_next_lgpe_ip4_lookup == ~0)
+        {
+          lgm->ip4_lookup_next_lgpe_ip4_lookup = vlib_node_add_next (
+              vnm->vlib_main, ip4_lookup_node.index,
+              lgpe_ip4_lookup_node.index);
+        }
+      else
+        {
+          /* ask cp to re-add ifaces and defaults */
+        }
     }
   else
     {
-      vnet_sw_interface_set_flags (vnm, lgm->lisp_gpe_hw_if_index,
-                                   0 /* down */);
+      CLIB_UNUSED(uword * val);
+      hash_pair_t * p;
+      u32 * table_ids = 0, * table_id;
+      lisp_gpe_tunnel_key_t * tunnels = 0, * tunnel;
+      vnet_lisp_gpe_add_del_fwd_entry_args_t _at, * at = &_at;
+      vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
+
+      /* remove all tunnels */
+      mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({
+        vec_add1(tunnels, tunnel[0]);
+      }));
+
+      vec_foreach(tunnel, tunnels) {
+        memset(at, 0, sizeof(at[0]));
+        at->is_add = 0;
+        gid_address_copy(&at->deid, &tunnel->eid);
+        ip_addr_v4(&at->dlocator).as_u32= tunnel->dst_loc;
+        vnet_lisp_gpe_add_del_fwd_entry (at, 0);
+      }
+      vec_free(tunnels);
+
+      /* disable all ifaces */
+      hash_foreach_pair(p, lgm->lisp_gpe_hw_if_index_by_table_id, ({
+        vec_add1(table_ids, p->key);
+      }));
+
+      vec_foreach(table_id, table_ids) {
+        ai->is_add = 0;
+        ai->table_id = table_id[0];
+
+        /* disables interface and removes defaults */
+        vnet_lisp_gpe_add_del_iface(ai, 0);
+      }
+      vec_free(table_ids);
     }
+
+  return 0;
 }
 
 static clib_error_t *
-lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm,
-                                   unformat_input_t * input,
-                                   vlib_cli_command_t * cmd)
+lisp_gpe_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
+                                    vlib_cli_command_t * cmd)
 {
   unformat_input_t _line_input, * line_input = &_line_input;
-  u8 is_add = 1;
-  vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
+  u8 is_en = 1;
+  vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
 
   /* Get a line of input. */
   if (! unformat_user (input, unformat_line_input, line_input))
@@ -1116,26 +1026,24 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm,
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (line_input, "up"))
-        is_add = 1;
-      else if (unformat (line_input, "down"))
-        is_add = 0;
+      if (unformat (line_input, "enable"))
+        is_en = 1;
+      else if (unformat (line_input, "disable"))
+        is_en = 0;
       else
         {
           return clib_error_return (0, "parse error: '%U'",
                                    format_unformat_error, line_input);
         }
     }
-
-  a->is_add = is_add;
-  vnet_lisp_gpe_add_del_iface (a, 0);
-  return 0;
+  a->is_en = is_en;
+  return vnet_lisp_gpe_enable_disable (a);
 }
 
-VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
-  .path = "lisp gpe iface",
-  .short_help = "lisp gpe iface [del]",
-  .function = lisp_gpe_add_del_iface_command_fn,
+VLIB_CLI_COMMAND (enable_disable_lisp_gpe_command, static) = {
+  .path = "lisp gpe",
+  .short_help = "lisp gpe [enable|disable]",
+  .function = lisp_gpe_enable_disable_command_fn,
 };
 
 clib_error_t *
@@ -1154,7 +1062,8 @@ lisp_gpe_init (vlib_main_t *vm)
   lgm->vlib_main = vm;
   lgm->im4 = &ip4_main;
   lgm->lookup_main = &ip4_main.lookup_main;
-  
+  lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0;
+
   mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof(uword),
               sizeof(lisp_gpe_tunnel_key_t));
 
index 7e86d57..1452b79 100644 (file)
@@ -74,15 +74,14 @@ typedef struct
   u8 ver_res;
   u8 res;
   u8 next_protocol;
-  u32 iid;
+  u32 vni;
 } lisp_gpe_tunnel_t;
 
 #define foreach_lisp_gpe_input_next             \
 _(DROP, "error-drop")                           \
 _(IP4_INPUT, "ip4-input")                       \
 _(IP6_INPUT, "ip6-input")                       \
-_(ETHERNET_INPUT, "ethernet-input")             \
-_(LISP_GPE_ENCAP, "lisp-gpe-encap")
+_(ETHERNET_INPUT, "ethernet-input")
 
 typedef enum {
 #define _(s,n) LISP_GPE_INPUT_NEXT_##s,
@@ -96,7 +95,7 @@ typedef enum {
 #include <vnet/lisp-gpe/lisp_gpe_error.def>
 #undef lisp_gpe_error
   LISP_GPE_N_ERROR,
-} lisp_gpe_input_error_t;
+} lisp_gpe_error_t;
 
 /* As a first step, reuse v4 fib. The goal of the typedef is to shield
  * consumers from future updates that may result in the lisp ip4 fib diverging
@@ -114,13 +113,18 @@ typedef struct lisp_gpe_main
   /* lookup tunnel by key */
   mhash_t lisp_gpe_tunnel_by_key;
 
-  /* lookup tunnel by adjacency index */
-  uword * lisp_gpe_tunnel_by_adj_index;
+  /* lookup decap tunnel termination sw_if_index by vni and vice versa */
+  uword * tunnel_term_sw_if_index_by_vni;
+  uword * vni_by_tunnel_term_sw_if_index;
 
   /* Free vlib hw_if_indices */
   u32 * free_lisp_gpe_tunnel_hw_if_indices;
 
-  u32 lisp_gpe_hw_if_index;
+  /* Lookup lisp-gpe interfaces by vrf */
+  uword * lisp_gpe_hw_if_index_by_table_id;
+
+  /* Lookup lgpe_ip4_lookup_next by vrf */
+  uword * lgpe_ip4_lookup_next_index_by_table_id;
 
   /* next node indexes that points ip4 lookup to lisp gpe lookup and lisp cp */
   u32 ip4_lookup_next_lgpe_ip4_lookup;
@@ -136,10 +140,9 @@ lisp_gpe_main_t lisp_gpe_main;
 
 extern vlib_node_registration_t lgpe_ip4_lookup_node;
 extern vlib_node_registration_t lisp_gpe_input_node;
-extern vlib_node_registration_t lisp_gpe_encap_node;
 
 u8 *
-format_lisp_gpe_encap_trace (u8 * s, va_list * args);
+format_lisp_gpe_tx_trace (u8 * s, va_list * args);
 u8 *
 format_lisp_gpe_header_with_length (u8 * s, va_list * args);
 
@@ -154,7 +157,7 @@ typedef struct
   u8 ver_res;
   u8 res;
   u8 next_protocol;
-  u32 iid; /* host byte order */
+  u32 vni; /* host byte order */
 } vnet_lisp_gpe_add_del_tunnel_args_t;
 
 int
@@ -164,12 +167,22 @@ vnet_lisp_gpe_add_del_tunnel (vnet_lisp_gpe_add_del_tunnel_args_t *a,
 typedef struct
 {
   u8 is_add;
+  u32 table_id; /* vrf */
+  u32 vni;      /* host byte order */
 } vnet_lisp_gpe_add_del_iface_args_t;
 
 void
 vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t *a,
                             u32 * hw_if_indexp);
 
+typedef struct
+{
+  u8 is_en;
+} vnet_lisp_gpe_enable_disable_args_t;
+
+clib_error_t *
+vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t *a);
+
 typedef enum
 {
   NO_ACTION,
@@ -194,7 +207,8 @@ typedef struct
   u8 ver_res;
   u8 res;
   u8 next_protocol;
-  u32 iid; /* host byte order */
+  u32 vni; /* host byte order */
+  u32 table_id;
 } vnet_lisp_gpe_add_del_fwd_entry_args_t;
 
 int
index f002eca..c4c3f75 100644 (file)
@@ -13,5 +13,6 @@
  * limitations under the License.
  */
  
+lisp_gpe_error (ENCAPSULATED, "good packets encapsulated")
 lisp_gpe_error (DECAPSULATED, "good packets decapsulated")
 lisp_gpe_error (NO_SUCH_TUNNEL, "no such tunnel packets")
index a93a6c5..29629c9 100644 (file)
@@ -1954,8 +1954,6 @@ format_decap_next (u8 * s, va_list * args)
       return format (s, "ip4");
     case LISP_GPE_INPUT_NEXT_IP6_INPUT:
       return format (s, "ip6");
-    case LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP:
-      return format (s, "nsh-lisp-gpe");
     default:
       return format (s, "unknown %d", next_index);
     }
@@ -2161,6 +2159,7 @@ _(lisp_add_del_locator_reply)                           \
 _(lisp_add_del_local_eid_reply)                         \
 _(lisp_gpe_add_del_fwd_entry_reply)                     \
 _(lisp_add_del_map_resolver_reply)                      \
+_(lisp_gpe_enable_disable_reply)                        \
 _(lisp_gpe_add_del_iface_reply)
 
 #define _(n)                                    \
@@ -2329,6 +2328,7 @@ _(LISP_ADD_DEL_LOCATOR_REPLY, lisp_add_del_locator_reply)               \
 _(LISP_ADD_DEL_LOCAL_EID_REPLY, lisp_add_del_local_eid_reply)           \
 _(LISP_GPE_ADD_DEL_FWD_ENTRY_REPLY, lisp_gpe_add_del_fwd_entry_reply)   \
 _(LISP_ADD_DEL_MAP_RESOLVER_REPLY, lisp_add_del_map_resolver_reply)     \
+_(LISP_GPE_ENABLE_DISABLE_REPLY, lisp_gpe_enable_disable_reply)         \
 _(LISP_GPE_ADD_DEL_IFACE_REPLY, lisp_gpe_add_del_iface_reply)           \
 _(LISP_LOCATOR_SET_DETAILS, lisp_locator_set_details)                   \
 _(LISP_LOCAL_EID_TABLE_DETAILS, lisp_local_eid_table_details)           \
@@ -7862,8 +7862,6 @@ static uword unformat_lisp_gpe_decap_next (unformat_input_t * input,
         *result = LISP_GPE_INPUT_NEXT_IP6_INPUT;
     else if (unformat (input, "ethernet"))
         *result = LISP_GPE_INPUT_NEXT_IP6_INPUT;
-    else if (unformat (input, "lisp-gpe"))
-        *result = LISP_GPE_INPUT_NEXT_LISP_GPE_ENCAP;
     else if (unformat (input, "%d", &tmp))
         *result = tmp;
     else
@@ -9747,6 +9745,47 @@ api_lisp_add_del_map_resolver(vat_main_t * vam)
     return 0;
 }
 
+static int
+api_lisp_gpe_enable_disable (vat_main_t * vam)
+{
+  unformat_input_t * input = vam->input;
+  vl_api_lisp_gpe_enable_disable_t *mp;
+  f64 timeout = ~0;
+  u8 is_set = 0;
+  u8 is_en = 1;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+      if (unformat(input, "enable")) {
+          is_set = 1;
+          is_en = 1;
+      } else if (unformat(input, "disable")) {
+          is_set = 1;
+          is_en = 0;
+      } else
+          break;
+  }
+
+  if (is_set == 0) {
+      errmsg("Value not set\n");
+      return -99;
+  }
+
+  /* Construct the API message */
+  M(LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable);
+
+  mp->is_en = is_en;
+
+  /* send it... */
+  S;
+
+  /* Wait for a reply... */
+  W;
+
+  /* NOTREACHED */
+  return 0;
+}
+
 static int
 api_lisp_gpe_add_del_iface(vat_main_t * vam)
 {
@@ -9754,7 +9793,8 @@ api_lisp_gpe_add_del_iface(vat_main_t * vam)
     vl_api_lisp_gpe_add_del_iface_t *mp;
     f64 timeout = ~0;
     u8 is_set = 0;
-    u8  is_add = 1;
+    u8 is_add = 1;
+    u32 table_id, vni;
 
     /* Parse args required to build the message */
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
@@ -9764,6 +9804,10 @@ api_lisp_gpe_add_del_iface(vat_main_t * vam)
         } else if (unformat(input, "down")) {
             is_set = 1;
             is_add = 0;
+        } else if (unformat(input, "table_id %d", &table_id)) {
+            ;
+        } else if (unformat(input, "vni %d", &vni)) {
+            ;
         } else
             break;
     }
@@ -9777,6 +9821,8 @@ api_lisp_gpe_add_del_iface(vat_main_t * vam)
     M(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface);
 
     mp->is_add = is_add;
+    mp->table_id = table_id;
+    mp->vni = vni;
 
     /* send it... */
     S;
@@ -10382,6 +10428,7 @@ _(lisp_add_del_local_eid, "<ipv4|ipv6>/<prefix> "                       \
 _(lisp_gpe_add_del_fwd_entry, "eid <ip4|6-addr>/<prefix> "              \
     "sloc <ip4/6-addr> dloc <ip4|6-addr> [del]")                        \
 _(lisp_add_del_map_resolver, "<ip4|6-addr> [del]")                      \
+_(lisp_gpe_enable_disable, "enable|disable")                            \
 _(lisp_gpe_add_del_iface, "up|down")                                    \
 _(lisp_locator_set_dump, "")                                            \
 _(lisp_local_eid_table_dump, "")                                        \
index 4956a43..ea76693 100644 (file)
@@ -321,6 +321,7 @@ _(LISP_ADD_DEL_LOCATOR, lisp_add_del_locator)                           \
 _(LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid)                       \
 _(LISP_GPE_ADD_DEL_FWD_ENTRY, lisp_gpe_add_del_fwd_entry)               \
 _(LISP_ADD_DEL_MAP_RESOLVER, lisp_add_del_map_resolver)                 \
+_(LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable)                     \
 _(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface)                       \
 _(LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump)                         \
 _(LISP_LOCAL_EID_TABLE_DUMP, lisp_local_eid_table_dump)                 \
@@ -4465,7 +4466,7 @@ vl_api_lisp_gpe_add_del_tunnel_t_handler
     a->ver_res = mp->ver_res;
     a->res = mp->res;
     a->next_protocol = mp->next_protocol;
-    a->iid = clib_net_to_host_u32 (mp->iid);
+    a->vni = clib_net_to_host_u32 (mp->iid);
 
     rv = vnet_lisp_gpe_add_del_tunnel (a, &sw_if_index);
     
@@ -4580,7 +4581,7 @@ vl_api_lisp_add_del_local_eid_t_handler(
     a->locator_set_index = locator_set_index;
     a->local = 1;
 
-    rv = vnet_lisp_add_del_mapping(a, &map_index);
+    rv = vnet_lisp_add_del_local_mapping(a, &map_index);
 
 out:
     vec_free(name);
@@ -4683,6 +4684,20 @@ vl_api_lisp_add_del_map_resolver_t_handler(
     REPLY_MACRO(VL_API_LISP_ADD_DEL_MAP_RESOLVER_REPLY);
 }
 
+static void
+vl_api_lisp_gpe_enable_disable_t_handler(
+    vl_api_lisp_gpe_enable_disable_t *mp)
+{
+    vl_api_lisp_gpe_enable_disable_reply_t *rmp;
+    int rv = 0;
+    vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
+
+    a->is_en = mp->is_en;
+    vnet_lisp_gpe_enable_disable (a);
+
+    REPLY_MACRO(VL_API_LISP_GPE_ENABLE_DISABLE_REPLY);
+}
+
 static void
 vl_api_lisp_gpe_add_del_iface_t_handler(
     vl_api_lisp_gpe_add_del_iface_t *mp)
@@ -4692,6 +4707,8 @@ vl_api_lisp_gpe_add_del_iface_t_handler(
     vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
 
     a->is_add = mp->is_add;
+    a->table_id = mp->table_id;
+    a->vni = mp->vni;
     vnet_lisp_gpe_add_del_iface (a, 0);
 
     REPLY_MACRO(VL_API_LISP_GPE_ADD_DEL_IFACE_REPLY);
@@ -4837,7 +4854,7 @@ send_lisp_gpe_tunnel_details (lisp_gpe_tunnel_t *tunnel,
     rmp->flags = tunnel->flags;
     rmp->ver_res = tunnel->ver_res;
     rmp->res = tunnel->res;
-    rmp->iid = htonl(tunnel->iid);
+    rmp->iid = htonl(tunnel->vni);
 
     vl_msg_api_send_shmem (q, (u8 *)&rmp);
 }
index f255fda..afad1c2 100644 (file)
@@ -2239,6 +2239,26 @@ define lisp_add_del_map_resolver_reply {
     i32 retval;
 };
 
+/** \brief enable or disable lisp-gpe protocol
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_en - enable protocol if non-zero, else disable
+*/
+define lisp_gpe_enable_disable {
+    u32 client_index;
+    u32 context;
+    u8  is_en;
+};
+
+/** \brief Reply for gpe enable/disable
+    @param context - returned sender context, to match reply w/ request
+    @param retval - return code
+*/
+define lisp_gpe_enable_disable_reply {
+    u32 context;
+    i32 retval;
+};
+
 /** \brief add or delete gpe_iface
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -2248,6 +2268,8 @@ define lisp_gpe_add_del_iface {
     u32 client_index;
     u32 context;
     u8  is_add;
+    u32 table_id;
+    u32 vni;
 };
 
 /** \brief Reply for gpe_iface add/del