LISP EID virtualization support
[vpp.git] / vnet / vnet / lisp-cp / control.c
index 2a29bd2..8b3d25f 100644 (file)
@@ -47,13 +47,13 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
       if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid,
                                                      &a->deid))
         {
-          clib_warning("eid %U found in the eid-table", format_ip_address,
+          clib_warning ("eid %U found in the eid-table", format_gid_address,
                        &a->deid);
           return VNET_API_ERROR_VALUE_EXIST;
         }
 
       pool_get(lcm->mapping_pool, m);
-      m->eid = a->deid;
+      gid_address_copy (&m->eid, &a->deid);
       m->locator_set_index = a->locator_set_index;
       m->ttl = a->ttl;
       m->action = a->action;
@@ -87,7 +87,7 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
     {
       if (mi == GID_LOOKUP_MISS)
         {
-          clib_warning("eid %U not found in the eid-table", format_ip_address,
+          clib_warning("eid %U not found in the eid-table", format_gid_address,
                        &a->deid);
           return VNET_API_ERROR_INVALID_VALUE;
         }
@@ -123,6 +123,7 @@ vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
 
       /* remove mapping from dictionary */
       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, 0, 0);
+      gid_address_free (&m->eid);
       pool_put_index (lcm->mapping_pool, mi);
     }
 
@@ -139,6 +140,12 @@ vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
   vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
 
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
   vni = gid_address_vni(&a->deid);
 
   /* store/remove mapping from map-cache */
@@ -210,9 +217,10 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
   u32 locator_set_index = 0, map_index = 0;
   uword * p;
   vnet_lisp_add_del_mapping_args_t _a, * a = &_a;
+  int rv = 0;
+  u32 vni = 0;
 
-  gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
-
+  memset (&eid, 0, sizeof (eid));
   /* Get a line of input. */
   if (! unformat_user (input, unformat_line_input, line_input))
     return 0;
@@ -223,6 +231,8 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
         is_add = 1;
       else if (unformat (line_input, "del"))
         is_add = 0;
+      else if (unformat (line_input, "vni %d", &vni))
+        gid_address_vni (&eid) = vni;
       else if (unformat (line_input, "eid %U", unformat_ip_prefix, prefp))
         {
           vec_add1(eids, eid);
@@ -244,27 +254,117 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
           goto done;
         }
     }
-
   /* XXX treat batch configuration */
+
+  gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
   a->deid = eid;
   a->is_add = is_add;
   a->locator_set_index = locator_set_index;
   a->local = 1;
 
-  vnet_lisp_add_del_local_mapping (a, &map_index);
+  rv = vnet_lisp_add_del_local_mapping (a, &map_index);
+  if (0 != rv)
+   {
+      error = clib_error_return(0, "failed to %s eid-table!",
+                                is_add ? "add" : "delete");
+   }
  done:
   vec_free(eids);
   if (locator_set_name)
     vec_free (locator_set_name);
+  gid_address_free (&a->deid);
   return error;
 }
 
 VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = {
     .path = "lisp eid-table",
-    .short_help = "lisp eid-table add/del eid <eid> locator-set <locator-set>",
+    .short_help = "lisp eid-table add/del [vni <vni>] eid <eid> "
+      "locator-set <locator-set>",
     .function = lisp_add_del_local_eid_command_fn,
 };
 
