LISP statistics
[vpp.git] / src / vnet / lisp-cp / control.c
index 043d60f..47badeb 100644 (file)
@@ -19,6 +19,7 @@
 #include <vnet/lisp-cp/lisp_msg_serdes.h>
 #include <vnet/lisp-gpe/lisp_gpe_fwd_entry.h>
 #include <vnet/lisp-gpe/lisp_gpe_tenant.h>
+#include <vnet/lisp-gpe/lisp_gpe_tunnel.h>
 #include <vnet/fib/fib_entry.h>
 #include <vnet/fib/fib_table.h>
 
@@ -284,6 +285,7 @@ dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
   if (fe->is_src_dst)
     gid_address_copy (&a->lcl_eid, &fe->leid);
 
+  vnet_lisp_del_fwd_stats (a, feip[0]);
   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
 
   /* delete entry in fwd table */
@@ -432,11 +434,13 @@ static void
 dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
 {
   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
-  mapping_t *src_map, *dst_map;
+  gid_address_t *rmt_eid, *lcl_eid;
+  mapping_t *lcl_map, *rmt_map;
   u32 sw_if_index;
   uword *feip = 0, *dpid;
   fwd_entry_t *fe;
   u8 type, is_src_dst = 0;
+  int rv;
 
   memset (a, 0, sizeof (*a));
 
@@ -445,33 +449,44 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
   if (feip)
     dp_del_fwd_entry (lcm, src_map_index, dst_map_index);
 
+  /*
+   * Determine local mapping and eid
+   */
   if (lcm->lisp_pitr)
-    src_map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
+    lcl_map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
   else
-    src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
-  dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
-
-  /* insert data plane forwarding entry */
+    lcl_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
+  lcl_eid = &lcl_map->eid;
+
+  /*
+   * Determine remote mapping and eid
+   */
+  rmt_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
+  rmt_eid = &rmt_map->eid;
+
+  /*
+   * Build and insert data plane forwarding entry
+   */
   a->is_add = 1;
 
   if (MR_MODE_SRC_DST == lcm->map_request_mode)
     {
-      if (GID_ADDR_SRC_DST == gid_address_type (&dst_map->eid))
+      if (GID_ADDR_SRC_DST == gid_address_type (rmt_eid))
        {
-         gid_address_sd_to_flat (&a->rmt_eid, &dst_map->eid,
-                                 &gid_address_sd_dst (&dst_map->eid));
-         gid_address_sd_to_flat (&a->lcl_eid, &dst_map->eid,
-                                 &gid_address_sd_src (&dst_map->eid));
+         gid_address_sd_to_flat (&a->rmt_eid, rmt_eid,
+                                 &gid_address_sd_dst (rmt_eid));
+         gid_address_sd_to_flat (&a->lcl_eid, rmt_eid,
+                                 &gid_address_sd_src (rmt_eid));
        }
       else
        {
-         gid_address_copy (&a->rmt_eid, &dst_map->eid);
-         gid_address_copy (&a->lcl_eid, &src_map->eid);
+         gid_address_copy (&a->rmt_eid, rmt_eid);
+         gid_address_copy (&a->lcl_eid, lcl_eid);
        }
       is_src_dst = 1;
     }
   else
-    gid_address_copy (&a->rmt_eid, &dst_map->eid);
+    gid_address_copy (&a->rmt_eid, rmt_eid);
 
   a->vni = gid_address_vni (&a->rmt_eid);
 
@@ -499,17 +514,22 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
     }
 
   /* find best locator pair that 1) verifies LISP policy 2) are connected */
-  if (0 == get_locator_pairs (lcm, src_map, dst_map, &a->locator_pairs))
+  rv = get_locator_pairs (lcm, lcl_map, rmt_map, &a->locator_pairs);
+
+  /* Either rmt mapping is negative or we can't find underlay path.
+   * Try again with petr if configured */
+  if (rv == 0 && (lcm->flags & LISP_FLAG_USE_PETR))
     {
-      /* negative entry */
-      a->is_negative = 1;
-      a->action = dst_map->action;
+      rmt_map = lisp_get_petr_mapping (lcm);
+      rv = get_locator_pairs (lcm, lcl_map, rmt_map, &a->locator_pairs);
     }
 
