Add MAC address support to LISP map-cache
[vpp.git] / vnet / vnet / lisp-cp / control.c
index 54a83f4..a820b9c 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);
     }
 
@@ -210,6 +211,7 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
   u8 is_add = 1;
   gid_address_t eid;
   ip_prefix_t * prefp = &gid_address_ippref(&eid);
+  u8 * mac = gid_address_mac(&eid);
   gid_address_t * eids = 0;
   clib_error_t * error = 0;
   u8 * locator_set_name = 0;
@@ -217,9 +219,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,8 +232,16 @@ 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))
         {
+          gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
+          vec_add1(eids, eid);
+        }
+      else if (unformat (line_input, "eid %U", unformat_mac_address, mac))
+        {
+          gid_address_type (&eid) = GID_ADDR_MAC;
           vec_add1(eids, eid);
         }
       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
@@ -251,8 +261,8 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
           goto done;
         }
     }
-
   /* XXX treat batch configuration */
+
   a->deid = eid;
   a->is_add = is_add;
   a->locator_set_index = locator_set_index;
@@ -268,15 +278,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)
@@ -573,6 +667,8 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
   ip_address_t rloc, * rlocs = 0;
   ip_prefix_t * deid_ippref, * seid_ippref;
   gid_address_t seid, deid;
+  u8 * dmac = gid_address_mac (&deid);
+  u8 * smac = gid_address_mac (&seid);
   u8 deid_set = 0, seid_set = 0;
   u8 * s = 0;
   u32 vni, action = ~0;
@@ -587,9 +683,6 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
   seid_ippref = &gid_address_ippref(&seid);
   deid_ippref = &gid_address_ippref(&deid);
 
-  gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
-  gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
-
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (line_input, "del-all"))
@@ -601,16 +694,30 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
       else if (unformat (line_input, "deid %U",
                          unformat_ip_prefix, deid_ippref))
         {
+          gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
+          deid_set = 1;
+        }
+      else if (unformat (line_input, "deid %U",
+                         unformat_mac_address, dmac))
+        {
+          gid_address_type (&deid) = GID_ADDR_MAC;
           deid_set = 1;
         }
       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))
         {
+          gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
+          seid_set = 1;
+        }
+      else if (unformat (line_input, "seid %U",
+                         unformat_mac_address, smac))
+        {
+          gid_address_type (&seid) = GID_ADDR_MAC;
           seid_set = 1;
         }
       else if (unformat (line_input, "rloc %U", unformat_ip_address, &rloc))
@@ -646,18 +753,22 @@ lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
           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 &&
-          (ip_prefix_version (deid_ippref) != ip_prefix_version(seid_ippref)))
+      if (GID_ADDR_IP_PREFIX == gid_address_type (&deid))
         {
-          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 &&
+              (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)
@@ -803,32 +914,74 @@ VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
     .function = lisp_pitr_set_locator_set_command_fn,
 };
 
+
+static u8 *
+format_eid_entry (u8 * s, va_list * args)
+{
+  vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
+  lisp_cp_main_t * lcm = va_arg (*args, lisp_cp_main_t *);
+  gid_address_t * gid = va_arg (*args, gid_address_t *);
+  locator_set_t * ls = va_arg (*args, locator_set_t *);
+  u32 * loc_index;
+  u8 first_line = 1;
+  u8 * loc;
+
+  u8 * type = ls->local ? format(0, "local(%s)", ls->name)
+                        : format(0, "remote");
+
+  if (vec_len (ls->locator_indices) == 0)
+    {
+      s = format (s, "%-35U%-20s", format_gid_address, gid, type);
+    }
+  else
+    {
+      vec_foreach (loc_index, ls->locator_indices)
+        {
+          locator_t * l = pool_elt_at_index (lcm->locator_pool, loc_index[0]);
+          if (l->local)
+            loc = format (0, "%U", format_vnet_sw_if_index_name, vnm,
+                          l->sw_if_index);
+          else
+            loc = format (0, "%U", format_ip_address,
+                          &gid_address_ip (&l->address));
+
+          if (first_line)
+            {
+              s = format (s, "%-35U%-20s%-v\n", format_gid_address,
+                          gid, type, loc);
+              first_line = 0;
+            }
+          else
+            s = format (s, "%55s%v\n", "", loc);
+        }
+    }
+  return s;
+}
+
 static clib_error_t *
-lisp_show_local_eid_table_command_fn (vlib_main_t * vm,
-                                      unformat_input_t * input,
-                                      vlib_cli_command_t * cmd)
+lisp_show_eid_table_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();
   mapping_t * mapit;
 
-  vlib_cli_output (vm, "%=20s%=16s", "EID", "Locator");
+  vlib_cli_output (vm, "%-35s%-20s%-s", "EID", "type", "locators");
   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,
-                     ls->name);
-    vec_free (msg);
+    vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
+                     lcm, &mapit->eid, ls);
   }));
 
   return 0;
 }
 
-VLIB_CLI_COMMAND (lisp_cp_show_local_eid_table_command) = {
+VLIB_CLI_COMMAND (lisp_cp_show_eid_table_command) = {
     .path = "show lisp eid-table",
-    .short_help = "Shows local EID table",
-    .function = lisp_show_local_eid_table_command_fn,
+    .short_help = "Shows EID table",
+    .function = lisp_show_eid_table_command_fn,
 };
 
 /* cleans locator to locator-set data and removes locators not part of
@@ -1294,6 +1447,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 +2061,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 +2235,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 +2291,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 +2318,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 +2367,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 +2881,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 */);