policer: add counters

Add counters to the policer against each of the 3 possible results:
conform, exceed and violate.

Type: improvement
Signed-off-by: Brian Russell <brian@graphiant.com>
Change-Id: Ia98a2f5655df6873259197d6bbf0ff2709b7d60e
diff --git a/src/vnet/policer/police.h b/src/vnet/policer/police.h
index 1005a62..d135e43 100644
--- a/src/vnet/policer/police.h
+++ b/src/vnet/policer/police.h
@@ -22,6 +22,8 @@
   POLICE_VIOLATE = 2,
 } policer_result_e;
 
+#define NUM_POLICE_RESULTS 3
+
 // This is the hardware representation of the policer.
 // To be multithread-safe, the policer is accessed through a spin-lock
 // on the lock field. (For a policer update operation, 24B needs to be
diff --git a/src/vnet/policer/police_inlines.h b/src/vnet/policer/police_inlines.h
index afcc772..0ed9730 100644
--- a/src/vnet/policer/police_inlines.h
+++ b/src/vnet/policer/police_inlines.h
@@ -68,10 +68,16 @@
   policer_read_response_type_st *pol;
   vnet_policer_main_t *pm = &vnet_policer_main;
 
+  /* Speculative prefetch assuming a conform result */
+  vlib_prefetch_combined_counter (&policer_counters[POLICE_CONFORM],
+				  vm->thread_index, policer_index);
+
   len = vlib_buffer_length_in_chain (vm, b);
   pol = &pm->policers[policer_index];
   col = vnet_police_packet (pol, len, packet_color, time_in_policer_periods);
   act = pol->action[col];
+  vlib_increment_combined_counter (&policer_counters[col], vm->thread_index,
+				   policer_index, 1, len);
   if (PREDICT_TRUE (act == SSE2_QOS_ACTION_MARK_AND_TRANSMIT))
     vnet_policer_mark (b, pol->mark_dscp[col]);
 
diff --git a/src/vnet/policer/policer.c b/src/vnet/policer/policer.c
index 80fa1e6..fbb3055 100644
--- a/src/vnet/policer/policer.c
+++ b/src/vnet/policer/policer.c
@@ -32,6 +32,21 @@
   return s;
 }
 
+vlib_combined_counter_main_t policer_counters[] = {
+  {
+    .name = "Policer-Conform",
+    .stat_segment_name = "/net/policer/conform",
+  },
+  {
+    .name = "Policer-Exceed",
+    .stat_segment_name = "/net/policer/exceed",
+  },
+  {
+    .name = "Policer-Violate",
+    .stat_segment_name = "/net/policer/violate",
+  },
+};
+
 clib_error_t *
 policer_add_del (vlib_main_t * vm,
 		 u8 * name,
@@ -86,6 +101,7 @@
     {
       policer_read_response_type_st *pp;
       sse2_qos_pol_cfg_params_st *cp;
+      int i;
 
       pool_get (pm->configs, cp);
       pool_get (pm->policer_templates, pp);
@@ -102,6 +118,12 @@
       hash_set_mem (pm->policer_index_by_name, name, pi);
       *policer_index = pi;
       policer->thread_index = ~0;
+
+      for (i = 0; i < NUM_POLICE_RESULTS; i++)
+	{
+	  vlib_validate_combined_counter (&policer_counters[i], pi);
+	  vlib_zero_combined_counter (&policer_counters[i], pi);
+	}
     }
   else
     {
@@ -117,6 +139,15 @@
 {
   policer_read_response_type_st *i
     = va_arg (*va, policer_read_response_type_st *);
+  uword pi = va_arg (*va, uword);
+  int result;
+  vlib_counter_t counts[NUM_POLICE_RESULTS];
+
+  for (result = 0; result < NUM_POLICE_RESULTS; result++)
+    {
+      vlib_get_combined_counter (&policer_counters[result], pi,
+				 &counts[result]);
+    }
 
   s = format (s, "policer at %llx: %s rate, %s color-aware\n",
 	      i, i->single_rate ? "single" : "dual",
@@ -127,6 +158,12 @@
 	      i->current_limit,
 	      i->current_bucket, i->extended_limit, i->extended_bucket);
   s = format (s, "last update %llu\n", i->last_update_time);
+  s = format (s, "conform %llu packets, %llu bytes\n",
+	      counts[POLICE_CONFORM].packets, counts[POLICE_CONFORM].bytes);
+  s = format (s, "exceed %llu packets, %llu bytes\n",
+	      counts[POLICE_EXCEED].packets, counts[POLICE_EXCEED].bytes);
+  s = format (s, "violate %llu packets, %llu bytes\n",
+	      counts[POLICE_VIOLATE].packets, counts[POLICE_VIOLATE].bytes);
   return s;
 }
 
@@ -496,6 +533,7 @@
   u32 pool_index;
   u8 *match_name = 0;
   u8 *name;
+  uword *pi;
   sse2_qos_pol_cfg_params_st *config;
   policer_read_response_type_st *templ;
 
@@ -507,14 +545,16 @@
     name = (u8 *) p->key;
     if (match_name == 0 || !strcmp((char *) name, (char *) match_name))
       {
-        pool_index = p->value[0];
-        config = pool_elt_at_index (pm->configs, pool_index);
-        templ = pool_elt_at_index (pm->policer_templates, pool_index);
-        vlib_cli_output (vm, "Name \"%s\" %U ",
-                         name, format_policer_config, config);
-        vlib_cli_output (vm, "Template %U",
-                         format_policer_instance, templ);
-        vlib_cli_output (vm, "-----------");
+	pi = hash_get_mem (pm->policer_index_by_name, name);
+
+	pool_index = p->value[0];
+	config = pool_elt_at_index (pm->configs, pool_index);
+	templ = pool_elt_at_index (pm->policer_templates, pool_index);
+	vlib_cli_output (vm, "Name \"%s\" %U ", name, format_policer_config,
+			 config);
+	vlib_cli_output (vm, "Template %U", format_policer_instance, templ,
+			 pi[0]);
+	vlib_cli_output (vm, "-----------");
       }
   }));
   /* *INDENT-ON* */
diff --git a/src/vnet/policer/policer.h b/src/vnet/policer/policer.h
index b7c1d61..2e57e46 100644
--- a/src/vnet/policer/policer.h
+++ b/src/vnet/policer/policer.h
@@ -46,6 +46,8 @@
 
 extern vnet_policer_main_t vnet_policer_main;
 
+extern vlib_combined_counter_main_t policer_counters[];
+
 typedef enum
 {
   VNET_POLICER_INDEX_BY_SW_IF_INDEX,