+int
+vnet_lisp_eid_table_map (u32 vni, u32 vrf, u8 is_add)
+{
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+  uword * table_id, * vnip;
+
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return -1;
+    }
+
+  if (vni == 0 || vrf == 0)
+    {
+      clib_warning ("can't add/del default vni-vrf mapping!");
+      return -1;
+    }
+
+  table_id = hash_get (lcm->table_id_by_vni, vni);
+  vnip = hash_get (lcm->vni_by_table_id, vrf);
+
+  if (is_add)
+    {
+      if (table_id || vnip)
+        {
+          clib_warning ("vni %d or vrf %d already used in any vrf/vni "
+                        "mapping!", vni, vrf);
+          return -1;
+        }
+      hash_set (lcm->table_id_by_vni, vni, vrf);
+      hash_set (lcm->vni_by_table_id, vrf, vni);
+    }
+  else
+    {
+      if (!table_id || !vnip)
+        {
+          clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
+                        "mapping!", vni, vrf);
+          return -1;
+        }
+      hash_unset (lcm->table_id_by_vni, vni);
+      hash_unset (lcm->vni_by_table_id, vrf);
+    }
+  return 0;
+}
+
+static clib_error_t *
+lisp_eid_table_map_command_fn (vlib_main_t * vm,
+                               unformat_input_t * input,
+                               vlib_cli_command_t * cmd)
+{
+  u8 is_add = 1;
+  u32 vni = 0, vrf = 0;
+  unformat_input_t _line_input, * line_input = &_line_input;
+
+  /* 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, "del"))
+        is_add = 0;
+      else if (unformat (line_input, "vni %d", &vni))
+        ;
+      else if (unformat (line_input, "vrf %d", &vrf))
+        ;
+      else
+        {
+          return unformat_parse_error (line_input);
+        }
+    }
+  vnet_lisp_eid_table_map (vni, vrf, is_add);
+  return 0;
+}
+
+VLIB_CLI_COMMAND (lisp_eid_table_map_command) = {
+    .path = "lisp eid-table map",
+    .short_help = "lisp eid-table map [del] vni <vni> vrf <vrf>",
+    .function = lisp_eid_table_map_command_fn,
+};
+
 static int
 lisp_add_del_negative_static_mapping (gid_address_t * deid,
     vnet_lisp_add_del_locator_set_args_t * ls, u8 action, u8 is_add)
@@ -366,11 +466,13 @@ lisp_add_del_negative_static_mapping (gid_address_t * deid,
  * @param rlocs vector of remote locators
  * @param action action for negative map-reply
  * @param is_add add mapping if non-zero, delete otherwise
+ * @param del_all if set, delete all remote mappings
  * @return return code
  */
 int
 vnet_lisp_add_del_remote_mapping (gid_address_t * deid, gid_address_t * seid,
-                                  ip_address_t * rlocs, u8 action, u8 is_add)
+                                  ip_address_t * rlocs, u8 action, u8 is_add,
+                                  u8 del_all)
 {
   vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
   vnet_lisp_add_del_mapping_args_t _sm_args, * sm_args = &_sm_args;
@@ -381,6 +483,15 @@ vnet_lisp_add_del_remote_mapping (gid_address_t * deid, gid_address_t * seid,
   ip_address_t * dl;
   int rc = -1;
 
+  if (vnet_lisp_enable_disable_status() == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
+  if (del_all)
+    return vnet_lisp_clear_all_remote_mappings ();
+
   memset (sm_args, 0, sizeof (sm_args[0]));
   memset (dm_args, 0, sizeof (dm_args[0]));
   memset (ls, 0, sizeof (ls[0]));
@@ -487,6 +598,50 @@ done:
   return rc;
 }
 
+int
+vnet_lisp_clear_all_remote_mappings (void)
+{
+  int rv = 0;
+  u32 mi, * map_indices = 0, * map_indexp;
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+  vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
+  vnet_lisp_add_del_locator_set_args_t _ls, * ls = &_ls;
+
+  pool_foreach_index (mi, lcm->mapping_pool,
+    ({
+      vec_add1 (map_indices, mi);
+    }));
+
+  vec_foreach (map_indexp, map_indices)
+    {
+      mapping_t * map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
+      if (!map->local)
+        {
+          del_fwd_entry (lcm, 0, map_indexp[0]);
+
+          dm_args->is_add = 0;
+          gid_address_copy (&dm_args->deid, &map->eid);
+          dm_args->locator_set_index = map->locator_set_index;
+
+          /* delete mapping associated to fwd entry */
+          vnet_lisp_add_del_mapping (dm_args, 0);
+
+          ls->is_add = 0;
+          ls->local = 0;
+          ls->index = map->locator_set_index;
+          /* delete locator set */
+          rv = vnet_lisp_add_del_locator_set (ls, 0);
+          if (rv != 0)
+            goto cleanup;
+        }
+    }
+
+cleanup:
+  if (map_indices)
+    vec_free (map_indices);
+  return rv;
+}
+
 /**
  * Handler for add/del remote mapping CLI.
  *
@@ -502,11 +657,11 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
 {
   clib_error_t * error = 0;
   unformat_input_t _line_input, * line_input = &_line_input;
-  u8 is_add = 1;
+  u8 is_add = 1, del_all = 0;
   ip_address_t rloc, * rlocs = 0;
   ip_prefix_t * deid_ippref, * seid_ippref;
   gid_address_t seid, deid;
-  u8 deid_set = 0;
+  u8 deid_set = 0, seid_set = 0;
   u8 * s = 0;
   u32 vni, action = ~0;
 
@@ -525,9 +680,11 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (line_input, "del"))
+      if (unformat (line_input, "del-all"))
+        del_all = 1;
+      else if (unformat (line_input, "del"))
         is_add = 0;
-      if (unformat (line_input, "add"))
+      else if (unformat (line_input, "add"))
         ;
       else if (unformat (line_input, "deid %U",
                          unformat_ip_prefix, deid_ippref))
@@ -536,12 +693,14 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
         }
       else if (unformat (line_input, "vni %u", &vni))
         {
-          gid_address_set_vni (&seid, vni);
-          gid_address_set_vni (&deid, vni);
+          gid_address_vni (&seid) = vni;
+          gid_address_vni (&deid) = vni;
         }
       else if (unformat (line_input, "seid %U",
                          unformat_ip_prefix, seid_ippref))
-        ;
+        {
+          seid_set = 1;
+        }
       else if (unformat (line_input, "rloc %U", unformat_ip_address, &rloc))
         vec_add1 (rlocs, rloc);
       else if (unformat (line_input, "action %s", &s))
@@ -567,30 +726,38 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
         }
     }
 
-  if (!deid_set)
+  if (!del_all)
     {
-      clib_warning ("missing deid!");
-      goto done;
-    }
+      if (!deid_set)
+        {
+          clib_warning ("missing deid!");
+          goto done;
+        }
 
-  if (is_add
-      && (ip_prefix_version (deid_ippref)
-        != ip_prefix_version (seid_ippref)))
-    {
-      clib_warning ("source and destination EIDs are not"
-                    " in the same IP family!");
-      goto done;
-    }
+      /* if seid not set, make sure the ip version is the same as that of the
+       * deid. This ensures the seid to be configured will be either 0/0 or
+       * ::/0 */
+      if (!seid_set)
+        ip_prefix_version(seid_ippref) = ip_prefix_version(deid_ippref);
 
-  if (is_add && (~0 == action)
-      && 0 == vec_len (rlocs))
-    {
-      clib_warning ("no action set for negative map-reply!");
-      goto done;
+      if (is_add &&
+          (ip_prefix_version (deid_ippref) != ip_prefix_version(seid_ippref)))
+        {
+          clib_warning ("source and destination EIDs are not"
+                        " in the same IP family!");
+          goto done;
+        }
+
+      if (is_add && (~0 == action)
+          && 0 == vec_len (rlocs))
+        {
+          clib_warning ("no action set for negative map-reply!");
+          goto done;
+        }
     }
 
   int rv = vnet_lisp_add_del_remote_mapping (&deid, &seid, rlocs,
-                                             action, is_add);
+                                             action, is_add, del_all);
   if (rv)
     clib_warning ("failed to %s remote mapping!",
                   is_add ? "add" : "delete");
@@ -604,7 +771,7 @@ done:
 
 VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) = {
     .path = "lisp remote-mapping",
-    .short_help = "lisp remote-mapping add|del vni <vni>"
+    .short_help = "lisp remote-mapping add|del [del-all] vni <vni>"
      "deid <dest-eid> seid <src-eid> [action <no-action|natively-forward|"
      "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
     .function = lisp_add_del_remote_mapping_command_fn,
@@ -639,6 +806,12 @@ vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
   mapping_t * m;
   uword * p;
 
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
   p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
   if (!p)
     {
@@ -677,6 +850,8 @@ lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
   u8 * locator_set_name = 0;
   u8 is_add = 1;
   unformat_input_t _line_input, * line_input = &_line_input;
+  clib_error_t * error = 0;
+  int rv = 0;
 
   /* Get a line of input. */
   if (! unformat_user (input, unformat_line_input, line_input))
@@ -697,12 +872,17 @@ lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
       clib_warning ("No locator set specified!");
       goto done;
     }
-  vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
+  rv = vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
+  if (0 != rv)
+    {
+      error = clib_error_return(0, "failed to %s pitr!",
+                                is_add ? "add" : "delete");
+    }
 
 done:
   if (locator_set_name)
     vec_free (locator_set_name);
-  return 0;
+  return error;
 }
 
 VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
@@ -719,13 +899,13 @@ lisp_show_local_eid_table_command_fn (vlib_main_t * vm,
   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
   mapping_t * mapit;
 
-  vlib_cli_output (vm, "%=20s%=16s", "EID", "Locator");
+  vlib_cli_output (vm, "%=30s%=16s", "EID", "Locator");
   pool_foreach (mapit, lcm->mapping_pool,
   ({
     u8 * msg = 0;
     locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
                                             mapit->locator_set_index);
-    vlib_cli_output (vm, "%-16U%16v", format_gid_address, &mapit->eid,
+    vlib_cli_output (vm, "%-30U%16v", format_gid_address, &mapit->eid,
                      ls->name);
     vec_free (msg);
   }));
@@ -780,24 +960,182 @@ clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
     }
 }
 
