LISP: add RLOC and map-notify counters
[vpp.git] / src / vnet / lisp-cp / control.c
index de048a4..3b85036 100644 (file)
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 
+u8 *format_lisp_cp_input_trace (u8 * s, va_list * args);
+
+typedef enum
+{
+  LISP_CP_INPUT_NEXT_DROP,
+  LISP_CP_INPUT_N_NEXT,
+} lisp_cp_input_next_t;
+
 typedef struct
 {
   u8 is_resend;
@@ -512,12 +520,46 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
   pool_get (lcm->fwd_entry_pool, fe);
   fe->locator_pairs = a->locator_pairs;
   gid_address_copy (&fe->reid, &a->rmt_eid);
-  gid_address_copy (&fe->leid, &src_map->eid);
+
+  if (is_src_dst)
+    gid_address_copy (&fe->leid, &a->lcl_eid);
+  else
+    gid_address_copy (&fe->leid, &src_map->eid);
+
   fe->is_src_dst = is_src_dst;
   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
            fe - lcm->fwd_entry_pool);
 }
 
+typedef struct
+{
+  u32 si;
+  u32 di;
+} fwd_entry_mt_arg_t;
+
+static void *
+dp_add_fwd_entry_thread_fn (void *arg)
+{
+  fwd_entry_mt_arg_t *a = arg;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  dp_add_fwd_entry (lcm, a->si, a->di);
+  return 0;
+}
+
+static int
+dp_add_fwd_entry_from_mt (u32 si, u32 di)
+{
+  fwd_entry_mt_arg_t a;
+
+  memset (&a, 0, sizeof (a));
+  a.si = si;
+  a.di = di;
+
+  vl_api_rpc_call_main_thread (dp_add_fwd_entry_thread_fn,
+                              (u8 *) & a, sizeof (a));
+  return 0;
+}
+
 /**
  * Returns vector of adjacencies.
  *
@@ -3487,6 +3529,52 @@ get_egress_map_resolver_ip (lisp_cp_main_t * lcm, ip_address_t * ip)
   return 0;
 }
 
+/* CP output statistics */
+#define foreach_lisp_cp_output_error                  \
+_(MAP_REGISTERS_SENT, "map-registers sent")           \
+_(RLOC_PROBES_SENT, "rloc-probes sent")
+
+static char *lisp_cp_output_error_strings[] = {
+#define _(sym,string) string,
+  foreach_lisp_cp_output_error
+#undef _
+};
+
+typedef enum
+{
+#define _(sym,str) LISP_CP_OUTPUT_ERROR_##sym,
+  foreach_lisp_cp_output_error
+#undef _
+    LISP_CP_OUTPUT_N_ERROR,
+} lisp_cp_output_error_t;
+
+static uword
+lisp_cp_output (vlib_main_t * vm, vlib_node_runtime_t * node,
+               vlib_frame_t * from_frame)
+{
+  return 0;
+}
+
+/* dummy node used only for statistics */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (lisp_cp_output_node) = {
+  .function = lisp_cp_output,
+  .name = "lisp-cp-output",
+  .vector_size = sizeof (u32),
+  .format_trace = format_lisp_cp_input_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_errors = LISP_CP_OUTPUT_N_ERROR,
+  .error_strings = lisp_cp_output_error_strings,
+
+  .n_next_nodes = LISP_CP_INPUT_N_NEXT,
+
+  .next_nodes = {
+      [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
 static int
 send_rloc_probe (lisp_cp_main_t * lcm, gid_address_t * deid,
                 u32 local_locator_set_index, ip_address_t * sloc,
@@ -3532,7 +3620,7 @@ send_rloc_probes (lisp_cp_main_t * lcm)
   mapping_t *lm;
   fwd_entry_t *e;
   locator_pair_t *lp;
-  u32 si;
+  u32 si, rloc_probes_sent = 0;
 
   /* *INDENT-OFF* */
   pool_foreach (e, lcm->fwd_entry_pool,
@@ -3561,17 +3649,21 @@ send_rloc_probes (lisp_cp_main_t * lcm)
         /* get first remote locator */
         send_rloc_probe (lcm, &e->reid, lm->locator_set_index, &lp->lcl_loc,
                          &lp->rmt_loc);
+        rloc_probes_sent++;
       }
   });
   /* *INDENT-ON* */
 
+  vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
+                              LISP_CP_OUTPUT_ERROR_RLOC_PROBES_SENT,
+                              rloc_probes_sent);
   return 0;
 }
 
 static int
 send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
 {
-  u32 bi;
+  u32 bi, map_registers_sent = 0;
   vlib_buffer_t *b;
   ip_address_t sloc;
   vlib_frame_t *f;
@@ -3626,11 +3718,16 @@ send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
     to_next[0] = bi;
     f->n_vectors = 1;
     vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
+    map_registers_sent++;
 
     hash_set (lcm->map_register_messages_by_nonce, nonce, 0);
   }
   free_map_register_records (records);
 