-  /* TODO remove */
-  u8 ipver = ip_prefix_version (&gid_address_ippref (&a->rmt_eid));
-  a->decap_next_index = (ipver == IP4) ?
-    LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
+  /* negative entry */
+  if (rv == 0)
+    {
+      a->is_negative = 1;
+      a->action = rmt_map->action;
+    }
 
   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
 
@@ -521,7 +541,7 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
   if (is_src_dst)
     gid_address_copy (&fe->leid, &a->lcl_eid);
   else
-    gid_address_copy (&fe->leid, &src_map->eid);
+    gid_address_copy (&fe->leid, lcl_eid);
 
   fe->is_src_dst = is_src_dst;
   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
@@ -975,6 +995,20 @@ mapping_delete_timer (lisp_cp_main_t * lcm, u32 mi)
   timing_wheel_delete (&lcm->wheel, mi);
 }
 
+static int
+is_local_ip (lisp_cp_main_t * lcm, ip_address_t * addr)
+{
+  fib_node_index_t fei;
+  fib_prefix_t prefix;
+  fib_entry_flag_t flags;
+
+  ip_address_to_fib_prefix (addr, &prefix);
+
+  fei = fib_table_lookup (0, &prefix);
+  flags = fib_entry_get_flags (fei);
+  return (FIB_ENTRY_FLAG_LOCAL & flags);
+}
+
 /**
  * Adds/removes/updates mapping. Does not program forwarding.
  *
@@ -998,6 +1032,7 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   u32 mi, ls_index = 0, dst_map_index;
   mapping_t *old_map;
+  locator_t *loc;
 
   if (vnet_lisp_enable_disable_status () == 0)
     {
@@ -1018,6 +1053,18 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
 
   if (is_add)
     {
+      /* check if none of the locators match localy configured address */
+      vec_foreach (loc, rlocs)
+      {
+       ip_prefix_t *p = &gid_address_ippref (&loc->address);
+       if (is_local_ip (lcm, &ip_prefix_addr (p)))
+         {
+           clib_warning ("RLOC %U matches a local address!",
+                         format_gid_address, &loc->address);
+           return VNET_API_ERROR_LISP_RLOC_LOCAL;
+         }
+      }
+
       /* overwrite: if mapping already exists, decide if locators should be
        * updated and be done */
       if (old_map && gid_address_cmp (&old_map->eid, eid) == 0)
@@ -1183,15 +1230,11 @@ vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
 
   if (a->is_add)
     {
-      /* TODO 1) check if src/dst 2) once we have src/dst working, use it in
-       * delete*/
-
       /* check if source eid has an associated mapping. If pitr mode is on,
        * just use the pitr's mapping */
       local_mi = lcm->lisp_pitr ? lcm->pitr_map_index :
        gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->leid);
 