+static inline
+uword *get_locator_set_index(vnet_lisp_add_del_locator_set_args_t * a,
+                             uword * p)
+{
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+
+  ASSERT(a != NULL);
+  ASSERT(p != NULL);
+
+  /* find locator-set */
+  if (a->local)
+    {
+      p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
+    }
+  else
+    {
+      *p = a->index;
+    }
+
+  return p;
+}
+
+static inline
+int is_locator_in_locator_set(lisp_cp_main_t * lcm, locator_set_t * ls,
+                              locator_t * loc)
+{
+  locator_t * itloc;
+  u32 * locit;
+
+  ASSERT(ls != NULL);
+  ASSERT(loc != NULL);
+
+  vec_foreach(locit, ls->locator_indices)
+    {
+      itloc = pool_elt_at_index(lcm->locator_pool, locit[0]);
+      if (itloc->sw_if_index == loc->sw_if_index ||
+          !gid_address_cmp(&itloc->address, &loc->address))
+        {
+          clib_warning("Duplicate locator");
+          return VNET_API_ERROR_VALUE_EXIST;
+        }
+    }
+
+  return 0;
+}
+
+static inline
+void remove_locator_from_locator_set(locator_set_t * ls, u32 * locit,
+                                     u32 ls_index, u32 loc_id)
+{
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+  u32 ** ls_indexes = NULL;
+
+  ASSERT(ls != NULL);
+  ASSERT(locit != NULL);
+
+  ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
+                                locit[0]);
+  pool_put_index(lcm->locator_pool, locit[0]);
+  vec_del1(ls->locator_indices, loc_id);
+  vec_del1(ls_indexes[0], ls_index);
+}
+
+int
+vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
+                           locator_set_t * ls, u32 * ls_result)
+{
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+  locator_t * loc = NULL, *itloc = NULL;
+  uword _p = (u32)~0, * p = &_p;
+  u32 loc_index = ~0, ls_index = ~0, * locit = NULL, ** ls_indexes = NULL;
+  u32 loc_id = ~0;
+  int ret = 0;
+
+  ASSERT(a != NULL);
+
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
+  p = get_locator_set_index(a, p);
+  if (!p)
+    {
+      clib_warning("locator-set %v doesn't exist", a->name);
+      return VNET_API_ERROR_INVALID_ARGUMENT;
+    }
+
+  if (ls == 0)
+    {
+      ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
+      if (!ls)
+        {
+          clib_warning("locator-set %d to be overwritten doesn't exist!",
+                       p[0]);
+          return VNET_API_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+  if (a->is_add)
+    {
+
+        if (ls_result)
+          ls_result[0] = p[0];
+
+        /* allocate locators */
+        vec_foreach (itloc, a->locators)
+          {
+            ret = is_locator_in_locator_set(lcm, ls, itloc);
+            if (0 != ret)
+              {
+                return ret;
+              }
+
+            pool_get(lcm->locator_pool, loc);
+            loc[0] = itloc[0];
+            loc_index = loc - lcm->locator_pool;
+
+            vec_add1(ls->locator_indices, loc_index);
+
+            vec_validate (lcm->locator_to_locator_sets, loc_index);
+            ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
+                                          loc_index);
+            vec_add1(ls_indexes[0], ls_index);
+          }
+      }
+    else
+      {
+        ls_index = p[0];
+
+        itloc = a->locators;
+        loc_id = 0;
+        vec_foreach (locit, ls->locator_indices)
+          {
+            loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
+
+            if (loc->local && loc->sw_if_index == itloc->sw_if_index)
+              {
+                remove_locator_from_locator_set(ls, locit,
+                                                ls_index, loc_id);
+              }
+            if (0 == loc->local &&
+                !gid_address_cmp(&loc->address, &itloc->address))
+              {
+                remove_locator_from_locator_set(ls, locit,
+                                                ls_index, loc_id);
+              }
+
+            loc_id++;
+          }
+      }
+
+  return 0;
+}
+
 int
 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
                                u32 * ls_result)
 {
   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
   locator_set_t * ls;
-  locator_t * loc, * itloc;
   uword _p = (u32)~0, * p = &_p;
-  u32 loc_index, ls_index, ** ls_indexes;
-  u32 **eid_indexes;
+  u32 ls_index;
+  u32 ** eid_indexes;
+  int ret = 0;
+
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
 
   if (a->is_add)
     {
-      /* check if overwrite */
-      if (a->local)
-        p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
-      else
-        *p = a->index;
+      p = get_locator_set_index(a, p);
 
       /* overwrite */
       if (p && p[0] != (u32)~0)
@@ -826,6 +1164,7 @@ vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
       else
         {
           pool_get(lcm->locator_set_pool, ls);
+          memset(ls, 0, sizeof(*ls));
           ls_index = ls - lcm->locator_set_pool;
 
           if (a->local)
@@ -845,35 +1184,20 @@ vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
             ls_result[0] = ls_index;
         }
 
-      /* allocate locators */
-      vec_foreach (itloc, a->locators)
+      ret = vnet_lisp_add_del_locator(a, ls, NULL);
+      if (0 != ret)
         {
-          pool_get(lcm->locator_pool, loc);
-          loc[0] = itloc[0];
-          loc_index = loc - lcm->locator_pool;
-
-          vec_add1(ls->locator_indices, loc_index);
-
-          vec_validate (lcm->locator_to_locator_sets, loc_index);
-          ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
-                                        loc_index);
-          vec_add1(ls_indexes[0], ls_index);
+          return ret;
         }
     }
   else
     {
-      /* find locator-set */
-      if (a->local)
+      p = get_locator_set_index(a, p);
+      if (!p)
         {
-          p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
-          if (!p)
-            {
-              clib_warning("locator-set %v doesn't exists", a->name);
-              return -1;
-            }
+          clib_warning("locator-set %v doesn't exists", a->name);
+          return -1;
         }
-      else
-        *p = a->index;
 
       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
       if (!ls)
@@ -881,12 +1205,13 @@ vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
           clib_warning("locator-set with index %d doesn't exists", p[0]);
           return -1;
         }
-//      /* XXX what happens when a mapping is configured to use the loc-set ? */
-//      if (vec_len (vec_elt_at_index(lcm->locator_set_to_eids, p[0])) != 0)
-//        {
-//          clib_warning ("Can't delete a locator that supports a mapping!");
-//          return -1;
-//        }
+
+      if (lcm->mreq_itr_rlocs == p[0])
+        {
+          clib_warning ("Can't delete the locator-set used to constrain "
+                        "the itr-rlocs in map-requests!");
+          return -1;
+        }
 
       if (vec_len(lcm->locator_set_to_eids) != 0)
       {
@@ -915,244 +1240,31 @@ vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
               }
           }
           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
-          vec_free(ls->name);
         }