+  vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
+                              LISP_CP_OUTPUT_ERROR_MAP_REGISTERS_SENT,
+                              map_registers_sent);
+
   return 0;
 }
 
@@ -3950,7 +4047,7 @@ lisp_cp_lookup_inline (vlib_main_t * vm,
                                              &src);
                  if (~0 != si)
                    {
-                     dp_add_fwd_entry (lcm, si, di);
+                     dp_add_fwd_entry_from_mt (si, di);
                    }
                }
            }
@@ -4064,8 +4161,11 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
 /* *INDENT-ON* */
 
 /* lisp_cp_input statistics */
-#define foreach_lisp_cp_input_error                     \
-_(DROP, "drop")                                         \
+#define foreach_lisp_cp_input_error                               \
+_(DROP, "drop")                                                   \
+_(RLOC_PROBE_REQ_RECEIVED, "rloc-probe requests received")        \
+_(RLOC_PROBE_REP_RECEIVED, "rloc-probe replies received")         \
+_(MAP_NOTIFIES_RECEIVED, "map-notifies received")                 \
 _(MAP_REPLIES_RECEIVED, "map-replies received")
 
 static char *lisp_cp_input_error_strings[] = {
@@ -4082,12 +4182,6 @@ typedef enum
     LISP_CP_INPUT_N_ERROR,
 } lisp_cp_input_error_t;
 
-typedef enum
-{
-  LISP_CP_INPUT_NEXT_DROP,
-  LISP_CP_INPUT_N_NEXT,
-} lisp_cp_input_next_t;
-
 typedef struct
 {
   gid_address_t dst_eid;
@@ -4457,49 +4551,35 @@ send_map_reply (lisp_cp_main_t * lcm, u32 mi, ip_address_t * dst,
   return 0;
 }
 
+static void
+find_ip_header (vlib_buffer_t * b, u8 ** ip_hdr)
+{
+  const i32 start = vnet_buffer (b)->ip.start_of_ip_header;
+  if (start < 0 && start < -sizeof (b->pre_data))
+    {
+      *ip_hdr = 0;
+      return;
+    }
+
+  *ip_hdr = b->data + start;
+  if ((u8 *) * ip_hdr > (u8 *) vlib_buffer_get_current (b))
+    *ip_hdr = 0;
+}
+
 void
-process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
-                    vlib_buffer_t * b)
+process_map_request (vlib_main_t * vm, vlib_node_runtime_t * node,
+                    lisp_cp_main_t * lcm, vlib_buffer_t * b)
 {
-  u8 *ip_hdr = 0, *udp_hdr;
-  ip4_header_t *ip4;
-  ip6_header_t *ip6;
+  u8 *ip_hdr = 0;
   ip_address_t *dst_loc = 0, probed_loc, src_loc;
   mapping_t m;
   map_request_hdr_t *mreq_hdr;
   gid_address_t src, dst;
   u64 nonce;
-  u32 i, len = 0;
+  u32 i, len = 0, rloc_probe_recv = 0;
   gid_address_t *itr_rlocs = 0;
 
   mreq_hdr = vlib_buffer_get_current (b);
-
-  // TODO ugly workaround to find out whether LISP is carried by ip4 or 6
-  // and needs to be fixed
-  udp_hdr = (u8 *) vlib_buffer_get_current (b) - sizeof (udp_header_t);
-  ip4 = (ip4_header_t *) (udp_hdr - sizeof (ip4_header_t));
-  ip6 = (ip6_header_t *) (udp_hdr - sizeof (ip6_header_t));
-
-  if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
-    ip_hdr = (u8 *) ip4;
-  else
-    {
-      u32 flags = clib_net_to_host_u32
-       (ip6->ip_version_traffic_class_and_flow_label);
-      if ((flags & 0xF0000000) == 0x60000000)
-       ip_hdr = (u8 *) ip6;
-      else
-       {
-         clib_warning ("internal error: cannot determine whether packet "
-                       "is ip4 or 6!");
-         return;
-       }
-    }
-
-  vlib_buffer_pull (b, sizeof (*mreq_hdr));
-
-  nonce = MREQ_NONCE (mreq_hdr);
-
   if (!MREQ_SMR (mreq_hdr) && !MREQ_RLOC_PROBE (mreq_hdr))
     {
       clib_warning
@@ -4507,6 +4587,9 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
       return;
     }
 
+  vlib_buffer_pull (b, sizeof (*mreq_hdr));
+  nonce = MREQ_NONCE (mreq_hdr);
+
   /* parse src eid */
   len = lisp_msg_parse_addr (b, &src);
   if (len == ~0)
@@ -4515,7 +4598,7 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
                                  MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
   if (len == ~0)
-    return;
+    goto done;
 
   /* parse eid records and send SMR-invoked map-requests */
   for (i = 0; i < MREQ_REC_COUNT (mreq_hdr); i++)
@@ -4535,6 +4618,13 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
        }
       else if (MREQ_RLOC_PROBE (mreq_hdr))
        {
+         find_ip_header (b, &ip_hdr);
+         if (!ip_hdr)
+           {
+             clib_warning ("Cannot find the IP header!");
+             goto done;
+           }
+         rloc_probe_recv++;
          memset (&m, 0, sizeof (m));
          u32 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
 
@@ -4553,6 +4643,9 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
     }
 
 done:
