LISP EID virtualization support
[vpp.git] / vnet / vnet / lisp-cp / control.c
index 54a83f4..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);
     }
 
@@ -217,9 +218,9 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
   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;
@@ -230,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);
@@ -251,8 +254,9 @@ 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;
@@ -268,15 +272,99 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
   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)
@@ -605,8 +693,8 @@ 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))
@@ -811,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);
   }));
@@ -1294,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)
@@ -1886,6 +1996,7 @@ 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++)
     {
@@ -2059,6 +2170,43 @@ get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
     }
 }
 
+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)
@@ -2078,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;
@@ -2105,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);
@@ -2150,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);
@@ -2662,6 +2816,7 @@ lisp_cp_init (vlib_main_t *vm)
 
   /* 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 */);