+      vec_free(ls->name);
+      vec_free(ls->locator_indices);
       pool_put(lcm->locator_set_pool, ls);
     }
   return 0;
 }
 
-static inline
-uword *vnet_lisp_get_locator(vnet_lisp_add_del_locator_set_args_t * a,
-                             uword *p)
+clib_error_t *
+vnet_lisp_enable_disable (u8 is_enabled)
 {
-  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+  vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
+  uword * table_id, * refc;
+  u32 i;
+  clib_error_t * error = 0;
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+  vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
 
-  ASSERT(a != NULL);
-  ASSERT(p != NULL);
-
-  /* find locator-set */
-  if (a->local)
-  {
-      p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
-  }
-  else
-  {
-      *p = a->index;
-  }
-
-  return p;
-}
-
-int
-vnet_lisp_add_del_locator_set_name (vnet_lisp_add_del_locator_set_args_t * a,
-                                    u32 * ls_result)
-{
-  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
-  locator_set_t * ls;
-  uword _p = (u32)~0, * p = &_p;
-  u32 ls_index = ~0;
-  u32 **eid_indexes = NULL;
-
-  ASSERT(a != NULL);
-  ASSERT(ls_result != NULL);
-
-  p = vnet_lisp_get_locator(a, p);
-
-  if (a->is_add)
-    {
-      /* overwrite */
-      if (p && p[0] != (u32)~0)
-        {
-          ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
-          if (!ls)
-            {
-              clib_warning("locator-set %d to be overwritten doesn't exist!",
-                           p[0]);
-              return VNET_API_ERROR_UNSPECIFIED;
-            }
-
-          /* clean locator to locator-set vectors and remove locators if
-           * they're not part of another locator-set */
-          clean_locator_to_locator_set (lcm, p[0]);
-
-          /* remove locator indices from locator set */
-          vec_free(ls->locator_indices);
-
-          ls_index = p[0];
-
-          if (ls_result)
-            ls_result[0] = p[0];
-        }
-      /* new locator-set */
-      else
-        {
-          pool_get(lcm->locator_set_pool, ls);
-          ls_index = ls - lcm->locator_set_pool;
-
-          if (a->local)
-            {
-              ls->name = vec_dup(a->name);
-
-              if (!lcm->locator_set_index_by_name)
-                lcm->locator_set_index_by_name = hash_create_vec(
-                    /* size */0, sizeof(ls->name[0]), sizeof(uword));
-              hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
-
-              /* mark as local locator-set */
-              vec_add1(lcm->local_locator_set_indexes, ls_index);
-            }
-          ls->local = a->local;
-         ls->locator_indices = NULL;
-          if (ls_result)
-            ls_result[0] = ls_index;
-        }
-    }
-  else
-    {
-       if (!p)
-       {
-           clib_warning("locator-set %v doesn't exists", a->name);
-           return VNET_API_ERROR_INVALID_ARGUMENT;
-       }
-
-       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
-       if (!ls)
-       {
-           clib_warning("locator-set with index %d doesn't exists", p[0]);
-           return VNET_API_ERROR_INVALID_ARGUMENT;
-       }
-
-      if (vec_len(lcm->locator_set_to_eids) != 0)
-      {
-          eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
-          if (vec_len(eid_indexes[0]) != 0)
-          {
-              clib_warning ("Can't delete a locator that supports a mapping!");
-              return -1;
-          }
-      }
-
-      /* clean locator to locator-sets data */
-      clean_locator_to_locator_set (lcm, p[0]);
-
-      if (ls->local)
-        {
-          u32 it, lsi;
-
-          vec_foreach_index(it, lcm->local_locator_set_indexes)
-            {
-              lsi = vec_elt(lcm->local_locator_set_indexes, it);
-              if (lsi == p[0])
-                {
-                  vec_del1(lcm->local_locator_set_indexes, it);
-                  break;
-                }
-            }
-          hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
-          vec_free(ls->name);
-        }
-      pool_put(lcm->locator_set_pool, ls);
-    }
-  return 0;
-}
-
-int
-vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t *a,
-                           u32 *ls_result)
-{
-  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
-  locator_set_t *ls = NULL;
-  locator_t *loc = NULL, *itloc = NULL;
-  uword _p = (u32)~0, * p = &_p;
-  u32 loc_index = ~0, ls_index = ~0, *locit = NULL, **ls_indexes = NULL;
-  u32 i = ~0;
-
-  ASSERT(a != NULL);
-  ASSERT(ls_result != NULL);
-
-  p = vnet_lisp_get_locator(a, p);
-  if (!p) {
-      clib_warning("locator-set %v doesn't exists", a->name);
-      return VNET_API_ERROR_INVALID_ARGUMENT;
-  }
-
-  ls_index = p[0];
-
-  if (a->is_add)
-    {
-        ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
-        if (!ls)
-        {
-            clib_warning("locator-set %d to be overwritten doesn't exist!",
-                         p[0]);
-            return VNET_API_ERROR_INVALID_ARGUMENT;
-        }
-
-        if (ls_result)
-            ls_result[0] = p[0];
-
-      /* allocate locators */
-      itloc = a->locators;
-      pool_get(lcm->locator_pool, loc);
-      loc[0] = itloc[0];
-      loc_index = loc - lcm->locator_pool;
-
-      vec_add1(ls->locator_indices, loc_index);
-
-      vec_validate (lcm->locator_to_locator_sets, loc_index);
-      ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
-                                    loc_index);
-      vec_add1(ls_indexes[0], ls_index);
-    }
-  else
-    {
-      ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
-      if (!ls)
-        {
-          clib_warning("locator-set with index %d doesn't exists", p[0]);
-          return VNET_API_ERROR_INVALID_ARGUMENT;
-        }
-
-      if (ls->local)
-      {
-          itloc = a->locators;
-          i = 0;
-          vec_foreach (locit, ls->locator_indices)
-          {
-              loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
-              if (loc->local && loc->sw_if_index == itloc->sw_if_index)
-              {
-                  ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
-                                                locit[0]);
-                  pool_put_index(lcm->locator_pool, locit[0]);
-                  vec_del1(ls->locator_indices, i);
-                  vec_del1(ls_indexes[0], ls_index);
-              }
-              i++;
-          }
-      }
-    }
-  return 0;
-}
-
-clib_error_t *
-vnet_lisp_enable_disable (u8 is_enabled)
-{
-  vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
-  uword * table_id, * refc;
-  u32 i;
-  clib_error_t * error = 0;
-  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
-  vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
-
-  a->is_en = is_enabled;
-  error = vnet_lisp_gpe_enable_disable (a);
-  if (error)
-    {
-      return clib_error_return (0, "failed to %s data-plane!",
-                                a->is_en ? "enable" : "disable");
-    }
+  a->is_en = is_enabled;
+  error = vnet_lisp_gpe_enable_disable (a);
+  if (error)
+    {
+      return clib_error_return (0, "failed to %s data-plane!",
+                                a->is_en ? "enable" : "disable");
+    }
 
   if (is_enabled)
     {
@@ -1270,6 +1382,28 @@ VLIB_CLI_COMMAND (lisp_show_status_command) = {
     .short_help = "show lisp status",
     .function = lisp_show_status_command_fn,
 };
+
+static clib_error_t *
+lisp_show_eid_table_map_command_fn (vlib_main_t * vm, unformat_input_t * input,
+                                    vlib_cli_command_t * cmd)
+{
+  hash_pair_t * p;
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+
+  vlib_cli_output (vm, "%=10s%=10s", "VNI", "VRF");
+  hash_foreach_pair (p, lcm->table_id_by_vni,
+    {
+      vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
+    });
+  return 0;
+}
+
+VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = {
+    .path = "show lisp eid-table map",
+    .short_help = "show lisp eid-table vni to vrf mappings",
+    .function = lisp_show_eid_table_map_command_fn,
+};
+
 static clib_error_t *
 lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
                                      vlib_cli_command_t * cmd)
@@ -1283,6 +1417,7 @@ lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
   locator_t locator, * locators = 0;
   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
   u32 ls_index = 0;
+  int rv = 0;
 
   memset(&locator, 0, sizeof(locator));
   memset(a, 0, sizeof(a[0]));
@@ -1316,7 +1451,12 @@ lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
   a->is_add = is_add;
   a->local = 1;
 
-  vnet_lisp_add_del_locator_set(a, &ls_index);
+  rv = vnet_lisp_add_del_locator_set(a, &ls_index);
+  if (0 != rv)
+    {
+      error = clib_error_return(0, "failed to %s locator-set!",
+                                is_add ? "add" : "delete");
+    }
 
  done:
   vec_free(locators);
@@ -1327,11 +1467,81 @@ 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 <iface-name> "
-        "p <priority> w <weight>",
+    .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
+        "p <priority> w <weight>]",
     .function = lisp_add_del_locator_set_command_fn,
 };
 