-
       if (GID_LOOKUP_MISS == local_mi)
        {
          clib_warning ("Local eid %U not found. Cannot add adjacency!",
@@ -1257,6 +1300,7 @@ vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
       pool_get (lcm->mapping_pool, m);
       m->locator_set_index = locator_set_index;
       m->local = 1;
+      m->pitr_set = 1;
       lcm->pitr_map_index = m - lcm->mapping_pool;
 
       /* enable pitr mode */
@@ -1273,6 +1317,71 @@ vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
   return 0;
 }
 
+/**
+ * Configure Proxy-ETR
+ *
+ * @param ip PETR's IP address
+ * @param is_add Flag that indicates if this is an addition or removal
+ *
+ * return 0 on success
+ */
+int
+vnet_lisp_use_petr (ip_address_t * ip, u8 is_add)
+{
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  u32 ls_index = ~0;
+  mapping_t *m;
+  vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
+  locator_t loc;
+
+  if (vnet_lisp_enable_disable_status () == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
+  memset (ls_args, 0, sizeof (*ls_args));
+
+  if (is_add)
+    {
+      /* Create dummy petr locator-set */
+      memset (&loc, 0, sizeof (loc));
+      gid_address_from_ip (&loc.address, ip);
+      loc.priority = 1;
+      loc.state = loc.weight = 1;
+      loc.local = 0;
+
+      ls_args->is_add = 1;
+      ls_args->index = ~0;
+      vec_add1 (ls_args->locators, loc);
+      vnet_lisp_add_del_locator_set (ls_args, &ls_index);
+
+      /* Add petr mapping */
+      pool_get (lcm->mapping_pool, m);
+      m->locator_set_index = ls_index;
+      lcm->petr_map_index = m - lcm->mapping_pool;
+
+      /* Enable use-petr */
+      lcm->flags |= LISP_FLAG_USE_PETR;
+    }
+  else
+    {
+      m = pool_elt_at_index (lcm->mapping_pool, lcm->petr_map_index);
+
+      /* Remove petr locator */
+      ls_args->is_add = 0;
+      ls_args->index = m->locator_set_index;
+      vnet_lisp_add_del_locator_set (ls_args, 0);
+
+      /* Remove petr mapping */
+      pool_put_index (lcm->mapping_pool, lcm->petr_map_index);
+
+      /* Disable use-petr */
+      lcm->flags &= ~LISP_FLAG_USE_PETR;
+    }
+  return 0;
+}
+
 /* cleans locator to locator-set data and removes locators not part of
  * any locator-set */
 static void
@@ -2205,7 +2314,7 @@ send_rloc_probe (lisp_cp_main_t * lcm, gid_address_t * deid,
 
   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
 
-  next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
+  next_index = (ip_addr_version (rloc) == IP4) ?
     ip4_lookup_node.index : ip6_lookup_node.index;
 
   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
@@ -2544,16 +2653,15 @@ lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
   return vni;
 }
 
-always_inline void
+void
 get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
-                                 gid_address_t * src, gid_address_t * dst)
+                                 gid_address_t * src, gid_address_t * dst,
+                                 u16 type)
 {
   u32 vni = 0;
-  u16 type;
 
   memset (src, 0, sizeof (*src));
   memset (dst, 0, sizeof (*dst));
-  type = vnet_buffer (b)->lisp.overlay_afi;
 
   if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
     {
@@ -2592,6 +2700,11 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
       gid_address_vni (dst) = vni;
       gid_address_vni (src) = vni;
     }
+  else if (LISP_AFI_LCAF == type)
+    {
+      /* Eventually extend this to support NSH and other */
+      ASSERT (0);
+    }
 }
 
 static uword
@@ -2627,10 +2740,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
 
          b0 = vlib_get_buffer (vm, pi0);
          b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
-         vnet_buffer (b0)->lisp.overlay_afi = overlay;
 
          /* src/dst eid pair */
-         get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst);
+         get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay);
 
          /* if we have remote mapping for destination already in map-chache
             add forwarding tunnel directly. If not send a map-request */
@@ -2710,6 +2822,14 @@ lisp_cp_lookup_l2 (vlib_main_t * vm,
   return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC));
 }
 
+static uword
+lisp_cp_lookup_nsh (vlib_main_t * vm,
+                   vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+  /* TODO decide if NSH should be propagated as LCAF or not */
+  return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_LCAF));
+}
+
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
   .function = lisp_cp_lookup_ip4,