+  vlib_node_increment_counter (vm, node->node_index,
+                              LISP_CP_INPUT_ERROR_RLOC_PROBE_REQ_RECEIVED,
+                              rloc_probe_recv);
   vec_free (itr_rlocs);
 }
 
@@ -4602,7 +4695,7 @@ parse_map_reply (vlib_buffer_t * b)
 static void
 queue_map_reply_for_processing (map_records_arg_t * a)
 {
-  vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a));
+  vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (*a));
 }
 
 static void
@@ -4615,7 +4708,8 @@ static uword
 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
               vlib_frame_t * from_frame)
 {
-  u32 n_left_from, *from, *to_next_drop;
+  u32 n_left_from, *from, *to_next_drop, rloc_probe_rep_recv = 0,
+    map_notifies_recv = 0;
   lisp_msg_type_e type;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   map_records_arg_t *a;
@@ -4650,15 +4744,22 @@ lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
            case LISP_MAP_REPLY:
              a = parse_map_reply (b0);
              if (a)
-               queue_map_reply_for_processing (a);
+               {
+                 if (a->is_rloc_probe)
+                   rloc_probe_rep_recv++;
+                 queue_map_reply_for_processing (a);
+               }
              break;
            case LISP_MAP_REQUEST:
-             process_map_request (vm, lcm, b0);
+             process_map_request (vm, node, lcm, b0);
              break;
            case LISP_MAP_NOTIFY:
              a = parse_map_notify (b0);
              if (a)
-               queue_map_notify_for_processing (a);
+               {
+                 map_notifies_recv++;
+                 queue_map_notify_for_processing (a);
+               }
              break;
            default:
              clib_warning ("Unsupported LISP message type %d", type);
@@ -4676,6 +4777,12 @@ lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
                           n_left_to_next_drop);
     }
+  vlib_node_increment_counter (vm, node->node_index,
+                              LISP_CP_INPUT_ERROR_RLOC_PROBE_REP_RECEIVED,
+                              rloc_probe_rep_recv);
+  vlib_node_increment_counter (vm, node->node_index,
+                              LISP_CP_INPUT_ERROR_MAP_NOTIFIES_RECEIVED,
+                              map_notifies_recv);
   return from_frame->n_vectors;
 }