+static clib_error_t *
+lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
+                                     vlib_cli_command_t * cmd)
+{
+  lisp_gpe_main_t * lgm = &lisp_gpe_main;
+  vnet_main_t * vnm = lgm->vnet_main;
+  unformat_input_t _line_input, * line_input = &_line_input;
+  u8 is_add = 1;
+  clib_error_t * error = 0;
+  u8 * locator_set_name = 0;
+  u8 locator_set_name_set = 0;
+  locator_t locator, * locators = 0;
+  vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
+  u32 ls_index = 0;
+
+  memset(&locator, 0, sizeof(locator));
+  memset(a, 0, sizeof(a[0]));
+
+  /* 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, "locator-set %_%v%_", &locator_set_name))
+        locator_set_name_set = 1;
+      else if (unformat (line_input, "iface %U p %d w %d",
+                         unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
+                         &locator.priority, &locator.weight))
+        {
+          locator.local = 1;
+          vec_add1(locators, locator);
+        }
+      else
+        {
+          error = unformat_parse_error(line_input);
+          goto done;
+        }
+    }
+
+  if (!locator_set_name_set)
+    {
+      error = clib_error_return(0, "locator_set name not set!");
+      goto done;
+  }
+
+  a->name = locator_set_name;
+  a->locators = locators;
+  a->is_add = is_add;
+  a->local = 1;
+
+  vnet_lisp_add_del_locator(a, 0, &ls_index);
+
+ done:
+  vec_free(locators);
+  vec_free (locator_set_name);
+  return error;
+}
+
+VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
+    .path = "lisp locator",
+    .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
+                  "p <priority> w <weight>",
+    .function = lisp_add_del_locator_in_set_command_fn,
+};
+
 static clib_error_t *
 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
                                       unformat_input_t * input,
@@ -1347,16 +1557,23 @@ lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
   pool_foreach (lsit, lcm->locator_set_pool,
   ({
     u8 * msg = 0;
-    msg = format (msg, "%-16v", lsit->name);
+    int next_line = 0;
+    msg = format (msg, "%=16v", lsit->name);
     vec_foreach (locit, lsit->locator_indices)
       {
+        if (next_line)
+          {
+            msg = format (msg, "%16s", " ");
+          }
         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
         if (loc->local)
-          msg = format (msg, "%16d%16d%16d", loc->sw_if_index, loc->priority,
+          msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
                         loc->weight);
         else
-          msg = format (msg, "%16U%16d%16d", format_gid_address, &loc->address,
-                        loc->priority, loc->weight);
+          msg = format (msg, "%16U%16d%16d\n", format_ip_address,
+                        gid_address_ip(&loc->address), loc->priority,
+                        loc->weight);
+        next_line = 1;
       }
     vlib_cli_output (vm, "%v", msg);
     vec_free (msg);
@@ -1377,6 +1594,12 @@ vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
   ip_address_t * addr;
   u32 i;
 
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
   if (a->is_add)
     {
       vec_foreach(addr, lcm->map_resolvers)
@@ -1414,6 +1637,7 @@ lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
   u8 is_add = 1;
   ip_address_t ip_addr;
   clib_error_t * error = 0;
+  int rv = 0;
   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
 
   /* Get a line of input. */
@@ -1436,7 +1660,12 @@ lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
     }
   a->is_add = is_add;
   a->address = ip_addr;
-  vnet_lisp_add_del_map_resolver (a);
+  rv = vnet_lisp_add_del_map_resolver (a);
+  if (0 != rv)
+    {
+      error = clib_error_return(0, "failed to %s map-resolver!",
+                                is_add ? "add" : "delete");
+    }
 
  done:
   return error;
@@ -1448,6 +1677,117 @@ VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
     .function = lisp_add_del_map_resolver_command_fn,
 };
 