@@ -2767,6 +2887,25 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
 };
 /* *INDENT-ON* */
 
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = {
+  .function = lisp_cp_lookup_nsh,
+  .name = "lisp-cp-lookup-nsh",
+  .vector_size = sizeof (u32),
+  .format_trace = format_lisp_cp_lookup_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_errors = LISP_CP_LOOKUP_N_ERROR,
+  .error_strings = lisp_cp_lookup_error_strings,
+
+  .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
+
+  .next_nodes = {
+      [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
 /* lisp_cp_input statistics */
 #define foreach_lisp_cp_input_error                               \
 _(DROP, "drop")                                                   \
@@ -2883,21 +3022,21 @@ process_map_reply (map_records_arg_t * a)
                               m->authoritative, m->ttl,
                               1, 0 /* is_static */ , &dst_map_index);
 
+    if (dst_map_index == (u32) ~ 0)
+      continue;
+
     /* try to program forwarding only if mapping saved or updated */
-    if ((u32) ~ 0 != dst_map_index)
-      {
-       vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
-       memset (adj_args, 0, sizeof (adj_args[0]));
+    vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
+    memset (adj_args, 0, sizeof (adj_args[0]));
 
-       gid_address_copy (&adj_args->leid, &pmr->src);
-       gid_address_copy (&adj_args->reid, &m->eid);
-       adj_args->is_add = 1;
-       if (vnet_lisp_add_del_adjacency (adj_args))
-         clib_warning ("failed to add adjacency!");
+    gid_address_copy (&adj_args->leid, &pmr->src);
+    gid_address_copy (&adj_args->reid, &m->eid);
+    adj_args->is_add = 1;
+    if (vnet_lisp_add_del_adjacency (adj_args))
+      clib_warning ("failed to add adjacency!");
 
-       if ((u32) ~ 0 != m->ttl)
-         mapping_start_expiration_timer (lcm, dst_map_index, m->ttl * 60);
-      }
+    if ((u32) ~ 0 != m->ttl)
+      mapping_start_expiration_timer (lcm, dst_map_index, m->ttl * 60);
   }
 
   /* remove pending map request entry */
@@ -3442,6 +3581,7 @@ lisp_cp_init (vlib_main_t * vm)
   lcm->vnet_main = vnet_get_main ();
   lcm->mreq_itr_rlocs = ~0;
   lcm->lisp_pitr = 0;
+  lcm->flags = 0;
   memset (&lcm->active_map_resolver, 0, sizeof (lcm->active_map_resolver));
 
   gid_dictionary_init (&lcm->mapping_index_by_gid);
@@ -3462,6 +3602,55 @@ lisp_cp_init (vlib_main_t * vm)
   return 0;
 }
 
+static int
+lisp_stats_api_fill (lisp_cp_main_t * lcm, lisp_gpe_main_t * lgm,
+                    lisp_api_stats_t * stat, lisp_stats_key_t * key,
+                    u32 stats_index)
+{
+  lisp_stats_t *s;
+  lisp_gpe_fwd_entry_key_t fwd_key;
+  const lisp_gpe_tunnel_t *lgt;
+  fwd_entry_t *fe;
+
+  memset (stat, 0, sizeof (*stat));
+  memset (&fwd_key, 0, sizeof (fwd_key));
+
+  fe = pool_elt_at_index (lcm->fwd_entry_pool, key->fwd_entry_index);
+  ASSERT (fe != 0);
+
+  gid_to_dp_address (&fe->reid, &stat->deid);
+  gid_to_dp_address (&fe->leid, &stat->seid);
+  stat->vni = gid_address_vni (&fe->reid);
+
+  lgt = lisp_gpe_tunnel_get (key->tunnel_index);
+  stat->loc_rloc = lgt->key->lcl;
+  stat->rmt_rloc = lgt->key->rmt;
+
+  s = pool_elt_at_index (lgm->lisp_stats_pool, stats_index);
+  stat->stats = *s;
+  return 1;
+}
+
+lisp_api_stats_t *
+vnet_lisp_get_stats (void)
+{
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  lisp_api_stats_t *stats = 0, stat;
+  lisp_stats_key_t *key;
+  u32 index;
+
+  /* *INDENT-OFF* */
+  hash_foreach_mem (key, index, lgm->lisp_stats_index_by_key,
+  {
+    if (lisp_stats_api_fill (lcm, lgm, &stat, key, index))
+      vec_add1 (stats, stat);
+  });
+  /* *INDENT-ON* */
+
+  return stats;
+}
+
 static void *
 send_map_request_thread_fn (void *arg)
 {
@@ -3659,6 +3848,33 @@ send_map_resolver_service (vlib_main_t * vm,
   return 0;
 }
 
+vnet_api_error_t
+vnet_lisp_stats_enable_disable (u8 enable)
+{
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+
+  if (vnet_lisp_enable_disable_status () == 0)
+    return VNET_API_ERROR_LISP_DISABLED;
+
+  if (enable)
+    lcm->flags |= LISP_FLAG_STATS_ENABLED;
+  else
+    lcm->flags &= ~LISP_FLAG_STATS_ENABLED;
+
+  return 0;
+}
+
+u8
+vnet_lisp_stats_enable_disable_state (void)
+{
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+
+  if (vnet_lisp_enable_disable_status () == 0)
+    return VNET_API_ERROR_LISP_DISABLED;
+
+  return lcm->flags & LISP_FLAG_STATS_ENABLED;
+}
+
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
     .function = send_map_resolver_service,