+int
+vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
+{
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+  uword * p = 0;
+
+  //TODO: Wait for merge https://gerrit.fd.io/r/#/c/1427/
+//   if (vnet_lisp_enable_disable_status () == 0)
+//     {
+//       clib_warning ("LISP is disabled!");
+//       return VNET_API_ERROR_LISP_DISABLED;
+//     }
+
+  if (a->is_add)
+    {
+      p = hash_get_mem(lcm->locator_set_index_by_name, a->locator_set_name);
+      if (!p)
+        {
+          clib_warning("locator-set %v doesn't exist", a->locator_set_name);
+          return VNET_API_ERROR_INVALID_ARGUMENT;
+        }
+
+      lcm->mreq_itr_rlocs = p[0];
+    }
+  else
+    {
+      lcm->mreq_itr_rlocs = ~0;
+    }
+
+  return 0;
+}
+
+static clib_error_t *
+lisp_add_del_mreq_itr_rlocs_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;
+  u8 * locator_set_name = 0;
+  clib_error_t * error = 0;
+  int rv = 0;
+  vnet_lisp_add_del_mreq_itr_rloc_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, "del"))
+        is_add = 0;
+      else if (unformat (line_input, "add %s", &locator_set_name))
+        is_add = 1;
+      else
+        {
+          error = unformat_parse_error(line_input);
+          goto done;
+        }
+    }
+
+  a->is_add = is_add;
+  a->locator_set_name = locator_set_name;
+  rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
+  if (0 != rv)
+    {
+      error = clib_error_return(0, "failed to %s map-request itr-rlocs!",
+                                is_add ? "add" : "delete");
+    }
+
+  vec_free(locator_set_name);
+
+ done:
+  return error;
+
+}
+
+VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
+    .path = "lisp map-request itr-rlocs",
+    .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
+    .function = lisp_add_del_mreq_itr_rlocs_command_fn,
+};
+
+static clib_error_t *
+lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
+                                    unformat_input_t * input,
+                                    vlib_cli_command_t * cmd)
+{
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
+  locator_set_t * loc_set;
+
+  vlib_cli_output (vm, "%=20s", "itr-rlocs");
+
+  if (~0 == lcm->mreq_itr_rlocs)
+    {
+      return 0;
+    }
+
+  loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
+
+  vlib_cli_output (vm, "%=20s", loc_set->name);
+
+  return 0;
+}
+
+VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
+    .path = "show lisp map-request itr-rlocs",
+    .short_help = "Shows map-request itr-rlocs",
+    .function = lisp_show_mreq_itr_rlocs_command_fn,
+};
+
 /* Statistics (not really errors) */
 #define foreach_lisp_cp_lookup_error           \
 _(DROP, "drop")                                \
@@ -1494,6 +1834,49 @@ format_lisp_cp_lookup_trace (u8 * s, va_list * args)
   return s;
 }
 
+ip_interface_address_t *
+ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
+                                          u8 loop)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
+  if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
+    sw_if_index = swif->unnumbered_sw_if_index;
+  u32 ia =
+      (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
+          vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
+          (u32) ~0;
+  return pool_elt_at_index((lm)->if_address_pool, ia);
+}
+
+void *
+ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
+                                u8 version)
+{
+  ip_interface_address_t * ia;
+
+  ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
+  if (!ia)
+    return 0;
+  return ip_interface_address_get_address (lm, ia);
+}
+
+int
+ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
+                                   u8 version, ip_address_t * result)
+{
+  ip_lookup_main_t * lm;
+  void * addr;
+
+  lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
+  addr = ip_interface_get_first_address (lm, sw_if_index, version);
+  if (!addr)
+    return 0;
+
+  ip_address_set (result, addr, version);
+  return 1;
+}
+
 static u32
 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
                           ip_address_t * dst)
@@ -1505,104 +1888,105 @@ ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
       return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst));
 }
 
-void
-get_mr_and_local_iface_ip (lisp_cp_main_t *lcm, ip_address_t * mr_ip,
-                            ip_address_t * sloc)
+u32
+ip_fib_get_egress_iface_for_dst_with_lm (lisp_cp_main_t * lcm,
+                                         ip_address_t * dst,
+                                         ip_lookup_main_t * lm)
 {
   u32 adj_index;
   ip_adjacency_t * adj;
-  ip_interface_address_t * ia = 0;
+
+  adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
+  adj = ip_get_adjacency (lm, adj_index);
+
+  if (adj == 0)
+    return ~0;
+
+  /* we only want outgoing routes */
+  if (adj->lookup_next_index != IP_LOOKUP_NEXT_ARP
+      && adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
+    return ~0;
+
+  return adj->rewrite_header.sw_if_index;
+}
+
+/**
+ * Find the sw_if_index of the interface that would be used to egress towards
+ * dst.
+ */
+u32
+ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
+{
   ip_lookup_main_t * lm;
-  ip4_address_t * l4 = 0;
-  ip6_address_t * l6 = 0;
+
+  lm = ip_addr_version (dst) == IP4 ?
+      &lcm->im4->lookup_main : &lcm->im6->lookup_main;
+
+  return ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
+}
+
+/**
+ * Find first IP of the interface that would be used to egress towards dst.
+ * Returns 1 if the address is found 0 otherwise.
+ */
+int
+ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
+                                    ip_address_t * result)
+{
+  u32 si;
+  ip_lookup_main_t * lm;
+  void * addr = 0;
+  u8 ipver;
+
+  ASSERT(result != 0);
+
+  ipver = ip_addr_version(dst);
+
+  lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
+  si = ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
+
+  if ((u32) ~0 == si)
+    return 0;
+
+  /* find the first ip address */
+  addr = ip_interface_get_first_address (lm, si, ipver);
+  if (0 == addr)
+    return 0;
+
+  ip_address_set (result, addr, ipver);
+  return 1;
+}
+
+int
+get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
+                           ip_address_t * sloc)
+{
   ip_address_t * mrit;
 
   if (vec_len(lcm->map_resolvers) == 0)
     {
       clib_warning("No map-resolver configured");
-      return;
+      return 0;
     }
 
   /* find the first mr ip we have a route to and the ip of the
    * iface that has a route to it */
   vec_foreach(mrit, lcm->map_resolvers)
     {
-      lm = ip_addr_version (mrit) == IP4 ?
-          &lcm->im4->lookup_main : &lcm->im6->lookup_main;
-
-      adj_index = ip_fib_lookup_with_table (lcm, 0, mrit);
-      adj = ip_get_adjacency (lm, adj_index);
-
-      if (adj == 0)
-        continue;
-
-      if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
-        {
-          ia = pool_elt_at_index(lm->if_address_pool, adj->if_address_index);
-          if (ip_addr_version(mrit) == IP4)
-            {
-              l4 = ip_interface_address_get_address (lm, ia);
-            }
-          else
-            {
-              l6 = ip_interface_address_get_address (lm, ia);
-            }
-        }
-      else if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
-        {
-          /* find sw_if_index in rewrite header */
-          u32 sw_if_index = adj->rewrite_header.sw_if_index;
-
-          /* find suitable address */
-          if (ip_addr_version(mrit) == IP4)
-            {
-              /* find the first ip address */
-              foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
-                                            sw_if_index, 1 /* unnumbered */,
-              ({
-                l4 = ip_interface_address_get_address (&lcm->im4->lookup_main,
-                                                       ia);
-                break;
-              }));
-            }
-          else
-            {
-              /* find the first ip address */
-              foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
-                                            sw_if_index, 1 /* unnumbered */,
-              ({
-                l6 = ip_interface_address_get_address (&lcm->im6->lookup_main,
-                                                       ia);
-                break;
-              }));
-            }
-        }
-
-      if (l4)
-        {
-          ip_addr_v4(sloc).as_u32 = l4->as_u32;
-          ip_addr_version(sloc) = IP4;
-          ip_address_copy(mr_ip, mrit);
-          return;
-        }
-      else if (l6)
-        {
-          clib_memcpy (&ip_addr_v6(sloc), l6, sizeof(*l6));
-          ip_addr_version(sloc) = IP6;
+      if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, mrit, sloc)) {
           ip_address_copy(mr_ip, mrit);
-          return;
-        }
+          return 1;
+      }
     }
 
   clib_warning("Can't find map-resolver and local interface ip!");
-  return;
+  return 0;
 }
 
 static gid_address_t *
 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
 {
-  ip4_address_t * l4;
-  ip6_address_t * l6;
+  void * addr;
   u32 i;
   locator_t * loc;
   u32 * loc_indexp;
@@ -1612,30 +1996,29 @@ build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
   ip_prefix_t * ippref = &gid_address_ippref (gid);
   ip_address_t * rloc = &ip_prefix_addr (ippref);
 
+  memset (gid, 0, sizeof (gid[0]));
   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
     {
       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
 
-      ip_addr_version(rloc) = IP4;
       /* Add ipv4 locators first TODO sort them */
       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
                                    loc->sw_if_index, 1 /* unnumbered */,
       ({
-       l4 = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
-        ip_addr_v4 (rloc) = l4[0];
+       addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
+       ip_address_set (rloc, addr, IP4);
         ip_prefix_len (ippref) = 32;
         vec_add1 (rlocs, gid[0]);
       }));
 
-      ip_addr_version(rloc) = IP6;
       /* Add ipv6 locators */
       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
                                    loc->sw_if_index, 1 /* unnumbered */,
       ({
-        l6 = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
-        ip_addr_v6 (rloc) = l6[0];
+        addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
+        ip_address_set (rloc, addr, IP6);
         ip_prefix_len (ippref) = 128;
         vec_add1 (rlocs, gid[0]);
       }));
@@ -1680,8 +2063,7 @@ build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
 
   bi_res[0] = bi;
 
-  if (rlocs)
-    vec_free(rlocs);
+  vec_free(rlocs);
   return b;
 }
 
@@ -1698,6 +2080,7 @@ send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
   mapping_t * map;
   pending_map_request_t * pmr;
   ip_address_t mr_ip, sloc;
+  u32 ls_index;
 
   /* get locator-set for seid */
   if (!lcm->lisp_pitr)
@@ -1718,17 +2101,26 @@ send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
                        format_gid_address, seid);
           return;
         }
+      ls_index = map->locator_set_index;
     }
   else
     {
       map_index = lcm->pitr_map_index;
       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
+      ls_index = map->locator_set_index;
+    }
+
+  /* overwrite locator set if map-request itr-rlocs configured */
+  if (~0 != lcm->mreq_itr_rlocs)
+    {
+      ls_index = lcm->mreq_itr_rlocs;
     }
 
-  loc_set = pool_elt_at_index (lcm->locator_set_pool, map->locator_set_index);
+  loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
 
-  /* get local iface ip to use in map-request XXX fib 0 for now*/
-  get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc);
+  /* get local iface ip to use in map-request */
+  if (0 == get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc))
+    return;
 
   /* build the encapsulated map request */
   b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, &mr_ip,
@@ -1767,21 +2159,54 @@ get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
 
   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
     {
-      ip_addr_v4(src).as_u32 = ip4->src_address.as_u32;
-      ip_addr_version(src) = IP4;
-      ip_addr_v4(dst).as_u32 = ip4->dst_address.as_u32;
-      ip_addr_version(dst) = IP4;
+      ip_address_set(src, &ip4->src_address, IP4);
+      ip_address_set(dst, &ip4->dst_address, IP4);
     }
   else
     {
       ip6 = hdr;
-      clib_memcpy (&ip_addr_v6(src), &ip6->src_address, sizeof(ip6->src_address));
-      ip_addr_version(src) = IP6;
-      clib_memcpy (&ip_addr_v6(dst), &ip6->dst_address, sizeof(ip6->dst_address));
-      ip_addr_version(dst) = IP6;
+      ip_address_set(src, &ip6->src_address, IP6);
+      ip_address_set(dst, &ip6->dst_address, IP6);
     }
 }
 
+static u32
+lisp_get_vni_from_buffer (vlib_buffer_t * b, u8 version)
+{
+  uword * vnip;
+  u32 vni = ~0, table_id = ~0, fib_index;
+  lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+
+  if (version == IP4)
+    {
+      ip4_fib_t * fib;
+      ip4_main_t * im4 = &ip4_main;
+      fib_index = vec_elt (im4->fib_index_by_sw_if_index,
+                           vnet_buffer (b)->sw_if_index[VLIB_RX]);
+      fib = find_ip4_fib_by_table_index_or_id (im4, fib_index,
+                                               IP4_ROUTE_FLAG_FIB_INDEX);
+      table_id = fib->table_id;
+    }
+  else
+    {
+      ip6_fib_t * fib;
+      ip6_main_t * im6 = &ip6_main;
+      fib_index = vec_elt (im6->fib_index_by_sw_if_index,
+                           vnet_buffer (b)->sw_if_index[VLIB_RX]);
+      fib = find_ip6_fib_by_table_index_or_id (im6, fib_index,
+                                               IP6_ROUTE_FLAG_FIB_INDEX);
+      table_id = fib->table_id;
+    }
+
+  vnip = hash_get (lcm->vni_by_table_id, table_id);
+  if (vnip)
+    vni = vnip[0];
+  else
+    clib_warning ("vrf %d is not mapped to any vni!", table_id);
+
+  return vni;
+}
+
 static uword
 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
               vlib_frame_t * from_frame)
@@ -1801,7 +2226,7 @@ lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
 
       while (n_left_from > 0 && n_left_to_next_drop > 0)
         {
-          u32 pi0;
+          u32 pi0, vni;
           vlib_buffer_t * p0;
           ip4_header_t * ip0;
           gid_address_t src, dst;
@@ -1828,6 +2253,10 @@ lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
           ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
           ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
 
+          vni = lisp_get_vni_from_buffer (p0, ip_prefix_version (spref));
+          gid_address_vni (&dst) = vni;
+          gid_address_vni (&src) = vni;
+
           /* if we have remote mapping for destination already in map-chache
              add forwarding tunnel directly. If not send a map-request */
           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
@@ -1873,6 +2302,8 @@ lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
                                sizeof(ip_address_t));
                 }
             }
+          gid_address_free (&dst);
+          gid_address_free (&src);
         }
 
       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
@@ -1944,30 +2375,6 @@ format_lisp_cp_input_trace (u8 * s, va_list * args)
   return s;
 }
 
-ip_interface_address_t *
-ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
-                                          u8 loop)
-{
-  vnet_main_t *vnm = vnet_get_main ();
-  vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
-  if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
-    sw_if_index = swif->unnumbered_sw_if_index;
-  u32 ia =
-      (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
-          vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
-          (u32) ~0;
-  return pool_elt_at_index((lm)->if_address_pool, ia);
-}
-
-void *
-ip_interface_get_first_ip_addres (ip_lookup_main_t *lm, u32 sw_if_index,
-                                   u8 loop)
-{
-  ip_interface_address_t * ia = ip_interface_get_first_interface_address (
-      lm, sw_if_index, loop);
-  return ip_interface_address_get_address (lm, ia);
-}
-
 static void
 del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
                u32 dst_map_index)
@@ -1998,13 +2405,92 @@ del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
   pool_put(lcm->fwd_entry_pool, fe);
 }
 
+/**
+ * Finds first remote locator with best (lowest) priority that has a local
+ * peer locator with an underlying route to it.
+ *
+ */
+static u32
+get_locator_pair (lisp_cp_main_t* lcm, mapping_t * lcl_map, mapping_t * rmt_map,
+                  ip_address_t * lcl_loc, ip_address_t * rmt_loc)
+{
+  u32 i, minp = ~0, limitp = 0, li, check_index = 0, done = 0, esi;
+  locator_set_t * rmt_ls, * lcl_ls;
+  ip_address_t _lcl, * lcl = &_lcl;
+  locator_t * l, * rmt = 0;
+  uword * checked = 0;
+
+  rmt_ls = pool_elt_at_index(lcm->locator_set_pool, rmt_map->locator_set_index);
+  lcl_ls = pool_elt_at_index(lcm->locator_set_pool, lcl_map->locator_set_index);
+
+  if (!rmt_ls || vec_len(rmt_ls->locator_indices) == 0)
+    return 0;
+
+  while (!done)
+    {
+      /* find unvisited remote locator with best priority */
+      for (i = 0; i < vec_len(rmt_ls->locator_indices); i++)
+        {
+          if (0 != hash_get(checked, i))
+            continue;
+
+          li = vec_elt(rmt_ls->locator_indices, i);
+          l = pool_elt_at_index(lcm->locator_pool, li);
+
+          /* we don't support non-IP locators for now */
+          if (gid_address_type(&l->address) != GID_ADDR_IP_PREFIX)
+            continue;
+
+          if (l->priority < minp && l->priority >= limitp)
+            {
+              minp = l->priority;
+              rmt = l;
+              check_index = i;
+            }
+        }
+      /* check if a local locator with a route to remote locator exists */
+      if (rmt != 0)
+        {
+          esi = ip_fib_get_egress_iface_for_dst (
+              lcm, &gid_address_ip(&rmt->address));
+          if ((u32) ~0 == esi)
+            continue;
+
+          for (i = 0; i < vec_len(lcl_ls->locator_indices); i++)
+            {
+              li = vec_elt (lcl_ls->locator_indices, i);
+              locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
+
+              /* found local locator */
+              if (sl->sw_if_index == esi)
+                {
+                  if (0 == ip_interface_get_first_ip_address (lcm,
+                             sl->sw_if_index,
+                             gid_address_ip_version(&rmt->address), lcl))
+                    continue;
+
+                  ip_address_copy(rmt_loc, &gid_address_ip(&rmt->address));
+                  ip_address_copy(lcl_loc, lcl);
+                  done = 2;
+                }
+            }
+
+          /* skip this remote locator in next searches */
+          limitp = minp;
+          hash_set(checked, check_index, 1);
+        }
+      else
+        done = 1;
+    }
+  hash_free(checked);
+  return (done == 2) ? 1 : 0;
+}
+
 static void
 add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
 {
   mapping_t * src_map, * dst_map;
-  locator_set_t * dst_ls, * src_ls;
-  u32 i, minp = ~0, sw_if_index;
-  locator_t * dl = 0;
+  u32 sw_if_index;
   uword * feip = 0, * tidp;
   fwd_entry_t* fe;
   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
@@ -2030,56 +2516,13 @@ add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
     }
   a->table_id = tidp[0];
 
-  /* XXX simple forwarding policy: first lowest (value) priority locator */
-  dst_ls = pool_elt_at_index (lcm->locator_set_pool,
-                              dst_map->locator_set_index);
-  for (i = 0; i < vec_len (dst_ls->locator_indices); i++)
-    {
-      u32 li = vec_elt (dst_ls->locator_indices, i);
-      locator_t * l = pool_elt_at_index (lcm->locator_pool, li);
-      if (l->priority < minp && gid_address_type(&l->address)
-            == GID_ADDR_IP_PREFIX)
-        {
-          minp = l->priority;
-          dl = l;
-        }
-    }
-  if (dl)
-    {
-      src_ls = pool_elt_at_index(lcm->locator_set_pool,
-                                 src_map->locator_set_index);
-      for (i = 0; i < vec_len(src_ls->locator_indices); i++)
-        {
-          u32 li = vec_elt (src_ls->locator_indices, i);
-          locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
-
-          if (ip_addr_version(&gid_address_ip(&dl->address)) == IP4)
-            {
-              ip4_address_t * l4;
-              l4 = ip_interface_get_first_ip_addres (&lcm->im4->lookup_main,
-                                                     sl->sw_if_index,
-                                                     1 /* unnumbered */);
-              ip_addr_v4(&a->slocator) = *l4;
-              ip_addr_version(&a->slocator) = IP4;
-            }
-          else
-            {
-              ip6_address_t * l6;
-              l6 = ip_interface_get_first_ip_addres (&lcm->im6->lookup_main,
-                                                     sl->sw_if_index,
-                                                     1 /* unnumbered */);
-              ip_addr_v6(&a->slocator) = *l6;
-              ip_addr_version(&a->slocator) = IP6;
-            }
-        }
-    }
-
   /* insert data plane forwarding entry */
   a->is_add = 1;
-  if (dl)
-    a->dlocator = gid_address_ip(&dl->address);
-  else
+
+  /* find best locator pair that 1) verifies LISP policy 2) are connected */
+  if (0 == get_locator_pair (lcm, src_map, dst_map, &a->slocator, &a->dlocator))
     {
+      /* negative entry */
       a->is_negative = 1;
       a->action = dst_map->action;
     }
@@ -2367,11 +2810,13 @@ lisp_cp_init (vlib_main_t *vm)
   lcm->im6 = &ip6_main;
   lcm->vlib_main = vm;
   lcm->vnet_main = vnet_get_main();
+  lcm->mreq_itr_rlocs = ~0;
 
   gid_dictionary_init (&lcm->mapping_index_by_gid);
 
   /* default vrf mapped to vni 0 */
   hash_set(lcm->table_id_by_vni, 0, 0);
+  hash_set(lcm->vni_by_table_id, 0, 0);
 
   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
                          lisp_cp_input_node.index, 1 /* is_ip4 */);