stats: refactor 16/35516/16
authorDamjan Marion <damarion@cisco.com>
Tue, 1 Mar 2022 14:51:18 +0000 (15:51 +0100)
committerDamjan Marion <dmarion@me.com>
Wed, 9 Mar 2022 13:51:31 +0000 (13:51 +0000)
Type: refactor
Change-Id: Ifd533a095d979dc55bfbe5fac7e0b7510a4d900c
Signed-off-by: Damjan Marion <damarion@cisco.com>
36 files changed:
src/plugins/lacp/input.c
src/plugins/lacp/lacp.c
src/plugins/mactime/mactime_top.c
src/plugins/nat/nat44-ed/nat44_ed.c
src/plugins/nat/pnat/tests/pnat_test_stubs.h
src/plugins/prom/prom.c
src/plugins/unittest/counter_test.c
src/vlib/CMakeLists.txt
src/vlib/buffer.c
src/vlib/cli.c
src/vlib/counter.c
src/vlib/error.c
src/vlib/main.c
src/vlib/node_cli.c
src/vlib/stat_weak_inlines.h [deleted file]
src/vlib/stats/cli.c [new file with mode: 0644]
src/vlib/stats/collector.c [new file with mode: 0644]
src/vlib/stats/format.c [new file with mode: 0644]
src/vlib/stats/init.c [new file with mode: 0644]
src/vlib/stats/provider_mem.c [new file with mode: 0644]
src/vlib/stats/shared.h [new file with mode: 0644]
src/vlib/stats/stats.c [new file with mode: 0644]
src/vlib/stats/stats.h [new file with mode: 0644]
src/vlib/threads.c
src/vnet/CMakeLists.txt
src/vnet/bfd/bfd_udp.c
src/vnet/bonding/cli.c
src/vnet/devices/devices.c
src/vnet/interface/stats.c [new file with mode: 0644]
src/vpp-api/client/stat_client.c
src/vpp-api/client/stat_client.h
src/vpp/CMakeLists.txt
src/vpp/stats/stat_segment.c [deleted file]
src/vpp/stats/stat_segment.h [deleted file]
src/vpp/stats/stat_segment_provider.c [deleted file]
src/vpp/stats/stat_segment_shared.h [deleted file]

index ebca2ad..3997af8 100644 (file)
@@ -16,7 +16,7 @@
 #define _GNU_SOURCE
 #include <vnet/bonding/node.h>
 #include <lacp/node.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 
 static int
 lacp_packet_scan (vlib_main_t * vm, member_if_t * mif)
@@ -213,12 +213,12 @@ lacp_input (vlib_main_t * vm, vlib_buffer_t * b0, u32 bi0)
       /* Actually scan the packet */
       e = lacp_packet_scan (vm, mif);
       bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
-      stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
-                                     [mif->sw_if_index].actor_state,
-                                     mif->actor.state);
-      stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
-                                     [mif->sw_if_index].partner_state,
-                                     mif->partner.state);
+      vlib_stats_set_gauge (
+       bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state,
+       mif->actor.state);
+      vlib_stats_set_gauge (
+       bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state,
+       mif->partner.state);
       mif->last_packet_signature_valid = 1;
       mif->last_packet_signature = last_packet_signature;
     }
index 44a32aa..ad77102 100644 (file)
@@ -21,7 +21,7 @@
 #include <vppinfra/hash.h>
 #include <vnet/bonding/node.h>
 #include <lacp/node.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 
 lacp_main_t lacp_main;
 
@@ -173,16 +173,16 @@ lacp_periodic (vlib_main_t * vm)
     if (actor_state != mif->actor.state)
       {
        bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
-       stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
-                                       [mif->sw_if_index].actor_state,
-                                       mif->actor.state);
+       vlib_stats_set_gauge (
+         bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state,
+         mif->actor.state);
       }
     if (partner_state != mif->partner.state)
       {
        bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
-       stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
-                                       [mif->sw_if_index].partner_state,
-                                       mif->partner.state);
+       vlib_stats_set_gauge (
+         bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state,
+         mif->partner.state);
       }
   }
   /* *INDENT-ON* */
@@ -380,12 +380,12 @@ lacp_init_state_machines (vlib_main_t * vm, member_if_t * mif)
   lacp_init_mux_machine (vm, mif);
   lacp_init_ptx_machine (vm, mif);
   lacp_init_rx_machine (vm, mif);
-  stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
-                                 [mif->sw_if_index].actor_state,
-                                 mif->actor.state);
-  stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
-                                 [mif->sw_if_index].partner_state,
-                                 mif->partner.state);
+  vlib_stats_set_gauge (
+    bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state,
+    mif->actor.state);
+  vlib_stats_set_gauge (
+    bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state,
+    mif->partner.state);
 }
 
 VLIB_INIT_FUNCTION (lacp_periodic_init);
index ed4c734..abcb530 100644 (file)
@@ -187,7 +187,7 @@ scrape_stats_segment (mt_main_t * mm)
   mactime_device_t *dev;
   stat_segment_access_t sa;
   stat_client_main_t *sm = mm->stat_client_main;
-  stat_segment_directory_entry_t *ep;
+  vlib_stats_entry_t *ep;
   int need_update2 = 0;
   static u32 *pool_indices;
   int i, j;
index c29ee54..b67a247 100644 (file)
@@ -38,7 +38,7 @@
 #include <nat/nat44-ed/nat44_ed_affinity.h>
 #include <nat/nat44-ed/nat44_ed_inlines.h>
 
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 
 snat_main_t snat_main;
 
@@ -2290,8 +2290,8 @@ nat_init (vlib_main_t * vm)
 
   nat_init_simple_counter (sm->total_sessions, "total-sessions",
                           "/nat44-ed/total-sessions");
-  sm->max_cfg_sessions_gauge = stat_segment_new_entry (
-    (u8 *) "/nat44-ed/max-cfg-sessions", STAT_DIR_TYPE_SCALAR_INDEX);
+  sm->max_cfg_sessions_gauge =
+    vlib_stats_add_gauge ("/nat44-ed/max-cfg-sessions");
 
 #define _(x)                                                                  \
   nat_init_simple_counter (sm->counters.fastpath.in2out.x, #x,                \
@@ -2373,8 +2373,8 @@ nat44_plugin_enable (nat44_config_t c)
     c.sessions = 63 * 1024;
 
   sm->max_translations_per_thread = c.sessions;
-  stat_segment_set_state_counter (sm->max_cfg_sessions_gauge,
-                                 sm->max_translations_per_thread);
+  vlib_stats_set_gauge (sm->max_cfg_sessions_gauge,
+                       sm->max_translations_per_thread);
   sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
 
   vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
@@ -3145,8 +3145,8 @@ nat44_update_session_limit (u32 session_limit, u32 vrf_id)
     return 1;
   sm->max_translations_per_thread = nat44_get_max_session_limit ();
 
-  stat_segment_set_state_counter (sm->max_cfg_sessions_gauge,
-                                 sm->max_translations_per_thread);
+  vlib_stats_set_gauge (sm->max_cfg_sessions_gauge,
+                       sm->max_translations_per_thread);
 
   sm->translation_buckets =
     nat_calc_bihash_buckets (sm->max_translations_per_thread);
index bfe1838..2dc59ac 100644 (file)
 void os_panic(void) {}
 void os_exit(int code) {}
 u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index) { return 0; }
-#include <vpp/stats/stat_segment.h>
-clib_error_t *stat_segment_register_gauge(u8 *names,
-                                          stat_segment_update_fn update_fn,
-                                          u32 index) {
-    return 0;
-};
 #include <vnet/feature/feature.h>
 vnet_feature_main_t feature_main;
 void classify_get_trace_chain(void){};
index 3fb3704..0b03a7a 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <prom/prom.h>
 #include <vpp-api/client/stat_client.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 #include <ctype.h>
 
 static prom_main_t prom_main;
@@ -388,7 +388,7 @@ static void
 prom_stat_segment_client_init (void)
 {
   stat_client_main_t *scm = &stat_client_main;
-  stat_segment_main_t *sm = &stat_segment_main;
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
   uword size;
 
   size = sm->memory_size ? sm->memory_size : STAT_SEGMENT_DEFAULT_SIZE;
index 24b9e1e..e7090f0 100644 (file)
@@ -19,7 +19,7 @@
 #include <vppinfra/error.h>
 
 #include <vlib/counter.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 
 enum
 {
@@ -38,7 +38,7 @@ enum
 static uint64_t
 get_stats_epoch ()
 {
-  stat_segment_main_t *sm = &stat_segment_main;
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
   return sm->shared_header->epoch;
 }
 
@@ -49,7 +49,7 @@ get_stats_epoch ()
 static int
 get_vec_mem_size (void *v, uword data_size)
 {
-  stat_segment_main_t *sm = &stat_segment_main;
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
 
   if (v == 0)
     return 0;
index a74c8ce..bb43abd 100644 (file)
@@ -88,6 +88,12 @@ add_vpp_library(vlib
   physmem.c
   punt.c
   punt_node.c
+  stats/cli.c
+  stats/collector.c
+  stats/format.c
+  stats/init.c
+  stats/provider_mem.c
+  stats/stats.c
   threads.c
   threads_cli.c
   time.c
@@ -130,6 +136,8 @@ add_vpp_library(vlib
   physmem_funcs.h
   physmem.h
   punt.h
+  stats/shared.h
+  stats/stats.h
   threads.h
   time.h
   trace_funcs.h
index 7a70a8a..fbded6e 100644 (file)
@@ -46,7 +46,7 @@
 #include <vppinfra/linux/sysfs.h>
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 
 #define VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA 16384
 #define VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA_UNPRIV 8192
@@ -63,17 +63,6 @@ STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, template_end, 64);
 
 u16 __vlib_buffer_external_hdr_size = 0;
 
-static void
-buffer_gauges_update_cached_fn (stat_segment_directory_entry_t * e,
-                               u32 index);
-
-static void
-buffer_gauges_update_available_fn (stat_segment_directory_entry_t * e,
-                                  u32 index);
-
-static void
-buffer_gauges_update_used_fn (stat_segment_directory_entry_t * e, u32 index);
-
 uword
 vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
                                       vlib_buffer_t * b_first)
@@ -798,37 +787,39 @@ buffer_get_by_index (vlib_buffer_main_t * bm, u32 index)
 }
 
 static void
-buffer_gauges_update_used_fn (stat_segment_directory_entry_t * e, u32 index)
+buffer_gauges_collect_used_fn (vlib_stats_collector_data_t *d)
 {
   vlib_main_t *vm = vlib_get_main ();
-  vlib_buffer_pool_t *bp = buffer_get_by_index (vm->buffer_main, index);
+  vlib_buffer_pool_t *bp =
+    buffer_get_by_index (vm->buffer_main, d->private_data);
   if (!bp)
     return;
 
-  e->value = bp->n_buffers - bp->n_avail - buffer_get_cached (bp);
+  d->entry->value = bp->n_buffers - bp->n_avail - buffer_get_cached (bp);
 }
 
 static void
-buffer_gauges_update_available_fn (stat_segment_directory_entry_t * e,
-                                  u32 index)
+buffer_gauges_collect_available_fn (vlib_stats_collector_data_t *d)
 {
   vlib_main_t *vm = vlib_get_main ();
-  vlib_buffer_pool_t *bp = buffer_get_by_index (vm->buffer_main, index);
+  vlib_buffer_pool_t *bp =
+    buffer_get_by_index (vm->buffer_main, d->private_data);
   if (!bp)
     return;
 
-  e->value = bp->n_avail;
+  d->entry->value = bp->n_avail;
 }
 
 static void
-buffer_gauges_update_cached_fn (stat_segment_directory_entry_t * e, u32 index)
+buffer_gauges_collect_cached_fn (vlib_stats_collector_data_t *d)
 {
   vlib_main_t *vm = vlib_get_main ();
-  vlib_buffer_pool_t *bp = buffer_get_by_index (vm->buffer_main, index);
+  vlib_buffer_pool_t *bp =
+    buffer_get_by_index (vm->buffer_main, d->private_data);
   if (!bp)
     return;
 
-  e->value = buffer_get_cached (bp);
+  d->entry->value = buffer_get_cached (bp);
 }
 
 clib_error_t *
@@ -902,23 +893,23 @@ vlib_buffer_main_init (struct vlib_main_t * vm)
 
   vec_foreach (bp, bm->buffer_pools)
   {
+    vlib_stats_collector_reg_t reg = { .private_data = bp - bm->buffer_pools };
     if (bp->n_buffers == 0)
       continue;
 
-    vec_reset_length (name);
-    name = format (name, "/buffer-pools/%s/cached%c", bp->name, 0);
-    stat_segment_register_gauge (name, buffer_gauges_update_cached_fn,
-                                bp - bm->buffer_pools);
+    reg.entry_index =
+      vlib_stats_add_gauge ("/buffer-pools/%s/cached", bp->name);
+    reg.collect_fn = buffer_gauges_collect_cached_fn;
+    vlib_stats_register_collector_fn (&reg);
 
-    vec_reset_length (name);
-    name = format (name, "/buffer-pools/%s/used%c", bp->name, 0);
-    stat_segment_register_gauge (name, buffer_gauges_update_used_fn,
-                                bp - bm->buffer_pools);
+    reg.entry_index = vlib_stats_add_gauge ("/buffer-pools/%s/used", bp->name);
+    reg.collect_fn = buffer_gauges_collect_used_fn;
+    vlib_stats_register_collector_fn (&reg);
 
-    vec_reset_length (name);
-    name = format (name, "/buffer-pools/%s/available%c", bp->name, 0);
-    stat_segment_register_gauge (name, buffer_gauges_update_available_fn,
-                                bp - bm->buffer_pools);
+    reg.entry_index =
+      vlib_stats_add_gauge ("/buffer-pools/%s/available", bp->name);
+    reg.collect_fn = buffer_gauges_collect_available_fn;
+    vlib_stats_register_collector_fn (&reg);
   }
 
 done:
index a00ae62..2187d28 100644 (file)
@@ -38,6 +38,7 @@
  */
 
 #include <vlib/vlib.h>
+#include <vlib/stats/stats.h>
 #include <vlib/unix/unix.h>
 #include <vppinfra/callback.h>
 #include <vppinfra/cpu.h>
@@ -753,13 +754,6 @@ vl_msg_pop_heap (void *oldheap)
 {
 }
 
-void *vlib_stats_push_heap (void *) __attribute__ ((weak));
-void *
-vlib_stats_push_heap (void *notused)
-{
-  return 0;
-}
-
 static clib_error_t *
 show_memory_usage (vlib_main_t * vm,
                   unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -820,14 +814,14 @@ show_memory_usage (vlib_main_t * vm,
     }
   if (stats_segment)
     {
-      void *oldheap = vlib_stats_push_heap (0);
+      void *oldheap = vlib_stats_set_heap (0);
       was_enabled = clib_mem_trace_enable_disable (0);
       u8 *s_in_svm = format (0, "%U\n", format_clib_mem_heap, 0, 1);
       if (oldheap)
        clib_mem_set_heap (oldheap);
       u8 *s = vec_dup (s_in_svm);
 
-      oldheap = vlib_stats_push_heap (0);
+      oldheap = vlib_stats_set_heap (0);
       vec_free (s_in_svm);
       if (oldheap)
        {
@@ -1038,7 +1032,7 @@ enable_disable_memory_trace (vlib_main_t * vm,
   /* Stats segment */
   if (stats_segment)
     {
-      oldheap = vlib_stats_push_heap (0);
+      oldheap = vlib_stats_set_heap ();
       current_traced_heap = clib_mem_get_heap ();
       clib_mem_trace (stats_segment);
       /* We don't want to call vlib_stats_pop_heap... */
index 186b48d..ceaf013 100644 (file)
@@ -38,7 +38,7 @@
  */
 
 #include <vlib/vlib.h>
-#include <vlib/stat_weak_inlines.h>
+#include <vlib/stats/stats.h>
 
 void
 vlib_clear_simple_counters (vlib_simple_counter_main_t * cm)
@@ -80,7 +80,7 @@ vlib_validate_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
 {
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   int i, resized = 0;
-  void *oldheap = vlib_stats_push_heap (cm->counters);
+  void *oldheap = vlib_stats_set_heap ();
 
   vec_validate (cm->counters, tm->n_vlib_mains - 1);
   for (i = 0; i < tm->n_vlib_mains; i++)
@@ -93,12 +93,10 @@ vlib_validate_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
        vec_validate_aligned (cm->counters[i], index, CLIB_CACHE_LINE_BYTES);
       }
 
+  clib_mem_set_heap (oldheap);
   /* Avoid the epoch increase when there was no counter vector resize. */
   if (resized)
-    vlib_stats_pop_heap (cm, oldheap, index,
-                        2 /* STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE */);
-  else
-    clib_mem_set_heap (oldheap);
+    vlib_stats_update_counter (cm, index, STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE);
 }
 
 void
@@ -108,7 +106,7 @@ vlib_free_simple_counter (vlib_simple_counter_main_t * cm)
 
   vlib_stats_delete_cm (cm);
 
-  void *oldheap = vlib_stats_push_heap (cm->counters);
+  void *oldheap = vlib_stats_set_heap ();
   for (i = 0; i < vec_len (cm->counters); i++)
     vec_free (cm->counters[i]);
   vec_free (cm->counters);
@@ -120,7 +118,7 @@ vlib_validate_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
 {
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   int i, resized = 0;
-  void *oldheap = vlib_stats_push_heap (cm->counters);
+  void *oldheap = vlib_stats_set_heap ();
 
   vec_validate (cm->counters, tm->n_vlib_mains - 1);
   for (i = 0; i < tm->n_vlib_mains; i++)
@@ -133,12 +131,11 @@ vlib_validate_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
        vec_validate_aligned (cm->counters[i], index, CLIB_CACHE_LINE_BYTES);
       }
 
+  clib_mem_set_heap (oldheap);
   /* Avoid the epoch increase when there was no counter vector resize. */
   if (resized)
-    vlib_stats_pop_heap (cm, oldheap, index,
-                        3 /*STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED */);
-  else
-    clib_mem_set_heap (oldheap);
+    vlib_stats_update_counter (cm, index,
+                              STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED);
 }
 
 int
@@ -147,7 +144,7 @@ int
 {
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   int i;
-  void *oldheap = vlib_stats_push_heap (cm->counters);
+  void *oldheap = vlib_stats_set_heap ();
 
   /* Possibly once in recorded history */
   if (PREDICT_FALSE (vec_len (cm->counters) == 0))
@@ -180,7 +177,7 @@ vlib_free_combined_counter (vlib_combined_counter_main_t * cm)
 
   vlib_stats_delete_cm (cm);
 
-  void *oldheap = vlib_stats_push_heap (cm->counters);
+  void *oldheap = vlib_stats_set_heap ();
   for (i = 0; i < vec_len (cm->counters); i++)
     vec_free (cm->counters[i]);
   vec_free (cm->counters);
index 9a9ca4a..e513a7d 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <vlib/vlib.h>
 #include <vppinfra/heap.h>
-#include <vlib/stat_weak_inlines.h>
+#include <vlib/stats/stats.h>
 
 uword
 vlib_error_drop_buffers (vlib_main_t * vm,
@@ -158,7 +158,7 @@ vlib_register_errors (vlib_main_t *vm, u32 node_index, u32 n_errors,
   vec_validate (vm->error_elog_event_types, l - 1);
 
   /* Switch to the stats segment ... */
-  oldheap = vlib_stats_push_heap (0);
+  oldheap = vlib_stats_set_heap ();
 
   /* Allocate a counter/elog type for each error. */
   vec_validate (em->counters, l - 1);
@@ -172,25 +172,23 @@ vlib_register_errors (vlib_main_t *vm, u32 node_index, u32 n_errors,
     clib_memset (em->counters + n->error_heap_index,
                 0, n_errors * sizeof (em->counters[0]));
 
+  oldheap = clib_mem_set_heap (oldheap);
+
   /* Register counter indices in the stat segment directory */
   {
     int i;
-    u8 *error_name = 0;
 
     for (i = 0; i < n_errors; i++)
       {
-       vec_reset_length (error_name);
-       error_name =
-         format (error_name, "/err/%v/%s%c", n->name, counters[i].name, 0);
-       vlib_stats_register_error_index (oldheap, error_name, em->counters,
-                                        n->error_heap_index + i);
+       vlib_stats_register_error_index (em->counters, n->error_heap_index + i,
+                                        "/err/%v/%s", n->name,
+                                        counters[i].name);
       }
 
-    vec_free (error_name);
   }
 
   /* (re)register the em->counters base address, switch back to main heap */
-  vlib_stats_pop_heap2 (em->counters, vm->thread_index, oldheap, 1);
+  vlib_stats_update_error_vector (em->counters, vm->thread_index, 1);
 
   {
     elog_event_type_t t;
index 189884a..6d241bd 100644 (file)
@@ -41,6 +41,7 @@
 #include <vppinfra/format.h>
 #include <vlib/vlib.h>
 #include <vlib/threads.h>
+#include <vlib/stats/stats.h>
 #include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
 
 #include <vlib/unix/unix.h>
@@ -1826,7 +1827,6 @@ placeholder_queue_signal_callback (vlib_main_t * vm)
 }
 
 #define foreach_weak_reference_stub             \
-_(vlib_map_stat_segment_init)                   \
 _(vpe_api_init)                                 \
 _(vlibmemory_init)                              \
 _(map_api_segment_init)
@@ -1887,7 +1887,7 @@ vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
       goto done;
     }
 
-  if ((error = vlib_map_stat_segment_init (vm)))
+  if ((error = vlib_stats_init (vm)))
     {
       clib_error_report (error);
       goto done;
index 77fef77..075430e 100644 (file)
@@ -42,6 +42,7 @@
 #include <fcntl.h>
 #include <vlib/vlib.h>
 #include <vlib/threads.h>
+#include <vlib/stats/stats.h>
 #include <math.h>
 
 static int
@@ -465,13 +466,6 @@ format_vlib_node_stats (u8 * s, va_list * va)
   return s;
 }
 
-f64 vlib_get_stat_segment_update_rate (void) __attribute__ ((weak));
-f64
-vlib_get_stat_segment_update_rate (void)
-{
-  return 1e70;
-}
-
 static clib_error_t *
 show_node_runtime (vlib_main_t * vm,
                   unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -598,16 +592,14 @@ show_node_runtime (vlib_main_t * vm,
            }
 
          dt = time_now - nm->time_last_runtime_stats_clear;
-         vlib_cli_output
-           (vm,
-            "Time %.1f, %f sec internal node vector rate %.2f loops/sec %.2f\n"
-            "  vector rates in %.4e, out %.4e, drop %.4e, punt %.4e",
-            dt,
-            vlib_get_stat_segment_update_rate (),
-            internal_node_vector_rates[j],
-            stat_vm->loops_per_second,
-            (f64) n_input / dt,
-            (f64) n_output / dt, (f64) n_drop / dt, (f64) n_punt / dt);
+         vlib_cli_output (
+           vm,
+           "Time %.1f, %f sec internal node vector rate %.2f loops/sec %.2f\n"
+           "  vector rates in %.4e, out %.4e, drop %.4e, punt %.4e",
+           dt, vlib_stats_get_segment_update_rate (),
+           internal_node_vector_rates[j], stat_vm->loops_per_second,
+           (f64) n_input / dt, (f64) n_output / dt, (f64) n_drop / dt,
+           (f64) n_punt / dt);
 
          if (summary == 0)
            {
@@ -684,6 +676,8 @@ clear_node_runtime (vlib_main_t * vm,
       nm->time_last_runtime_stats_clear = vlib_time_now (vm);
     }
 
+  vlib_stats_set_timestamp (STAT_COUNTER_LAST_STATS_CLEAR,
+                           vm->node_main.time_last_runtime_stats_clear);
   vlib_worker_thread_barrier_release (vm);
 
   vec_free (stat_vms);
diff --git a/src/vlib/stat_weak_inlines.h b/src/vlib/stat_weak_inlines.h
deleted file mode 100644 (file)
index a68566d..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * NOTE: Only include this file from external components that require
- * a loose coupling to the stats component.
- */
-
-#ifndef included_stat_weak_inlines_h
-#define included_stat_weak_inlines_h
-void *vlib_stats_push_heap (void *) __attribute__ ((weak));
-void *
-vlib_stats_push_heap (void *unused)
-{
-  return 0;
-};
-
-void vlib_stats_pop_heap (void *, void *, u32, int) __attribute__ ((weak));
-void
-vlib_stats_pop_heap (void *notused, void *notused2, u32 i, int type)
-{
-};
-void vlib_stats_register_error_index (void *, u8 *, u64 *, u64)
-  __attribute__ ((weak));
-void
-vlib_stats_register_error_index (void * notused, u8 * notused2, u64 * notused3, u64 notused4)
-{
-};
-
-void vlib_stats_pop_heap2 (void *, u32, void *, int) __attribute__ ((weak));
-void
-vlib_stats_pop_heap2 (void *notused, u32 notused2, void *notused3,
-                     int notused4)
-{
-};
-
-void vlib_stat_segment_lock (void) __attribute__ ((weak));
-void
-vlib_stat_segment_lock (void)
-{
-}
-
-void vlib_stat_segment_unlock (void) __attribute__ ((weak));
-void
-vlib_stat_segment_unlock (void)
-{
-}
-void vlib_stats_delete_cm (void *) __attribute__ ((weak));
-void
-vlib_stats_delete_cm (void *notused)
-{
-}
-
-void vlib_stats_register_mem_heap (void *) __attribute__ ((weak));
-void
-vlib_stats_register_mem_heap (void *notused)
-{
-}
-
-#endif
diff --git a/src/vlib/stats/cli.c b/src/vlib/stats/cli.c
new file mode 100644 (file)
index 0000000..4d7026b
--- /dev/null
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/stats/stats.h>
+
+static int
+name_sort_cmp (void *a1, void *a2)
+{
+  vlib_stats_entry_t *n1 = a1;
+  vlib_stats_entry_t *n2 = a2;
+
+  return strcmp ((char *) n1->name, (char *) n2->name);
+}
+
+static u8 *
+format_stat_dir_entry (u8 *s, va_list *args)
+{
+  vlib_stats_entry_t *ep = va_arg (*args, vlib_stats_entry_t *);
+  char *type_name;
+  char *format_string;
+
+  format_string = "%-74s %-10s %10lld";
+
+  switch (ep->type)
+    {
+    case STAT_DIR_TYPE_SCALAR_INDEX:
+      type_name = "ScalarPtr";
+      break;
+
+    case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
+    case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
+      type_name = "CMainPtr";
+      break;
+
+    case STAT_DIR_TYPE_ERROR_INDEX:
+      type_name = "ErrIndex";
+      break;
+
+    case STAT_DIR_TYPE_NAME_VECTOR:
+      type_name = "NameVector";
+      break;
+
+    case STAT_DIR_TYPE_EMPTY:
+      type_name = "empty";
+      break;
+
+    case STAT_DIR_TYPE_SYMLINK:
+      type_name = "Symlink";
+      break;
+
+    default:
+      type_name = "illegal!";
+      break;
+    }
+
+  return format (s, format_string, ep->name, type_name, 0);
+}
+static clib_error_t *
+show_stat_segment_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                             vlib_cli_command_t *cmd)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *show_data;
+  int i;
+
+  int verbose = 0;
+
+  if (unformat (input, "verbose"))
+    verbose = 1;
+
+  /* Lock even as reader, as this command doesn't handle epoch changes */
+  vlib_stats_segment_lock ();
+  show_data = vec_dup (sm->directory_vector);
+  vlib_stats_segment_unlock ();
+
+  vec_sort_with_function (show_data, name_sort_cmp);
+
+  vlib_cli_output (vm, "%-74s %10s %10s", "Name", "Type", "Value");
+
+  for (i = 0; i < vec_len (show_data); i++)
+    {
+      vlib_stats_entry_t *ep = vec_elt_at_index (show_data, i);
+
+      if (ep->type == STAT_DIR_TYPE_EMPTY)
+       continue;
+
+      vlib_cli_output (vm, "%-100U", format_stat_dir_entry,
+                      vec_elt_at_index (show_data, i));
+    }
+
+  if (verbose)
+    {
+      ASSERT (sm->heap);
+      vlib_cli_output (vm, "%U", format_clib_mem_heap, sm->heap,
+                      0 /* verbose */);
+    }
+
+  return 0;
+}
+
+static clib_error_t *
+show_stat_segment_hash_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                  vlib_cli_command_t *cmd)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  char *name;
+  u32 i;
+  hash_foreach_mem (name, i, sm->directory_vector_by_name,
+                   ({ vlib_cli_output (vm, "%d: %s\n", i, name); }));
+  return 0;
+}
+
+VLIB_CLI_COMMAND (show_stat_segment_hash_command, static) = {
+  .path = "show statistics hash",
+  .short_help = "show statistics hash",
+  .function = show_stat_segment_hash_command_fn,
+};
+
+VLIB_CLI_COMMAND (show_stat_segment_command, static) = {
+  .path = "show statistics segment",
+  .short_help = "show statistics segment [verbose]",
+  .function = show_stat_segment_command_fn,
+};
diff --git a/src/vlib/stats/collector.c b/src/vlib/stats/collector.c
new file mode 100644 (file)
index 0000000..cc348bb
--- /dev/null
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlib/stats/stats.h>
+
+static void
+stat_validate_counter_vector2 (vlib_stats_entry_t *ep, u32 max1, u32 max2)
+{
+  counter_t **counters = ep->data;
+  int i;
+  vec_validate_aligned (counters, max1, CLIB_CACHE_LINE_BYTES);
+  for (i = 0; i <= max1; i++)
+    vec_validate_aligned (counters[i], max2, CLIB_CACHE_LINE_BYTES);
+
+  ep->data = counters;
+}
+
+static void
+stat_validate_counter_vector (vlib_stats_entry_t *ep, u32 max)
+{
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
+  ASSERT (tm->n_vlib_mains > 0);
+  stat_validate_counter_vector2 (ep, tm->n_vlib_mains, max);
+}
+
+static inline void
+update_node_counters (vlib_stats_segment_t *sm)
+{
+  vlib_main_t **stat_vms = 0;
+  vlib_node_t ***node_dups = 0;
+  int i, j;
+  static u32 no_max_nodes = 0;
+
+  vlib_node_get_nodes (0 /* vm, for barrier sync */,
+                      (u32) ~0 /* all threads */, 1 /* include stats */,
+                      0 /* barrier sync */, &node_dups, &stat_vms);
+
+  u32 l = vec_len (node_dups[0]);
+  u8 *symlink_name = 0;
+
+  /*
+   * Extend performance nodes if necessary
+   */
+  if (l > no_max_nodes)
+    {
+      void *oldheap = clib_mem_set_heap (sm->heap);
+      vlib_stats_segment_lock ();
+
+      stat_validate_counter_vector (
+       &sm->directory_vector[STAT_COUNTER_NODE_CLOCKS], l - 1);
+      stat_validate_counter_vector (
+       &sm->directory_vector[STAT_COUNTER_NODE_VECTORS], l - 1);
+      stat_validate_counter_vector (
+       &sm->directory_vector[STAT_COUNTER_NODE_CALLS], l - 1);
+      stat_validate_counter_vector (
+       &sm->directory_vector[STAT_COUNTER_NODE_SUSPENDS], l - 1);
+
+      vec_validate (sm->nodes, l - 1);
+      vlib_stats_entry_t *ep;
+      ep = &sm->directory_vector[STAT_COUNTER_NODE_NAMES];
+      ep->data = sm->nodes;
+
+      /* Update names dictionary */
+      vlib_node_t **nodes = node_dups[0];
+      int i;
+      for (i = 0; i < vec_len (nodes); i++)
+       {
+         vlib_node_t *n = nodes[i];
+         u8 *s = format (0, "%v%c", n->name, 0);
+         if (sm->nodes[n->index])
+           vec_free (sm->nodes[n->index]);
+         sm->nodes[n->index] = s;
+
+         oldheap = clib_mem_set_heap (oldheap);
+#define _(E, t, name, p)                                                      \
+  vlib_stats_add_symlink (STAT_COUNTER_##E, n->index, "/nodes/%U/" #name,     \
+                         format_vlib_stats_symlink, s);
+         foreach_stat_segment_node_counter_name
+#undef _
+           oldheap = clib_mem_set_heap (oldheap);
+       }
+
+      vlib_stats_segment_unlock ();
+      clib_mem_set_heap (oldheap);
+      no_max_nodes = l;
+    }
+
+  for (j = 0; j < vec_len (node_dups); j++)
+    {
+      vlib_node_t **nodes = node_dups[j];
+
+      for (i = 0; i < vec_len (nodes); i++)
+       {
+         counter_t **counters;
+         counter_t *c;
+         vlib_node_t *n = nodes[i];
+
+         if (j == 0)
+           {
+             if (strncmp ((char *) sm->nodes[n->index], (char *) n->name,
+                          strlen ((char *) sm->nodes[n->index])))
+               {
+                 u32 vector_index;
+                 void *oldheap = clib_mem_set_heap (sm->heap);
+                 vlib_stats_segment_lock ();
+                 u8 *s = format (0, "%v%c", n->name, 0);
+                 clib_mem_set_heap (oldheap);
+#define _(E, t, name, p)                                                      \
+  vec_reset_length (symlink_name);                                            \
+  symlink_name = format (symlink_name, "/nodes/%U/" #name,                    \
+                        format_vlib_stats_symlink, sm->nodes[n->index]);     \
+  vector_index = vlib_stats_find_entry_index ("%v", symlink_name);            \
+  ASSERT (vector_index != -1);                                                \
+  vlib_stats_rename_symlink (vector_index, "/nodes/%U/" #name,                \
+                            format_vlib_stats_symlink, s);
+                 foreach_stat_segment_node_counter_name
+#undef _
+                   vec_free (symlink_name);
+                 clib_mem_set_heap (sm->heap);
+                 vec_free (sm->nodes[n->index]);
+                 sm->nodes[n->index] = s;
+                 vlib_stats_segment_unlock ();
+                 clib_mem_set_heap (oldheap);
+               }
+           }
+
+         counters = sm->directory_vector[STAT_COUNTER_NODE_CLOCKS].data;
+         c = counters[j];
+         c[n->index] = n->stats_total.clocks - n->stats_last_clear.clocks;
+
+         counters = sm->directory_vector[STAT_COUNTER_NODE_VECTORS].data;
+         c = counters[j];
+         c[n->index] = n->stats_total.vectors - n->stats_last_clear.vectors;
+
+         counters = sm->directory_vector[STAT_COUNTER_NODE_CALLS].data;
+         c = counters[j];
+         c[n->index] = n->stats_total.calls - n->stats_last_clear.calls;
+
+         counters = sm->directory_vector[STAT_COUNTER_NODE_SUSPENDS].data;
+         c = counters[j];
+         c[n->index] = n->stats_total.suspends - n->stats_last_clear.suspends;
+       }
+      vec_free (node_dups[j]);
+    }
+  vec_free (node_dups);
+  vec_free (stat_vms);
+}
+
+static void
+do_stat_segment_updates (vlib_main_t *vm, vlib_stats_segment_t *sm)
+{
+  if (sm->node_counters_enabled)
+    update_node_counters (sm);
+
+  vlib_stats_collector_t *c;
+  pool_foreach (c, sm->collectors)
+    {
+      vlib_stats_collector_data_t data = {
+       .entry_index = c->entry_index,
+       .vector_index = c->vector_index,
+       .private_data = c->private_data,
+       .entry = sm->directory_vector + c->entry_index,
+      };
+      c->fn (&data);
+    }
+
+  /* Heartbeat, so clients detect we're still here */
+  sm->directory_vector[STAT_COUNTER_HEARTBEAT].value++;
+}
+
+static uword
+stat_segment_collector_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
+                               vlib_frame_t *f)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+
+  while (1)
+    {
+      do_stat_segment_updates (vm, sm);
+      vlib_process_suspend (vm, sm->update_interval);
+    }
+  return 0; /* or not */
+}
+
+VLIB_REGISTER_NODE (stat_segment_collector, static) = {
+  .function = stat_segment_collector_process,
+  .name = "statseg-collector-process",
+  .type = VLIB_NODE_TYPE_PROCESS,
+};
diff --git a/src/vlib/stats/format.c b/src/vlib/stats/format.c
new file mode 100644 (file)
index 0000000..419ff6b
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlib/stats/stats.h>
+
+u8 *
+format_vlib_stats_symlink (u8 *s, va_list *args)
+{
+  char *input = va_arg (*args, char *);
+  char *modified_input = vec_dup (input);
+  int i;
+  u8 *result;
+
+  for (i = 0; i < strlen (modified_input); i++)
+    if (modified_input[i] == '/')
+      modified_input[i] = '_';
+
+  result = format (s, "%s", modified_input);
+  vec_free (modified_input);
+  return result;
+}
diff --git a/src/vlib/stats/init.c b/src/vlib/stats/init.c
new file mode 100644 (file)
index 0000000..d81916a
--- /dev/null
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlib/stats/stats.h>
+
+#define STAT_SEGMENT_SOCKET_FILENAME "stats.sock"
+
+static void
+vector_rate_collector_fn (vlib_stats_collector_data_t *d)
+{
+  vlib_main_t *this_vlib_main;
+  counter_t **counters = d->entry->data;
+  counter_t *cb = counters[0];
+  f64 vector_rate = 0.0;
+  u32 i, n_threads = vlib_get_n_threads ();
+
+  vlib_stats_validate_counter_vector (d->entry_index, n_threads - 1);
+
+  for (i = 0; i < n_threads; i++)
+    {
+      f64 this_vector_rate;
+      this_vlib_main = vlib_get_main_by_index (i);
+
+      this_vector_rate = vlib_internal_node_vector_rate (this_vlib_main);
+      vlib_clear_internal_node_vector_rate (this_vlib_main);
+
+      cb[i] = this_vector_rate;
+      vector_rate += this_vector_rate;
+    }
+
+  /* And set the system average rate */
+  vector_rate /= (f64) (i > 1 ? i - 1 : 1);
+  vlib_stats_set_gauge (d->private_data, vector_rate);
+}
+
+clib_error_t *
+vlib_stats_init (vlib_main_t *vm)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_shared_header_t *shared_header;
+  vlib_stats_collector_reg_t reg = {};
+
+  void *oldheap;
+  uword memory_size, sys_page_sz;
+  int mfd;
+  char *mem_name = "stat segment";
+  void *heap, *memaddr;
+
+  memory_size = sm->memory_size;
+  if (memory_size == 0)
+    memory_size = STAT_SEGMENT_DEFAULT_SIZE;
+
+  if (sm->log2_page_sz == CLIB_MEM_PAGE_SZ_UNKNOWN)
+    sm->log2_page_sz = CLIB_MEM_PAGE_SZ_DEFAULT;
+
+  mfd = clib_mem_vm_create_fd (sm->log2_page_sz, mem_name);
+
+  if (mfd == -1)
+    return clib_error_return (0, "stat segment memory fd failure: %U",
+                             format_clib_error, clib_mem_get_last_error ());
+  /* Set size */
+  if ((ftruncate (mfd, memory_size)) == -1)
+    {
+      close (mfd);
+      return clib_error_return (0, "stat segment ftruncate failure");
+    }
+
+  memaddr = clib_mem_vm_map_shared (0, memory_size, mfd, 0, mem_name);
+
+  if (memaddr == CLIB_MEM_VM_MAP_FAILED)
+    return clib_error_return (0, "stat segment mmap failure");
+
+  sys_page_sz = clib_mem_get_page_size ();
+
+  heap =
+    clib_mem_create_heap (((u8 *) memaddr) + sys_page_sz,
+                         memory_size - sys_page_sz, 1 /* locked */, mem_name);
+  sm->heap = heap;
+  sm->memfd = mfd;
+
+  sm->directory_vector_by_name = hash_create_string (0, sizeof (uword));
+  sm->shared_header = shared_header = memaddr;
+
+  shared_header->version = STAT_SEGMENT_VERSION;
+  shared_header->base = memaddr;
+
+  sm->stat_segment_lockp = clib_mem_alloc (sizeof (clib_spinlock_t));
+  clib_spinlock_init (sm->stat_segment_lockp);
+
+  oldheap = clib_mem_set_heap (sm->heap);
+
+  /* Set up the name to counter-vector hash table */
+  sm->directory_vector = 0;
+
+  shared_header->epoch = 1;
+
+  /* Scalar stats and node counters */
+  vec_validate (sm->directory_vector, STAT_COUNTERS - 1);
+#define _(E, t, n, p)                                                         \
+  strcpy (sm->directory_vector[STAT_COUNTER_##E].name, p "/" #n);             \
+  sm->directory_vector[STAT_COUNTER_##E].type = STAT_DIR_TYPE_##t;
+  foreach_stat_segment_counter_name
+#undef _
+    /* Save the vector in the shared segment, for clients */
+    shared_header->directory_vector = sm->directory_vector;
+
+  clib_mem_set_heap (oldheap);
+
+  vlib_stats_register_mem_heap (heap);
+
+  reg.collect_fn = vector_rate_collector_fn;
+  reg.private_data = vlib_stats_add_gauge ("/sys/vector_rate");
+  reg.entry_index =
+    vlib_stats_add_counter_vector ("/sys/vector_rate_per_worker");
+  vlib_stats_register_collector_fn (&reg);
+  vlib_stats_validate_counter_vector (reg.entry_index, vlib_get_n_threads ());
+
+  return 0;
+}
+
+static clib_error_t *
+statseg_config (vlib_main_t *vm, unformat_input_t *input)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  sm->update_interval = 10.0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "socket-name %s", &sm->socket_name))
+       ;
+      /* DEPRECATE: default (does nothing) */
+      else if (unformat (input, "default"))
+       ;
+      else if (unformat (input, "size %U", unformat_memory_size,
+                        &sm->memory_size))
+       ;
+      else if (unformat (input, "page-size %U", unformat_log2_page_size,
+                        &sm->log2_page_sz))
+       ;
+      else if (unformat (input, "per-node-counters on"))
+       sm->node_counters_enabled = 1;
+      else if (unformat (input, "per-node-counters off"))
+       sm->node_counters_enabled = 0;
+      else if (unformat (input, "update-interval %f", &sm->update_interval))
+       ;
+      else
+       return clib_error_return (0, "unknown input `%U'",
+                                 format_unformat_error, input);
+    }
+
+  /*
+   * NULL-terminate socket name string
+   * clib_socket_init()->socket_config() use C str*
+   */
+  if (vec_len (sm->socket_name))
+    vec_terminate_c_string (sm->socket_name);
+
+  return 0;
+}
+
+VLIB_EARLY_CONFIG_FUNCTION (statseg_config, "statseg");
+
+/*
+ * Accept connection on the socket and exchange the fd for the shared
+ * memory segment.
+ */
+static clib_error_t *
+stats_socket_accept_ready (clib_file_t *uf)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  clib_error_t *err;
+  clib_socket_t client = { 0 };
+
+  err = clib_socket_accept (sm->socket, &client);
+  if (err)
+    {
+      clib_error_report (err);
+      return err;
+    }
+
+  /* Send the fd across and close */
+  err = clib_socket_sendmsg (&client, 0, 0, &sm->memfd, 1);
+  if (err)
+    clib_error_report (err);
+  clib_socket_close (&client);
+
+  return 0;
+}
+
+static clib_error_t *
+stats_segment_socket_init (void)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  clib_error_t *error;
+  clib_socket_t *s = clib_mem_alloc (sizeof (clib_socket_t));
+
+  memset (s, 0, sizeof (clib_socket_t));
+  s->config = (char *) sm->socket_name;
+  s->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_SEQPACKET |
+            CLIB_SOCKET_F_ALLOW_GROUP_WRITE | CLIB_SOCKET_F_PASSCRED;
+
+  if ((error = clib_socket_init (s)))
+    return error;
+
+  clib_file_t template = { 0 };
+  template.read_function = stats_socket_accept_ready;
+  template.file_descriptor = s->fd;
+  template.description = format (0, "stats segment listener %s", s->config);
+  clib_file_add (&file_main, &template);
+
+  sm->socket = s;
+
+  return 0;
+}
+
+static clib_error_t *
+stats_segment_socket_exit (vlib_main_t *vm)
+{
+  /*
+   * cleanup the listener socket on exit.
+   */
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  unlink ((char *) sm->socket_name);
+  return 0;
+}
+
+VLIB_MAIN_LOOP_EXIT_FUNCTION (stats_segment_socket_exit);
+
+static clib_error_t *
+statseg_init (vlib_main_t *vm)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+
+  /* set default socket file name when statseg config stanza is empty. */
+  if (!vec_len (sm->socket_name))
+    sm->socket_name = format (0, "%s/%s%c", vlib_unix_get_runtime_dir (),
+                             STAT_SEGMENT_SOCKET_FILENAME, 0);
+  return stats_segment_socket_init ();
+}
+
+VLIB_INIT_FUNCTION (statseg_init) = {
+  .runs_after = VLIB_INITS ("unix_input_init", "linux_epoll_input_init"),
+};
diff --git a/src/vlib/stats/provider_mem.c b/src/vlib/stats/provider_mem.c
new file mode 100644 (file)
index 0000000..d52ea4a
--- /dev/null
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlib/stats/stats.h>
+
+static clib_mem_heap_t **memory_heaps_vec;
+
+enum
+{
+  STAT_MEM_TOTAL = 0,
+  STAT_MEM_USED,
+  STAT_MEM_FREE,
+  STAT_MEM_USED_MMAP,
+  STAT_MEM_TOTAL_ALLOC,
+  STAT_MEM_FREE_CHUNKS,
+  STAT_MEM_RELEASABLE,
+} stat_mem_usage_e;
+
+/*
+ * Called from the stats periodic process to update memory counters.
+ */
+static void
+stat_provider_mem_usage_update_fn (vlib_stats_collector_data_t *d)
+{
+  clib_mem_usage_t usage;
+  clib_mem_heap_t *heap;
+  counter_t **counters = d->entry->data;
+  counter_t *cb;
+
+  heap = vec_elt (memory_heaps_vec, d->private_data);
+  clib_mem_get_heap_usage (heap, &usage);
+  cb = counters[0];
+  cb[STAT_MEM_TOTAL] = usage.bytes_total;
+  cb[STAT_MEM_USED] = usage.bytes_used;
+  cb[STAT_MEM_FREE] = usage.bytes_free;
+  cb[STAT_MEM_USED_MMAP] = usage.bytes_used_mmap;
+  cb[STAT_MEM_TOTAL_ALLOC] = usage.bytes_max;
+  cb[STAT_MEM_FREE_CHUNKS] = usage.bytes_free_reclaimed;
+  cb[STAT_MEM_RELEASABLE] = usage.bytes_overhead;
+}
+
+/*
+ * Provide memory heap counters.
+ * Two dimensional array of heap index and per-heap gauges.
+ */
+void
+vlib_stats_register_mem_heap (clib_mem_heap_t *heap)
+{
+  vlib_stats_collector_reg_t r = {};
+  u32 idx;
+
+  vec_add1 (memory_heaps_vec, heap);
+
+  r.entry_index = idx = vlib_stats_add_counter_vector ("/mem/%s", heap->name);
+  vlib_stats_validate_counter_vector (idx, STAT_MEM_RELEASABLE);
+
+  /* Create symlink */
+  vlib_stats_add_symlink (idx, STAT_MEM_TOTAL, "/mem/%s/used", heap->name);
+  vlib_stats_add_symlink (idx, STAT_MEM_USED, "/mem/%s/total", heap->name);
+  vlib_stats_add_symlink (idx, STAT_MEM_FREE, "/mem/%s/free", heap->name);
+
+  r.private_data = vec_len (memory_heaps_vec) - 1;
+  r.collect_fn = stat_provider_mem_usage_update_fn;
+  vlib_stats_register_collector_fn (&r);
+}
diff --git a/src/vlib/stats/shared.h b/src/vlib/stats/shared.h
new file mode 100644 (file)
index 0000000..d2d5d49
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#ifndef included_stat_segment_shared_h
+#define included_stat_segment_shared_h
+
+typedef enum
+{
+  STAT_DIR_TYPE_ILLEGAL = 0,
+  STAT_DIR_TYPE_SCALAR_INDEX,
+  STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
+  STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
+  STAT_DIR_TYPE_ERROR_INDEX,
+  STAT_DIR_TYPE_NAME_VECTOR,
+  STAT_DIR_TYPE_EMPTY,
+  STAT_DIR_TYPE_SYMLINK,
+} stat_directory_type_t;
+
+typedef struct
+{
+  stat_directory_type_t type;
+  union
+  {
+    struct
+    {
+      uint32_t index1;
+      uint32_t index2;
+    };
+    uint64_t index;
+    uint64_t value;
+    void *data;
+    uint8_t **string_vector;
+  };
+#define VLIB_STATS_MAX_NAME_SZ 128
+  char name[VLIB_STATS_MAX_NAME_SZ];
+} vlib_stats_entry_t;
+
+/*
+ * Shared header first in the shared memory segment.
+ */
+typedef struct
+{
+  uint64_t version;
+  void *base;
+  volatile uint64_t epoch;
+  volatile uint64_t in_progress;
+  volatile vlib_stats_entry_t *directory_vector;
+  volatile uint64_t **error_vector;
+} vlib_stats_shared_header_t;
+
+#endif /* included_stat_segment_shared_h */
diff --git a/src/vlib/stats/stats.c b/src/vlib/stats/stats.c
new file mode 100644 (file)
index 0000000..19edaf0
--- /dev/null
@@ -0,0 +1,514 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/stats/stats.h>
+
+vlib_stats_main_t vlib_stats_main;
+
+/*
+ *  Used only by VPP writers
+ */
+
+void
+vlib_stats_segment_lock (void)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  clib_spinlock_lock (sm->stat_segment_lockp);
+  sm->shared_header->in_progress = 1;
+}
+
+void
+vlib_stats_segment_unlock (void)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  sm->shared_header->epoch++;
+  sm->shared_header->in_progress = 0;
+  clib_spinlock_unlock (sm->stat_segment_lockp);
+}
+
+/*
+ * Change heap to the stats shared memory segment
+ */
+void *
+vlib_stats_set_heap ()
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+
+  ASSERT (sm && sm->shared_header);
+  return clib_mem_set_heap (sm->heap);
+}
+
+u32
+vlib_stats_find_entry_index (char *fmt, ...)
+{
+  u8 *name;
+  va_list va;
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+  vec_add1 (name, 0);
+
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  hash_pair_t *hp = hash_get_pair (sm->directory_vector_by_name, name);
+  vec_free (name);
+  return hp ? hp->value[0] : STAT_SEGMENT_INDEX_INVALID;
+}
+
+static void
+hash_set_str_key_alloc (uword **h, const char *key, uword v)
+{
+  int size = strlen (key) + 1;
+  void *copy = clib_mem_alloc (size);
+  clib_memcpy_fast (copy, key, size);
+  hash_set_mem (*h, copy, v);
+}
+
+static void
+hash_unset_str_key_free (uword **h, const char *key)
+{
+  hash_pair_t *hp = hash_get_pair_mem (*h, key);
+  if (hp)
+    {
+      void *_k = uword_to_pointer (hp->key, void *);
+      hash_unset_mem (*h, _k);
+      clib_mem_free (_k);
+    }
+}
+
+u32
+vlib_stats_create_counter (vlib_stats_entry_t *e)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  void *oldheap;
+  u32 index = ~0;
+  int i;
+
+  oldheap = clib_mem_set_heap (sm->heap);
+  vec_foreach_index_backwards (i, sm->directory_vector)
+    if (sm->directory_vector[i].type == STAT_DIR_TYPE_EMPTY)
+      {
+       index = i;
+       break;
+      }
+
+  index = index == ~0 ? vec_len (sm->directory_vector) : index;
+
+  vec_validate (sm->directory_vector, index);
+  sm->directory_vector[index] = *e;
+
+  clib_mem_set_heap (oldheap);
+  hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
+
+  return index;
+}
+
+void
+vlib_stats_remove_entry (u32 entry_index)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
+  void *oldheap;
+  counter_t **c;
+  u32 i;
+
+  if (entry_index >= vec_len (sm->directory_vector))
+    return;
+
+  oldheap = clib_mem_set_heap (sm->heap);
+
+  switch (e->type)
+    {
+    case STAT_DIR_TYPE_NAME_VECTOR:
+      for (i = 0; i < vec_len (e->string_vector); i++)
+       vec_free (e->string_vector[i]);
+      vec_free (e->string_vector);
+      break;
+
+    case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
+      c = e->data;
+      e->data = 0;
+      for (i = 0; i < vec_len (c); i++)
+       vec_free (c[i]);
+      vec_free (c);
+      break;
+
+    case STAT_DIR_TYPE_SCALAR_INDEX:
+    case STAT_DIR_TYPE_SYMLINK:
+      break;
+    default:
+      ASSERT (0);
+    }
+
+  clib_mem_set_heap (oldheap);
+  hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
+
+  memset (e, 0, sizeof (*e));
+  e->type = STAT_DIR_TYPE_EMPTY;
+}
+
+static void
+vlib_stats_set_entry_name (vlib_stats_entry_t *e, char *s)
+{
+  u32 i, len = VLIB_STATS_MAX_NAME_SZ - 1;
+
+  for (i = 0; i < len; i++)
+    {
+      e->name[i] = s[i];
+      if (s[i] == 0)
+       return;
+    }
+  ASSERT (i < VLIB_STATS_MAX_NAME_SZ - 1);
+  s[i] = 0;
+}
+
+void
+vlib_stats_update_counter (void *cm_arg, u32 cindex,
+                          stat_directory_type_t type)
+{
+  vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
+  char *stat_segment_name;
+  vlib_stats_entry_t e = { 0 };
+
+  /* Not all counters have names / hash-table entries */
+  if (!cm->name && !cm->stat_segment_name)
+    return;
+
+  ASSERT (shared_header);
+
+  vlib_stats_segment_lock ();
+
+  /* Lookup hash-table is on the main heap */
+  stat_segment_name = cm->stat_segment_name ? cm->stat_segment_name : cm->name;
+
+  u32 vector_index = vlib_stats_find_entry_index ("%s", stat_segment_name);
+
+  /* Update the vector */
+  if (vector_index == STAT_SEGMENT_INDEX_INVALID)
+    {
+      vlib_stats_set_entry_name (&e, stat_segment_name);
+      e.type = type;
+      vector_index = vlib_stats_create_counter (&e);
+    }
+
+  vlib_stats_entry_t *ep = &sm->directory_vector[vector_index];
+  ep->data = cm->counters;
+
+  /* Reset the client hash table pointer, since it WILL change! */
+  shared_header->directory_vector = sm->directory_vector;
+
+  vlib_stats_segment_unlock ();
+}
+
+void
+vlib_stats_register_error_index (u64 *em_vec, u64 index, char *fmt, ...)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
+  vlib_stats_entry_t e = {};
+  va_list va;
+  u8 *name;
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+
+  ASSERT (shared_header);
+
+  vlib_stats_segment_lock ();
+  u32 vector_index = vlib_stats_find_entry_index ("%v", name);
+
+  if (vector_index == STAT_SEGMENT_INDEX_INVALID)
+    {
+      vec_add1 (name, 0);
+      vlib_stats_set_entry_name (&e, (char *) name);
+      e.type = STAT_DIR_TYPE_ERROR_INDEX;
+      e.index = index;
+      vector_index = vlib_stats_create_counter (&e);
+
+      /* Warn clients to refresh any pointers they might be holding */
+      shared_header->directory_vector = sm->directory_vector;
+    }
+
+  vlib_stats_segment_unlock ();
+  vec_free (name);
+}
+
+void
+vlib_stats_update_error_vector (u64 *error_vector, u32 thread_index, int lock)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
+  void *oldheap = clib_mem_set_heap (sm->heap);
+
+  ASSERT (shared_header);
+
+  if (lock)
+    vlib_stats_segment_lock ();
+
+  /* Reset the client hash table pointer, since it WILL change! */
+  vec_validate (sm->error_vector, thread_index);
+  sm->error_vector[thread_index] = error_vector;
+
+  shared_header->error_vector = sm->error_vector;
+  shared_header->directory_vector = sm->directory_vector;
+
+  if (lock)
+    vlib_stats_segment_unlock ();
+  clib_mem_set_heap (oldheap);
+}
+
+void
+vlib_stats_delete_cm (void *cm_arg)
+{
+  vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e;
+
+  /* Not all counters have names / hash-table entries */
+  if (!cm->name && !cm->stat_segment_name)
+    return;
+
+  vlib_stats_segment_lock ();
+
+  /* Lookup hash-table is on the main heap */
+  char *stat_segment_name =
+    cm->stat_segment_name ? cm->stat_segment_name : cm->name;
+  u32 index = vlib_stats_find_entry_index ("%s", stat_segment_name);
+
+  e = &sm->directory_vector[index];
+
+  hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
+
+  memset (e, 0, sizeof (*e));
+  e->type = STAT_DIR_TYPE_EMPTY;
+
+  vlib_stats_segment_unlock ();
+}
+
+static u32
+vlib_stats_new_entry_internal (stat_directory_type_t t, u8 *name)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
+  vlib_stats_entry_t e = { .type = t };
+
+  ASSERT (shared_header);
+
+  u32 vector_index = vlib_stats_find_entry_index ("%v", name);
+  if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
+    {
+      vector_index = ~0;
+      goto done;
+    }
+
+  vec_add1 (name, 0);
+  vlib_stats_set_entry_name (&e, (char *) name);
+
+  vlib_stats_segment_lock ();
+  vector_index = vlib_stats_create_counter (&e);
+
+  shared_header->directory_vector = sm->directory_vector;
+
+  vlib_stats_segment_unlock ();
+
+done:
+  vec_free (name);
+  return vector_index;
+}
+
+u32
+vlib_stats_add_gauge (char *fmt, ...)
+{
+  va_list va;
+  u8 *name;
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+  return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
+}
+
+void
+vlib_stats_set_gauge (u32 index, u64 value)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+
+  ASSERT (index < vec_len (sm->directory_vector));
+  sm->directory_vector[index].value = value;
+}
+
+u32
+vlib_stats_add_timestamp (char *fmt, ...)
+{
+  va_list va;
+  u8 *name;
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+  return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
+}
+
+void
+vlib_stats_set_timestamp (u32 entry_index, f64 value)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+
+  ASSERT (entry_index < vec_len (sm->directory_vector));
+  sm->directory_vector[entry_index].value = value;
+}
+
+u32
+vlib_stats_add_string_vector (char *fmt, ...)
+{
+  va_list va;
+  u8 *name;
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+  return vlib_stats_new_entry_internal (STAT_DIR_TYPE_NAME_VECTOR, name);
+}
+
+void
+vlib_stats_set_string_vector (u32 entry_index, u32 vector_index, char *fmt,
+                             ...)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
+  va_list va;
+  void *oldheap;
+
+  oldheap = clib_mem_set_heap (sm->heap);
+  vlib_stats_segment_lock ();
+
+  vec_validate (e->string_vector, vector_index);
+  vec_reset_length (e->string_vector[vector_index]);
+
+  va_start (va, fmt);
+  e->string_vector[vector_index] =
+    va_format (e->string_vector[vector_index], fmt, &va);
+  va_end (va);
+
+  vlib_stats_segment_unlock ();
+  clib_mem_set_heap (oldheap);
+}
+
+u32
+vlib_stats_add_counter_vector (char *fmt, ...)
+{
+  va_list va;
+  u8 *name;
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+  return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
+                                       name);
+}
+
+void
+vlib_stats_validate_counter_vector (u32 entry_index, u32 vector_index)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
+  void *oldheap;
+  counter_t **c = e->data;
+
+  if (vec_len (c) > 0 && vec_len (c[0]) > vector_index)
+    return;
+
+  oldheap = clib_mem_set_heap (sm->heap);
+  vlib_stats_segment_lock ();
+
+  vec_validate_aligned (c, 0, CLIB_CACHE_LINE_BYTES);
+  vec_validate_aligned (c[0], vector_index, CLIB_CACHE_LINE_BYTES);
+  e->data = c;
+
+  vlib_stats_segment_unlock ();
+  clib_mem_set_heap (oldheap);
+}
+
+u32
+vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
+  vlib_stats_entry_t e;
+  va_list va;
+  u8 *name;
+
+  ASSERT (shared_header);
+  ASSERT (entry_index < vec_len (sm->directory_vector));
+
+  va_start (va, fmt);
+  name = va_format (0, fmt, &va);
+  va_end (va);
+
+  if (vlib_stats_find_entry_index ("%v", name) == STAT_SEGMENT_INDEX_INVALID)
+    {
+      vec_add1 (name, 0);
+      vlib_stats_set_entry_name (&e, (char *) name);
+      e.type = STAT_DIR_TYPE_SYMLINK;
+      e.index1 = entry_index;
+      e.index2 = vector_index;
+      vector_index = vlib_stats_create_counter (&e);
+
+      /* Warn clients to refresh any pointers they might be holding */
+      shared_header->directory_vector = sm->directory_vector;
+    }
+  else
+    vector_index = ~0;
+
+  vec_free (name);
+  return vector_index;
+}
+
+void
+vlib_stats_rename_symlink (u64 entry_index, char *fmt, ...)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
+  va_list va;
+  u8 *new_name;
+
+  hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
+
+  va_start (va, fmt);
+  new_name = va_format (0, fmt, &va);
+  va_end (va);
+
+  vec_add1 (new_name, 0);
+  vlib_stats_set_entry_name (e, (char *) new_name);
+  hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, entry_index);
+  vec_free (new_name);
+}
+
+f64
+vlib_stats_get_segment_update_rate (void)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  return sm->update_interval;
+}
+
+void
+vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *reg)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_collector_t *c;
+
+  ASSERT (reg->entry_index != ~0);
+
+  pool_get_zero (sm->collectors, c);
+  c->fn = reg->collect_fn;
+  c->entry_index = reg->entry_index;
+  c->vector_index = reg->vector_index;
+  c->private_data = reg->private_data;
+
+  return;
+}
diff --git a/src/vlib/stats/stats.h b/src/vlib/stats/stats.h
new file mode 100644 (file)
index 0000000..25d7c4b
--- /dev/null
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#ifndef included_stats_stats_h
+#define included_stats_stats_h
+
+#include <vppinfra/socket.h>
+#include <vppinfra/lock.h>
+#include <vlib/stats/shared.h>
+
+/* Default stat segment 32m */
+#define STAT_SEGMENT_DEFAULT_SIZE (32 << 20)
+
+/* Shared segment memory layout version */
+#define STAT_SEGMENT_VERSION 2
+
+#define STAT_SEGMENT_INDEX_INVALID UINT32_MAX
+
+typedef enum
+{
+  STAT_COUNTER_HEARTBEAT = 0,
+  STAT_COUNTER_LAST_STATS_CLEAR,
+  STAT_COUNTER_NODE_CLOCKS,
+  STAT_COUNTER_NODE_VECTORS,
+  STAT_COUNTER_NODE_CALLS,
+  STAT_COUNTER_NODE_SUSPENDS,
+  STAT_COUNTER_NODE_NAMES,
+  STAT_COUNTERS
+} stat_segment_counter_t;
+
+#define foreach_stat_segment_node_counter_name                                \
+  _ (NODE_CLOCKS, COUNTER_VECTOR_SIMPLE, clocks, "/sys/node")                 \
+  _ (NODE_VECTORS, COUNTER_VECTOR_SIMPLE, vectors, "/sys/node")               \
+  _ (NODE_CALLS, COUNTER_VECTOR_SIMPLE, calls, "/sys/node")                   \
+  _ (NODE_SUSPENDS, COUNTER_VECTOR_SIMPLE, suspends, "/sys/node")
+
+#define foreach_stat_segment_counter_name                                     \
+  _ (LAST_STATS_CLEAR, SCALAR_INDEX, last_stats_clear, "/sys")                \
+  _ (HEARTBEAT, SCALAR_INDEX, heartbeat, "/sys")                              \
+  _ (NODE_NAMES, NAME_VECTOR, names, "/sys/node")                             \
+  foreach_stat_segment_node_counter_name
+
+typedef struct
+{
+  u32 entry_index;
+  u32 vector_index;
+  u64 private_data;
+  vlib_stats_entry_t *entry;
+} vlib_stats_collector_data_t;
+
+typedef void (*vlib_stats_collector_fn_t) (vlib_stats_collector_data_t *);
+
+typedef struct
+{
+  vlib_stats_collector_fn_t collect_fn;
+  u32 entry_index;
+  u32 vector_index;
+  u64 private_data;
+} vlib_stats_collector_reg_t;
+
+typedef struct
+{
+  vlib_stats_collector_fn_t fn;
+  u32 entry_index;
+  u32 vector_index;
+  u64 private_data;
+} vlib_stats_collector_t;
+
+typedef struct
+{
+  /* internal, does not point to shared memory */
+  vlib_stats_collector_t *collectors;
+
+  /* statistics segment */
+  uword *directory_vector_by_name;
+  vlib_stats_entry_t *directory_vector;
+  volatile u64 **error_vector;
+  u8 **nodes;
+
+  /* Update interval */
+  f64 update_interval;
+
+  clib_spinlock_t *stat_segment_lockp;
+  clib_socket_t *socket;
+  u8 *socket_name;
+  ssize_t memory_size;
+  clib_mem_page_sz_t log2_page_sz;
+  u8 node_counters_enabled;
+  void *heap;
+  vlib_stats_shared_header_t
+    *shared_header; /* pointer to shared memory segment */
+  int memfd;
+
+} vlib_stats_segment_t;
+
+typedef struct
+{
+  vlib_stats_segment_t segment;
+} vlib_stats_main_t;
+
+extern vlib_stats_main_t vlib_stats_main;
+
+static_always_inline vlib_stats_segment_t *
+vlib_stats_get_segment ()
+{
+  return &vlib_stats_main.segment;
+}
+
+static_always_inline vlib_stats_entry_t *
+vlib_stats_get_entry (vlib_stats_segment_t *sm, u32 entry_index)
+{
+  vlib_stats_entry_t *e;
+  ASSERT (entry_index < vec_len (sm->directory_vector));
+  e = sm->directory_vector + entry_index;
+  ASSERT (e->type != STAT_DIR_TYPE_EMPTY && e->type != STAT_DIR_TYPE_ILLEGAL);
+  return e;
+}
+
+clib_error_t *vlib_stats_init (vlib_main_t *vm);
+void *vlib_stats_set_heap ();
+void vlib_stats_update_counter (void *, u32, stat_directory_type_t);
+void vlib_stats_register_error_index (u64 *em_vec, u64 index, char *fmt, ...);
+void vlib_stats_update_error_vector (u64 *error_vector, u32 thread_index,
+                                    int lock);
+void vlib_stats_segment_lock (void);
+void vlib_stats_segment_unlock (void);
+void vlib_stats_delete_cm (void *);
+void vlib_stats_register_mem_heap (clib_mem_heap_t *);
+f64 vlib_stats_get_segment_update_rate (void);
+
+/* gauge */
+u32 vlib_stats_add_gauge (char *fmt, ...);
+void vlib_stats_set_gauge (u32 entry_index, u64 value);
+
+/* timestamp */
+u32 vlib_stats_add_timestamp (char *fmt, ...);
+void vlib_stats_set_timestamp (u32 entry_index, f64 value);
+
+/* vector */
+u32 vlib_stats_add_counter_vector (char *fmt, ...);
+void vlib_stats_validate_counter_vector (u32 entry_index, u32 vector_index);
+
+/* string vector */
+u32 vlib_stats_add_string_vector (char *fmt, ...);
+void vlib_stats_set_string_vector (u32 entry_index, u32 vector_index,
+                                  char *fmt, ...);
+
+/* symlink */
+u32 vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...);
+void vlib_stats_rename_symlink (u64 entry_index, char *fmt, ...);
+
+/* common to all types */
+void vlib_stats_remove_entry (u32 entry_index);
+u32 vlib_stats_find_entry_index (char *fmt, ...);
+void vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *r);
+
+format_function_t format_vlib_stats_symlink;
+
+#endif
index f4d95c4..23e52c6 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <vlib/threads.h>
 
-#include <vlib/stat_weak_inlines.h>
+#include <vlib/stats/stats.h>
 
 u32
 vl (void *p)
@@ -180,6 +180,11 @@ vlib_thread_init (vlib_main_t * vm)
   u32 first_index = 1;
   u32 i;
   uword *avail_cpu;
+  u32 stats_num_worker_threads_dir_index;
+
+  stats_num_worker_threads_dir_index =
+    vlib_stats_add_gauge ("/sys/num_worker_threads");
+  ASSERT (stats_num_worker_threads_dir_index != ~0);
 
   /* get bitmaps of active cpu cores and sockets */
   tm->cpu_core_bitmap =
@@ -319,6 +324,7 @@ vlib_thread_init (vlib_main_t * vm)
   clib_bitmap_free (avail_cpu);
 
   tm->n_vlib_mains = n_vlib_mains;
+  vlib_stats_set_gauge (stats_num_worker_threads_dir_index, n_vlib_mains - 1);
 
   /*
    * Allocate the remaining worker threads, and thread stack vector slots
@@ -729,12 +735,13 @@ start_workers (vlib_main_t * vm)
                                CLIB_CACHE_LINE_BYTES);
 
              /* Switch to the stats segment ... */
-             void *oldheap = vlib_stats_push_heap (0);
+             void *oldheap = vlib_stats_set_heap ();
              vm_clone->error_main.counters =
                vec_dup_aligned (vlib_get_first_main ()->error_main.counters,
                                 CLIB_CACHE_LINE_BYTES);
-             vlib_stats_pop_heap2 (vm_clone->error_main.counters,
-                                   worker_thread_index, oldheap, 1);
+             clib_mem_set_heap (oldheap);
+             vlib_stats_update_error_vector (vm_clone->error_main.counters,
+                                             worker_thread_index, 1);
 
              vm_clone->error_main.counters_last_clear = vec_dup_aligned (
                vlib_get_first_main ()->error_main.counters_last_clear,
@@ -892,11 +899,12 @@ vlib_worker_thread_node_refork (void)
   j = vec_len (vm->error_main.counters) - 1;
 
   /* Switch to the stats segment ... */
-  void *oldheap = vlib_stats_push_heap (0);
+  void *oldheap = vlib_stats_set_heap ();
   vec_validate_aligned (old_counters, j, CLIB_CACHE_LINE_BYTES);
+  clib_mem_set_heap (oldheap);
   vm_clone->error_main.counters = old_counters;
-  vlib_stats_pop_heap2 (vm_clone->error_main.counters, vm_clone->thread_index,
-                       oldheap, 0);
+  vlib_stats_update_error_vector (vm_clone->error_main.counters,
+                                 vm_clone->thread_index, 0);
 
   vec_validate_aligned (old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES);
   vm_clone->error_main.counters_last_clear = old_counters_all_clear;
@@ -1392,7 +1400,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
        * rebuilding the stat segment node clones from the
        * stat thread...
        */
-      vlib_stat_segment_lock ();
+      vlib_stats_segment_lock ();
 
       /* Do stats elements on main thread */
       worker_thread_node_runtime_update_internal ();
@@ -1443,7 +1451,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm)
              os_panic ();
            }
        }
-      vlib_stat_segment_unlock ();
+      vlib_stats_segment_unlock ();
     }
 
   t_closed_total = now - vm->barrier_epoch;
index 88ef4cc..1cd5b58 100644 (file)
@@ -41,6 +41,7 @@ list(APPEND VNET_SOURCES
   interface/tx_queue.c
   interface/runtime.c
   interface/monitor.c
+  interface/stats.c
   interface_stats.c
   misc.c
 )
index 074d546..c89dd7c 100644 (file)
@@ -35,7 +35,7 @@
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/fib/fib_entry.h>
 #include <vnet/fib/fib_table.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 #include <vnet/bfd/bfd_debug.h>
 #include <vnet/bfd/bfd_udp.h>
 #include <vnet/bfd/bfd_main.h>
@@ -85,9 +85,9 @@ bfd_udp_main_t bfd_udp_main;
 void
 bfd_udp_update_stat_segment_entry (u32 entry, u64 value)
 {
-  vlib_stat_segment_lock ();
-  stat_segment_set_state_counter (entry, value);
-  vlib_stat_segment_unlock ();
+  vlib_stats_segment_lock ();
+  vlib_stats_set_gauge (entry, value);
+  vlib_stats_segment_unlock ();
 }
 
 vnet_api_error_t
@@ -1694,19 +1694,18 @@ clib_error_t *
 bfd_udp_stats_init (bfd_udp_main_t *bum)
 {
   const char *name4 = "/bfd/udp4/sessions";
-  bum->udp4_sessions_count_stat_seg_entry =
-    stat_segment_new_entry ((u8 *) name4, STAT_DIR_TYPE_SCALAR_INDEX);
+  bum->udp4_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name4);
 
-  stat_segment_set_state_counter (bum->udp4_sessions_count_stat_seg_entry, 0);
+  vlib_stats_set_gauge (bum->udp4_sessions_count_stat_seg_entry, 0);
   if (~0 == bum->udp4_sessions_count_stat_seg_entry)
     {
       return clib_error_return (
        0, "Could not create stat segment entry for %s", name4);
     }
   const char *name6 = "/bfd/udp6/sessions";
-  bum->udp6_sessions_count_stat_seg_entry =
-    stat_segment_new_entry ((u8 *) name6, STAT_DIR_TYPE_SCALAR_INDEX);
+  bum->udp6_sessions_count_stat_seg_entry = vlib_stats_add_gauge ("%s", name6);
 
+  vlib_stats_set_gauge (bum->udp6_sessions_count_stat_seg_entry, 0);
   if (~0 == bum->udp6_sessions_count_stat_seg_entry)
     {
       return clib_error_return (
index c3593ab..b0ded47 100644 (file)
@@ -20,7 +20,7 @@
 #include <vlib/unix/unix.h>
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/bonding/node.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/stats/stats.h>
 
 void
 bond_disable_collecting_distributing (vlib_main_t * vm, member_if_t * mif)
@@ -323,10 +323,10 @@ bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, member_if_t * mif)
 
   if (bif->mode == BOND_MODE_LACP)
     {
-      stat_segment_deregister_state_counter
-       (bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state);
-      stat_segment_deregister_state_counter
-       (bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state);
+      vlib_stats_remove_entry (
+       bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state);
+      vlib_stats_remove_entry (
+       bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state);
     }
 
   pool_put (bm->neighbors, mif);
@@ -650,32 +650,29 @@ bond_add_member (vlib_main_t * vm, bond_add_member_args_t * args)
     }
   if (bif->mode == BOND_MODE_LACP)
     {
-      u8 *name = format (0, "/if/lacp/%u/%u/state%c", bif->sw_if_index,
-                        args->member, 0);
+      u32 actor_idx, partner_idx;
 
-      vec_validate (bm->stats, bif->sw_if_index);
-      vec_validate (bm->stats[bif->sw_if_index], args->member);
-
-      args->error = stat_segment_register_state_counter
-       (name, &bm->stats[bif->sw_if_index][args->member].actor_state);
-      if (args->error != 0)
+      actor_idx = vlib_stats_add_gauge ("/if/lacp/%u/%u/state",
+                                       bif->sw_if_index, args->member);
+      if (actor_idx == ~0)
        {
          args->rv = VNET_API_ERROR_INVALID_INTERFACE;
-         vec_free (name);
          return;
        }
 
-      vec_reset_length (name);
-      name = format (0, "/if/lacp/%u/%u/partner-state%c", bif->sw_if_index,
-                    args->member, 0);
-      args->error = stat_segment_register_state_counter
-       (name, &bm->stats[bif->sw_if_index][args->member].partner_state);
-      vec_free (name);
-      if (args->error != 0)
+      partner_idx = vlib_stats_add_gauge ("/if/lacp/%u/%u/partner-state",
+                                         bif->sw_if_index, args->member);
+      if (partner_idx == ~0)
        {
+         vlib_stats_remove_entry (actor_idx);
          args->rv = VNET_API_ERROR_INVALID_INTERFACE;
          return;
        }
+
+      vec_validate (bm->stats, bif->sw_if_index);
+      vec_validate (bm->stats[bif->sw_if_index], args->member);
+      bm->stats[bif->sw_if_index][args->member].actor_state = actor_idx;
+      bm->stats[bif->sw_if_index][args->member].partner_state = partner_idx;
     }
 
   pool_get (bm->neighbors, mif);
index 5c28cad..1a4f02d 100644 (file)
@@ -18,6 +18,7 @@
 #include <vnet/feature/feature.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ethernet/ethernet.h>
+#include <vlib/stats/stats.h>
 
 vnet_device_main_t vnet_device_main;
 
@@ -101,12 +102,30 @@ VNET_FEATURE_INIT (ethernet_input, static) = {
 };
 /* *INDENT-ON* */
 
+static void
+input_rate_collector_fn (vlib_stats_collector_data_t *d)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e2 = sm->directory_vector + d->private_data;
+  static u64 last_input_packets = 0;
+  f64 dt, now;
+
+  now = vlib_time_now (vlib_get_main ());
+  u64 input_packets = vnet_get_aggregate_rx_packets ();
+
+  dt = now - e2->value;
+  d->entry->value = (f64) (input_packets - last_input_packets) / dt;
+  last_input_packets = input_packets;
+  e2->value = now;
+}
+
 static clib_error_t *
 vnet_device_init (vlib_main_t * vm)
 {
   vnet_device_main_t *vdm = &vnet_device_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   vlib_thread_registration_t *tr;
+  vlib_stats_collector_reg_t reg = {};
   uword *p;
 
   vec_validate_aligned (vdm->workers, tm->n_vlib_mains - 1,
@@ -120,6 +139,12 @@ vnet_device_init (vlib_main_t * vm)
       vdm->next_worker_thread_index = tr->first_index;
       vdm->last_worker_thread_index = tr->first_index + tr->count - 1;
     }
+
+  reg.private_data = vlib_stats_add_timestamp ("/sys/last_update");
+  reg.entry_index = vlib_stats_add_gauge ("/sys/input_rate");
+  reg.collect_fn = input_rate_collector_fn;
+  vlib_stats_register_collector_fn (&reg);
+
   return 0;
 }
 
diff --git a/src/vnet/interface/stats.c b/src/vnet/interface/stats.c
new file mode 100644 (file)
index 0000000..55e49eb
--- /dev/null
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlib/stats/stats.h>
+#include <vnet/vnet.h>
+#include <vnet/devices/devices.h> /* vnet_get_aggregate_rx_packets */
+#include <vnet/interface.h>
+
+static u32 if_names_stats_entry_index = ~0;
+static u32 **dir_entry_indices = 0;
+
+static struct
+{
+  char *prefix, *name;
+  u32 index;
+} if_counters[] = {
+#define _(e, n, p) { .prefix = #p, .name = #n },
+  foreach_simple_interface_counter_name foreach_combined_interface_counter_name
+#undef _
+};
+
+static clib_error_t *
+statseg_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
+{
+  vlib_stats_segment_t *sm = vlib_stats_get_segment ();
+  vlib_stats_entry_t *e;
+  void *oldheap;
+
+  if (if_names_stats_entry_index == ~0)
+    {
+      if_names_stats_entry_index = vlib_stats_add_string_vector ("/if/names");
+
+      for (int i = 0; i < ARRAY_LEN (if_counters); i++)
+       if_counters[i].index = vlib_stats_find_entry_index (
+         "/%s/%s", if_counters[i].prefix, if_counters[i].name);
+    }
+
+  e = sm->directory_vector + if_names_stats_entry_index;
+
+  vec_validate (dir_entry_indices, sw_if_index);
+
+  vlib_stats_segment_lock ();
+
+  if (is_add)
+    {
+      vnet_sw_interface_t *si, *si_sup;
+      vnet_hw_interface_t *hi_sup;
+      u8 *s;
+
+      si = vnet_get_sw_interface (vnm, sw_if_index);
+      si_sup = vnet_get_sup_sw_interface (vnm, si->sw_if_index);
+      ASSERT (si_sup->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
+      hi_sup = vnet_get_hw_interface (vnm, si_sup->hw_if_index);
+
+      oldheap = clib_mem_set_heap (sm->heap);
+      s = format (0, "%v", hi_sup->name);
+      if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
+       s = format (s, ".%d", si->sub.id);
+      s = format (s, "%c", 0);
+
+      vec_validate (e->string_vector, sw_if_index);
+
+      ASSERT (e->string_vector[sw_if_index] == 0);
+      e->string_vector[sw_if_index] = s;
+      clib_mem_set_heap (oldheap);
+
+      s = format (0, "/interfaces/%U", format_vlib_stats_symlink, s);
+      for (u32 index, i = 0; i < ARRAY_LEN (if_counters); i++)
+       {
+         index = vlib_stats_add_symlink (if_counters[i].index, sw_if_index,
+                                         "%v/%s", s, if_counters[i].name);
+         ASSERT (index != ~0);
+         vec_add1 (dir_entry_indices[sw_if_index], index);
+       }
+      vec_free (s);
+    }
+  else
+    {
+      oldheap = clib_mem_set_heap (sm->heap);
+      vec_free (e->string_vector[sw_if_index]);
+      clib_mem_set_heap (oldheap);
+      for (u32 i = 0; i < vec_len (dir_entry_indices[sw_if_index]); i++)
+       vlib_stats_remove_entry (dir_entry_indices[sw_if_index][i]);
+      vec_free (dir_entry_indices[sw_if_index]);
+    }
+
+  vlib_stats_segment_unlock ();
+
+  return 0;
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (statseg_sw_interface_add_del);
index b0c8391..a5eafaf 100644 (file)
@@ -29,7 +29,8 @@
 #include <vppinfra/vec.h>
 #include <vppinfra/lock.h>
 #include <stdatomic.h>
-#include <vpp/stats/stat_segment.h>
+#include <vlib/vlib.h>
+#include <vlib/stats/stats.h>
 #include <vpp-api/client/stat_client.h>
 
 stat_client_main_t stat_client_main;
@@ -81,8 +82,8 @@ recv_fd (int sock)
   return fd;
 }
 
-static stat_segment_directory_entry_t *
-get_stat_vector_r (stat_client_main_t * sm)
+static vlib_stats_entry_t *
+get_stat_vector_r (stat_client_main_t *sm)
 {
   ASSERT (sm->shared_header);
   return stat_segment_adjust (sm,
@@ -172,7 +173,7 @@ double
 stat_segment_heartbeat_r (stat_client_main_t * sm)
 {
   stat_segment_access_t sa;
-  stat_segment_directory_entry_t *ep;
+  vlib_stats_entry_t *ep;
 
   /* Has directory been updated? */
   if (sm->shared_header->epoch != sm->current_epoch)
@@ -223,7 +224,7 @@ stat_vec_combined_init (vlib_counter_t c)
  * threads), otherwise copy out all values.
  */
 static stat_segment_data_t
-copy_data (stat_segment_directory_entry_t *ep, u32 index2, char *name,
+copy_data (vlib_stats_entry_t *ep, u32 index2, char *name,
           stat_client_main_t *sm)
 {
   stat_segment_data_t result = { 0 };
@@ -297,7 +298,7 @@ copy_data (stat_segment_directory_entry_t *ep, u32 index2, char *name,
     case STAT_DIR_TYPE_SYMLINK:
       /* Gather info from all threads into a vector */
       {
-       stat_segment_directory_entry_t *ep2;
+       vlib_stats_entry_t *ep2;
        ep2 = vec_elt_at_index (sm->directory_vector, ep->index1);
        return copy_data (ep2, ep->index2, ep->name, sm);
       }
@@ -370,7 +371,7 @@ stat_segment_ls_r (uint8_t ** patterns, stat_client_main_t * sm)
   if (stat_segment_access_start (&sa, sm))
     return 0;
 
-  stat_segment_directory_entry_t *counter_vec = get_stat_vector_r (sm);
+  vlib_stats_entry_t *counter_vec = get_stat_vector_r (sm);
   for (j = 0; j < vec_len (counter_vec); j++)
     {
       for (i = 0; i < vec_len (patterns); i++)
@@ -413,7 +414,7 @@ stat_segment_data_t *
 stat_segment_dump_r (uint32_t * stats, stat_client_main_t * sm)
 {
   int i;
-  stat_segment_directory_entry_t *ep;
+  vlib_stats_entry_t *ep;
   stat_segment_data_t *res = 0;
   stat_segment_access_t sa;
 
@@ -474,7 +475,7 @@ stat_segment_string_vector (uint8_t ** string_vector, const char *string)
 stat_segment_data_t *
 stat_segment_dump_entry_r (uint32_t index, stat_client_main_t * sm)
 {
-  stat_segment_directory_entry_t *ep;
+  vlib_stats_entry_t *ep;
   stat_segment_data_t *res = 0;
   stat_segment_access_t sa;
 
@@ -504,9 +505,9 @@ stat_segment_dump_entry (uint32_t index)
 char *
 stat_segment_index_to_name_r (uint32_t index, stat_client_main_t * sm)
 {
-  stat_segment_directory_entry_t *ep;
+  vlib_stats_entry_t *ep;
   stat_segment_access_t sa;
-  stat_segment_directory_entry_t *vec;
+  vlib_stats_entry_t *vec;
 
   /* Has directory been update? */
   if (sm->shared_header->epoch != sm->current_epoch)
index 730badd..2675271 100644 (file)
@@ -25,7 +25,7 @@
 #include <vlib/counter_types.h>
 #include <time.h>
 #include <stdbool.h>
-#include <vpp/stats/stat_segment_shared.h>
+#include <vlib/stats/shared.h>
 
 /* Default socket to exchange segment fd */
 /* TODO: Get from runtime directory */
@@ -49,8 +49,8 @@ typedef struct
 typedef struct
 {
   uint64_t current_epoch;
-  stat_segment_shared_header_t *shared_header;
-  stat_segment_directory_entry_t *directory_vector;
+  vlib_stats_shared_header_t *shared_header;
+  vlib_stats_entry_t *directory_vector;
   ssize_t memory_size;
   uint64_t timeout;
 } stat_client_main_t;
@@ -115,7 +115,7 @@ static inline int
 stat_segment_access_start (stat_segment_access_t * sa,
                           stat_client_main_t * sm)
 {
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
   uint64_t max_time;
 
   sa->epoch = shared_header->epoch;
@@ -130,10 +130,8 @@ stat_segment_access_start (stat_segment_access_t * sa,
       while (shared_header->in_progress != 0)
        ;
     }
-  sm->directory_vector =
-    (stat_segment_directory_entry_t *) stat_segment_adjust (sm,
-                                                           (void *)
-                                                           sm->shared_header->directory_vector);
+  sm->directory_vector = (vlib_stats_entry_t *) stat_segment_adjust (
+    sm, (void *) sm->shared_header->directory_vector);
   if (sm->timeout)
     return _time_now_nsec () < max_time ? 0 : -1;
   return 0;
@@ -164,7 +162,7 @@ stat_segment_set_timeout (uint64_t timeout)
 static inline bool
 stat_segment_access_end (stat_segment_access_t * sa, stat_client_main_t * sm)
 {
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
+  vlib_stats_shared_header_t *shared_header = sm->shared_header;
 
   if (shared_header->epoch != sa->epoch || shared_header->in_progress)
     return false;
index 1b43b12..44c1f6d 100644 (file)
@@ -66,8 +66,6 @@ set(VPP_SOURCES
   vnet/main.c
   app/vpe_cli.c
   app/version.c
-  stats/stat_segment.c
-  stats/stat_segment_provider.c
   api/api.c
   api/json_format.c
   api/types.c
@@ -90,11 +88,6 @@ add_vpp_executable(vpp
   DEPENDS vpp_version_h api_headers
 )
 
-add_vpp_headers(vpp
-  stats/stat_segment.h
-  stats/stat_segment_shared.h
-)
-
 ##############################################################################
 # vppctl binary
 ##############################################################################
diff --git a/src/vpp/stats/stat_segment.c b/src/vpp/stats/stat_segment.c
deleted file mode 100644 (file)
index 3ab60b9..0000000
+++ /dev/null
@@ -1,1149 +0,0 @@
-/*
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vppinfra/mem.h>
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include "stat_segment.h"
-#include <vnet/vnet.h>
-#include <vnet/devices/devices.h>      /* vnet_get_aggregate_rx_packets */
-#include <vpp-api/client/stat_client.h>
-
-stat_segment_main_t stat_segment_main;
-#define STATSEG_MAX_NAMESZ 128
-
-/*
- *  Used only by VPP writers
- */
-void
-vlib_stat_segment_lock (void)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  clib_spinlock_lock (sm->stat_segment_lockp);
-  sm->shared_header->in_progress = 1;
-}
-
-void
-vlib_stat_segment_unlock (void)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  sm->shared_header->epoch++;
-  sm->shared_header->in_progress = 0;
-  clib_spinlock_unlock (sm->stat_segment_lockp);
-}
-
-/*
- * Change heap to the stats shared memory segment
- */
-void *
-vlib_stats_push_heap (void *old)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-
-  sm->last = old;
-  ASSERT (sm && sm->shared_header);
-  return clib_mem_set_heap (sm->heap);
-}
-
-static u32
-lookup_hash_index (u8 * name)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  u32 index = STAT_SEGMENT_INDEX_INVALID;
-  hash_pair_t *hp;
-
-  /* Must be called in the context of the main heap */
-  ASSERT (clib_mem_get_heap () != sm->heap);
-
-  hp = hash_get_pair (sm->directory_vector_by_name, name);
-  if (hp)
-    {
-      index = hp->value[0];
-    }
-
-  return index;
-}
-
-static u32
-vlib_stats_get_next_vector_index ()
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  u32 next_vector_index = vec_len (sm->directory_vector);
-
-  ssize_t i;
-  vec_foreach_index_backwards (i, sm->directory_vector)
-  {
-    if (sm->directory_vector[i].type == STAT_DIR_TYPE_EMPTY)
-      {
-       next_vector_index = i;
-       break;
-      }
-  }
-
-  return next_vector_index;
-}
-
-/*
- * Wrapper functions that copies the key. Hash function is on the main heap.
- */
-static void
-hash_set_str_key_alloc (uword **h, const char *key, uword v)
-{
-  int size = strlen (key) + 1;
-  void *copy = clib_mem_alloc (size);
-  clib_memcpy_fast (copy, key, size);
-  hash_set_mem (*h, copy, v);
-}
-
-static void
-hash_unset_str_key_free (uword **h, const char *key)
-{
-  hash_pair_t *hp = hash_get_pair_mem (*h, key);
-  if (hp)
-    {
-      void *_k = uword_to_pointer (hp->key, void *);
-      hash_unset_mem (*h, _k);
-      clib_mem_free (_k);
-    }
-}
-
-static u32
-vlib_stats_create_counter (stat_segment_directory_entry_t * e, void *oldheap)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-
-  ASSERT (clib_mem_get_heap () == sm->heap);
-
-  u32 index = vlib_stats_get_next_vector_index ();
-  vec_validate (sm->directory_vector, index);
-  sm->directory_vector[index] = *e;
-
-  clib_mem_set_heap (oldheap);
-  hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
-  clib_mem_set_heap (sm->heap);
-
-  return index;
-}
-
-static void
-vlib_stats_delete_counter (u32 index, void *oldheap)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_directory_entry_t *e;
-
-  ASSERT (clib_mem_get_heap () == sm->heap);
-
-  if (index > vec_len (sm->directory_vector))
-    return;
-
-  e = &sm->directory_vector[index];
-
-  clib_mem_set_heap (oldheap);
-  hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
-  clib_mem_set_heap (sm->heap);
-
-  memset (e, 0, sizeof (*e));
-  e->type = STAT_DIR_TYPE_EMPTY;
-}
-
-/*
- * Called from main heap
- */
-void
-vlib_stats_delete_cm (void *cm_arg)
-{
-  vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_directory_entry_t *e;
-
-  /* Not all counters have names / hash-table entries */
-  if (!cm->name && !cm->stat_segment_name)
-    {
-      return;
-    }
-  vlib_stat_segment_lock ();
-
-  /* Lookup hash-table is on the main heap */
-  char *stat_segment_name =
-    cm->stat_segment_name ? cm->stat_segment_name : cm->name;
-  u32 index = lookup_hash_index ((u8 *) stat_segment_name);
-
-  e = &sm->directory_vector[index];
-  hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
-
-  void *oldheap = clib_mem_set_heap (sm->heap);        /* Enter stats segment */
-  clib_mem_set_heap (oldheap); /* Exit stats segment */
-
-  memset (e, 0, sizeof (*e));
-  e->type = STAT_DIR_TYPE_EMPTY;
-
-  vlib_stat_segment_unlock ();
-}
-
-void
-vlib_stats_pop_heap (void *cm_arg, void *oldheap, u32 cindex,
-                    stat_directory_type_t type)
-{
-  vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
-  char *stat_segment_name;
-  stat_segment_directory_entry_t e = { 0 };
-
-  /* Not all counters have names / hash-table entries */
-  if (!cm->name && !cm->stat_segment_name)
-    {
-      clib_mem_set_heap (oldheap);
-      return;
-    }
-
-  ASSERT (shared_header);
-
-  vlib_stat_segment_lock ();
-
-  /* Lookup hash-table is on the main heap */
-  stat_segment_name =
-    cm->stat_segment_name ? cm->stat_segment_name : cm->name;
-
-  clib_mem_set_heap (oldheap); /* Exit stats segment */
-  u32 vector_index = lookup_hash_index ((u8 *) stat_segment_name);
-  /* Back to stats segment */
-  clib_mem_set_heap (sm->heap);        /* Re-enter stat segment */
-
-
-  /* Update the vector */
-  if (vector_index == STAT_SEGMENT_INDEX_INVALID)
-    {                          /* New */
-      strncpy_s (e.name, STATSEG_MAX_NAMESZ, stat_segment_name,
-                STATSEG_MAX_NAMESZ - 1);
-      e.type = type;
-      vector_index = vlib_stats_create_counter (&e, oldheap);
-    }
-
-  stat_segment_directory_entry_t *ep = &sm->directory_vector[vector_index];
-  ep->data = cm->counters;
-
-  /* Reset the client hash table pointer, since it WILL change! */
-  shared_header->directory_vector = sm->directory_vector;
-
-  vlib_stat_segment_unlock ();
-  clib_mem_set_heap (oldheap);
-}
-
-u8 *
-format_vlib_stats_symlink (u8 *s, va_list *args)
-{
-  char *input = va_arg (*args, char *);
-  char *modified_input = vec_dup (input);
-  int i;
-  u8 *result;
-
-  for (i = 0; i < strlen (modified_input); i++)
-    if (modified_input[i] == '/')
-      modified_input[i] = '_';
-
-  result = format (s, "%s", modified_input);
-  vec_free (modified_input);
-  return result;
-}
-
-void
-vlib_stats_register_symlink (void *oldheap, u8 *name, u32 index1, u32 index2,
-                            u8 lock)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
-  stat_segment_directory_entry_t e;
-
-  ASSERT (shared_header);
-
-  if (lock)
-    vlib_stat_segment_lock ();
-  clib_mem_set_heap (oldheap); /* Exit stats segment */
-  u32 vector_index = lookup_hash_index (name);
-  /* Back to stats segment */
-  clib_mem_set_heap (sm->heap); /* Re-enter stat segment */
-
-  if (vector_index == STAT_SEGMENT_INDEX_INVALID)
-    {
-      strncpy_s (e.name, STATSEG_MAX_NAMESZ, (char *) name,
-                STATSEG_MAX_NAMESZ - 1);
-      e.type = STAT_DIR_TYPE_SYMLINK;
-      e.index1 = index1;
-      e.index2 = index2;
-      vector_index = vlib_stats_create_counter (&e, oldheap);
-
-      /* Warn clients to refresh any pointers they might be holding */
-      shared_header->directory_vector = sm->directory_vector;
-    }
-
-  if (lock)
-    vlib_stat_segment_unlock ();
-}
-
-void
-vlib_stats_rename_symlink (void *oldheap, u64 index, u8 *new_name)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_directory_entry_t *e;
-
-  ASSERT (clib_mem_get_heap () == sm->heap);
-  ASSERT (index < vec_len (sm->directory_vector));
-  if (index > vec_len (sm->directory_vector))
-    return;
-
-  e = &sm->directory_vector[index];
-
-  clib_mem_set_heap (oldheap);
-  hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
-  clib_mem_set_heap (sm->heap);
-
-  strncpy_s (e->name, STATSEG_MAX_NAMESZ, (char *) new_name,
-            STATSEG_MAX_NAMESZ - 1);
-  clib_mem_set_heap (oldheap);
-  hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
-  clib_mem_set_heap (sm->heap);
-}
-
-void
-vlib_stats_register_error_index (void *oldheap, u8 * name, u64 * em_vec,
-                                u64 index)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
-  stat_segment_directory_entry_t e;
-
-  ASSERT (shared_header);
-
-  vlib_stat_segment_lock ();
-  clib_mem_set_heap (oldheap); /* Exit stats segment */
-  u32 vector_index = lookup_hash_index (name);
-  /* Back to stats segment */
-  clib_mem_set_heap (sm->heap);        /* Re-enter stat segment */
-
-  if (vector_index == STAT_SEGMENT_INDEX_INVALID)
-    {
-      memcpy (e.name, name, vec_len (name));
-      e.name[vec_len (name)] = '\0';
-      e.type = STAT_DIR_TYPE_ERROR_INDEX;
-      e.index = index;
-      vector_index = vlib_stats_create_counter (&e, oldheap);
-
-      /* Warn clients to refresh any pointers they might be holding */
-      shared_header->directory_vector = sm->directory_vector;
-    }
-
-  vlib_stat_segment_unlock ();
-}
-
-/*
- * Creates a two dimensional vector with the maximum valid index specified in
- * both dimensions as arguments.
- * Must be called on the stat segment heap.
- */
-static void
-stat_validate_counter_vector2 (stat_segment_directory_entry_t *ep, u32 max1,
-                              u32 max2)
-{
-  counter_t **counters = ep->data;
-  int i;
-  vec_validate_aligned (counters, max1, CLIB_CACHE_LINE_BYTES);
-  for (i = 0; i <= max1; i++)
-    vec_validate_aligned (counters[i], max2, CLIB_CACHE_LINE_BYTES);
-
-  ep->data = counters;
-}
-
-static void
-stat_validate_counter_vector (stat_segment_directory_entry_t *ep, u32 max)
-{
-  vlib_thread_main_t *tm = vlib_get_thread_main ();
-  ASSERT (tm->n_vlib_mains > 0);
-  stat_validate_counter_vector2 (ep, tm->n_vlib_mains, max);
-}
-
-void
-vlib_stats_pop_heap2 (u64 * error_vector, u32 thread_index, void *oldheap,
-                     int lock)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
-
-  ASSERT (shared_header);
-
-  if (lock)
-    vlib_stat_segment_lock ();
-
-  /* Reset the client hash table pointer, since it WILL change! */
-  vec_validate (sm->error_vector, thread_index);
-  sm->error_vector[thread_index] = error_vector;
-
-  shared_header->error_vector = sm->error_vector;
-  shared_header->directory_vector = sm->directory_vector;
-
-  if (lock)
-    vlib_stat_segment_unlock ();
-  clib_mem_set_heap (oldheap);
-}
-
-/*
- * Create a new entry and add name to directory hash.
- * Returns ~0 if name exists.
- * Called from main heap.
- * The name is either C-string or nul-terminated vector
- */
-u32
-stat_segment_new_entry (u8 *name, stat_directory_type_t t)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
-  void *oldheap;
-  stat_segment_directory_entry_t e;
-
-  ASSERT (shared_header);
-
-  u32 vector_index = lookup_hash_index (name);
-  if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
-    return ~0;
-
-  memset (&e, 0, sizeof (e));
-  e.type = t;
-  // TODO, check length
-  strcpy_s (e.name, sizeof (e.name), (char *) name);
-
-  oldheap = vlib_stats_push_heap (NULL);
-  vlib_stat_segment_lock ();
-  vector_index = vlib_stats_create_counter (&e, oldheap);
-
-  shared_header->directory_vector = sm->directory_vector;
-
-  vlib_stat_segment_unlock ();
-  clib_mem_set_heap (oldheap);
-
-  return vector_index;
-}
-
-clib_error_t *
-vlib_map_stat_segment_init (void)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header;
-  void *oldheap;
-  uword memory_size, sys_page_sz;
-  int mfd;
-  char *mem_name = "stat segment";
-  void *heap, *memaddr;
-
-  memory_size = sm->memory_size;
-  if (memory_size == 0)
-    memory_size = STAT_SEGMENT_DEFAULT_SIZE;
-
-  if (sm->log2_page_sz == CLIB_MEM_PAGE_SZ_UNKNOWN)
-    sm->log2_page_sz = CLIB_MEM_PAGE_SZ_DEFAULT;
-
-  mfd = clib_mem_vm_create_fd (sm->log2_page_sz, mem_name);
-
-  if (mfd == -1)
-    return clib_error_return (0, "stat segment memory fd failure: %U",
-                             format_clib_error, clib_mem_get_last_error ());
-  /* Set size */
-  if ((ftruncate (mfd, memory_size)) == -1)
-    {
-      close (mfd);
-      return clib_error_return (0, "stat segment ftruncate failure");
-    }
-
-  memaddr = clib_mem_vm_map_shared (0, memory_size, mfd, 0, mem_name);
-
-  if (memaddr == CLIB_MEM_VM_MAP_FAILED)
-    return clib_error_return (0, "stat segment mmap failure");
-
-  sys_page_sz = clib_mem_get_page_size ();
-
-  heap =
-    clib_mem_create_heap (((u8 *) memaddr) + sys_page_sz,
-                         memory_size - sys_page_sz, 1 /* locked */, mem_name);
-  sm->heap = heap;
-  sm->memfd = mfd;
-
-  sm->directory_vector_by_name = hash_create_string (0, sizeof (uword));
-  sm->shared_header = shared_header = memaddr;
-
-  shared_header->version = STAT_SEGMENT_VERSION;
-  shared_header->base = memaddr;
-
-  sm->stat_segment_lockp = clib_mem_alloc (sizeof (clib_spinlock_t));
-  clib_spinlock_init (sm->stat_segment_lockp);
-
-  oldheap = clib_mem_set_heap (sm->heap);
-
-  /* Set up the name to counter-vector hash table */
-  sm->directory_vector = 0;
-
-  shared_header->epoch = 1;
-
-  /* Scalar stats and node counters */
-  vec_validate (sm->directory_vector, STAT_COUNTERS - 1);
-#define _(E,t,n,p)                                                     \
-  strcpy(sm->directory_vector[STAT_COUNTER_##E].name,  #p "/" #n); \
-  sm->directory_vector[STAT_COUNTER_##E].type = STAT_DIR_TYPE_##t;
-  foreach_stat_segment_counter_name
-#undef _
-    /* Save the vector in the shared segment, for clients */
-    shared_header->directory_vector = sm->directory_vector;
-
-  clib_mem_set_heap (oldheap);
-
-  vlib_stats_register_mem_heap (heap);
-
-  return 0;
-}
-
-static int
-name_sort_cmp (void *a1, void *a2)
-{
-  stat_segment_directory_entry_t *n1 = a1;
-  stat_segment_directory_entry_t *n2 = a2;
-
-  return strcmp ((char *) n1->name, (char *) n2->name);
-}
-
-static u8 *
-format_stat_dir_entry (u8 * s, va_list * args)
-{
-  stat_segment_directory_entry_t *ep =
-    va_arg (*args, stat_segment_directory_entry_t *);
-  char *type_name;
-  char *format_string;
-
-  format_string = "%-74s %-10s %10lld";
-
-  switch (ep->type)
-    {
-    case STAT_DIR_TYPE_SCALAR_INDEX:
-      type_name = "ScalarPtr";
-      break;
-
-    case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
-    case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
-      type_name = "CMainPtr";
-      break;
-
-    case STAT_DIR_TYPE_ERROR_INDEX:
-      type_name = "ErrIndex";
-      break;
-
-    case STAT_DIR_TYPE_NAME_VECTOR:
-      type_name = "NameVector";
-      break;
-
-    case STAT_DIR_TYPE_EMPTY:
-      type_name = "empty";
-      break;
-
-    case STAT_DIR_TYPE_SYMLINK:
-      type_name = "Symlink";
-      break;
-
-    default:
-      type_name = "illegal!";
-      break;
-    }
-
-  return format (s, format_string, ep->name, type_name, 0);
-}
-
-static clib_error_t *
-show_stat_segment_command_fn (vlib_main_t * vm,
-                             unformat_input_t * input,
-                             vlib_cli_command_t * cmd)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_directory_entry_t *show_data;
-  int i;
-
-  int verbose = 0;
-
-  if (unformat (input, "verbose"))
-    verbose = 1;
-
-  /* Lock even as reader, as this command doesn't handle epoch changes */
-  vlib_stat_segment_lock ();
-  show_data = vec_dup (sm->directory_vector);
-  vlib_stat_segment_unlock ();
-
-  vec_sort_with_function (show_data, name_sort_cmp);
-
-  vlib_cli_output (vm, "%-74s %10s %10s", "Name", "Type", "Value");
-
-  for (i = 0; i < vec_len (show_data); i++)
-    {
-      stat_segment_directory_entry_t *ep = vec_elt_at_index (show_data, i);
-
-      if (ep->type == STAT_DIR_TYPE_EMPTY)
-       continue;
-
-      vlib_cli_output (vm, "%-100U", format_stat_dir_entry,
-                      vec_elt_at_index (show_data, i));
-    }
-
-  if (verbose)
-    {
-      ASSERT (sm->heap);
-      vlib_cli_output (vm, "%U", format_clib_mem_heap, sm->heap,
-                      0 /* verbose */ );
-    }
-
-  return 0;
-}
-
-static clib_error_t *
-show_stat_segment_hash_command_fn (vlib_main_t *vm, unformat_input_t *input,
-                                  vlib_cli_command_t *cmd)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  char *name;
-  u32 i;
-  hash_foreach_mem (name, i, sm->directory_vector_by_name,
-                   ({ vlib_cli_output (vm, "%d: %s\n", i, name); }));
-  return 0;
-}
-
-VLIB_CLI_COMMAND (show_stat_segment_hash_command, static) = {
-  .path = "show statistics hash",
-  .short_help = "show statistics hash",
-  .function = show_stat_segment_hash_command_fn,
-};
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_stat_segment_command, static) =
-{
-  .path = "show statistics segment",
-  .short_help = "show statistics segment [verbose]",
-  .function = show_stat_segment_command_fn,
-};
-/* *INDENT-ON* */
-
-/*
- * Node performance counters:
- * total_calls [threads][node-index]
- * total_vectors
- * total_calls
- * total suspends
- */
-
-static inline void
-update_node_counters (stat_segment_main_t * sm)
-{
-  vlib_main_t **stat_vms = 0;
-  vlib_node_t ***node_dups = 0;
-  int i, j;
-  static u32 no_max_nodes = 0;
-
-  vlib_node_get_nodes (0 /* vm, for barrier sync */,
-                      (u32) ~0 /* all threads */, 1 /* include stats */,
-                      0 /* barrier sync */, &node_dups, &stat_vms);
-
-  u32 l = vec_len (node_dups[0]);
-  u8 *symlink_name = 0;
-
-  /*
-   * Extend performance nodes if necessary
-   */
-  if (l > no_max_nodes)
-    {
-      void *oldheap = clib_mem_set_heap (sm->heap);
-      vlib_stat_segment_lock ();
-
-      stat_validate_counter_vector (
-       &sm->directory_vector[STAT_COUNTER_NODE_CLOCKS], l - 1);
-      stat_validate_counter_vector (
-       &sm->directory_vector[STAT_COUNTER_NODE_VECTORS], l - 1);
-      stat_validate_counter_vector (
-       &sm->directory_vector[STAT_COUNTER_NODE_CALLS], l - 1);
-      stat_validate_counter_vector (
-       &sm->directory_vector[STAT_COUNTER_NODE_SUSPENDS], l - 1);
-
-      vec_validate (sm->nodes, l - 1);
-      stat_segment_directory_entry_t *ep;
-      ep = &sm->directory_vector[STAT_COUNTER_NODE_NAMES];
-      ep->data = sm->nodes;
-
-      /* Update names dictionary */
-      vlib_node_t **nodes = node_dups[0];
-      int i;
-      for (i = 0; i < vec_len (nodes); i++)
-       {
-         vlib_node_t *n = nodes[i];
-         u8 *s = format (0, "%v%c", n->name, 0);
-         if (sm->nodes[n->index])
-           vec_free (sm->nodes[n->index]);
-         sm->nodes[n->index] = s;
-
-#define _(E, t, name, p)                                                      \
-  vec_reset_length (symlink_name);                                            \
-  symlink_name = format (symlink_name, "/nodes/%U/" #name "%c",               \
-                        format_vlib_stats_symlink, s, 0);                    \
-  vlib_stats_register_symlink (oldheap, symlink_name, STAT_COUNTER_##E,       \
-                              n->index, 0 /* don't lock */);
-         foreach_stat_segment_node_counter_name
-#undef _
-       }
-
-      vec_free (symlink_name);
-      vlib_stat_segment_unlock ();
-      clib_mem_set_heap (oldheap);
-      no_max_nodes = l;
-    }
-
-  for (j = 0; j < vec_len (node_dups); j++)
-    {
-      vlib_node_t **nodes = node_dups[j];
-
-      for (i = 0; i < vec_len (nodes); i++)
-       {
-         counter_t **counters;
-         counter_t *c;
-         vlib_node_t *n = nodes[i];
-
-         if (j == 0)
-           {
-             if (strncmp ((char *) sm->nodes[n->index], (char *) n->name,
-                          strlen ((char *) sm->nodes[n->index])))
-               {
-                 u32 vector_index;
-                 u8 *symlink_new_name = 0;
-                 void *oldheap = clib_mem_set_heap (sm->heap);
-                 vlib_stat_segment_lock ();
-                 u8 *s = format (0, "%v%c", n->name, 0);
-#define _(E, t, name, p)                                                      \
-  vec_reset_length (symlink_name);                                            \
-  symlink_name = format (symlink_name, "/nodes/%U/" #name "%c",               \
-                        format_vlib_stats_symlink, sm->nodes[n->index], 0);  \
-  clib_mem_set_heap (oldheap); /* Exit stats segment */                       \
-  vector_index = lookup_hash_index ((u8 *) symlink_name);                     \
-  ASSERT (vector_index != -1);                                                \
-  clib_mem_set_heap (sm->heap); /* Re-enter stat segment */                   \
-  vec_reset_length (symlink_new_name);                                        \
-  symlink_new_name = format (symlink_new_name, "/nodes/%U/" #name "%c",       \
-                            format_vlib_stats_symlink, s, 0);                \
-  vlib_stats_rename_symlink (oldheap, vector_index, symlink_new_name);
-                 foreach_stat_segment_node_counter_name
-#undef _
-                   vec_free (symlink_name);
-                 vec_free (symlink_new_name);
-                 vec_free (sm->nodes[n->index]);
-                 sm->nodes[n->index] = s;
-                 vlib_stat_segment_unlock ();
-                 clib_mem_set_heap (oldheap);
-               }
-           }
-
-         counters = sm->directory_vector[STAT_COUNTER_NODE_CLOCKS].data;
-         c = counters[j];
-         c[n->index] = n->stats_total.clocks - n->stats_last_clear.clocks;
-
-         counters = sm->directory_vector[STAT_COUNTER_NODE_VECTORS].data;
-         c = counters[j];
-         c[n->index] = n->stats_total.vectors - n->stats_last_clear.vectors;
-
-         counters = sm->directory_vector[STAT_COUNTER_NODE_CALLS].data;
-         c = counters[j];
-         c[n->index] = n->stats_total.calls - n->stats_last_clear.calls;
-
-         counters = sm->directory_vector[STAT_COUNTER_NODE_SUSPENDS].data;
-         c = counters[j];
-         c[n->index] = n->stats_total.suspends - n->stats_last_clear.suspends;
-       }
-      vec_free (node_dups[j]);
-    }
-  vec_free (node_dups);
-  vec_free (stat_vms);
-}
-
-static void
-do_stat_segment_updates (vlib_main_t *vm, stat_segment_main_t *sm)
-{
-  u64 input_packets;
-  f64 dt, now;
-  static int num_worker_threads_set;
-
-  /*
-   * Set once at the beginning of time.
-   * Can't do this from the init routine, which happens before
-   * start_workers sets up vlib_mains...
-   */
-  if (PREDICT_FALSE (num_worker_threads_set == 0))
-    {
-      vlib_thread_main_t *tm = vlib_get_thread_main ();
-      ASSERT (tm->n_vlib_mains > 0);
-      stat_provider_register_vector_rate (tm->n_vlib_mains - 1);
-      sm->directory_vector[STAT_COUNTER_NUM_WORKER_THREADS].value =
-       tm->n_vlib_mains - 1;
-      num_worker_threads_set = 1;
-    }
-
-  /*
-   * Compute the aggregate input rate
-   */
-  now = vlib_time_now (vm);
-  dt = now - sm->directory_vector[STAT_COUNTER_LAST_UPDATE].value;
-  input_packets = vnet_get_aggregate_rx_packets ();
-  sm->directory_vector[STAT_COUNTER_INPUT_RATE].value =
-    (f64) (input_packets - sm->last_input_packets) / dt;
-  sm->directory_vector[STAT_COUNTER_LAST_UPDATE].value = now;
-  sm->last_input_packets = input_packets;
-  sm->directory_vector[STAT_COUNTER_LAST_STATS_CLEAR].value =
-    vm->node_main.time_last_runtime_stats_clear;
-
-  if (sm->node_counters_enabled)
-    update_node_counters (sm);
-
-  /* *INDENT-OFF* */
-  stat_segment_gauges_pool_t *g;
-  pool_foreach (g, sm->gauges)
-    {
-      g->fn (&sm->directory_vector[g->directory_index], g->caller_index);
-    }
-  /* *INDENT-ON* */
-
-  /* Heartbeat, so clients detect we're still here */
-  sm->directory_vector[STAT_COUNTER_HEARTBEAT].value++;
-}
-
-/*
- * Accept connection on the socket and exchange the fd for the shared
- * memory segment.
- */
-static clib_error_t *
-stats_socket_accept_ready (clib_file_t * uf)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  clib_error_t *err;
-  clib_socket_t client = { 0 };
-
-  err = clib_socket_accept (sm->socket, &client);
-  if (err)
-    {
-      clib_error_report (err);
-      return err;
-    }
-
-  /* Send the fd across and close */
-  err = clib_socket_sendmsg (&client, 0, 0, &sm->memfd, 1);
-  if (err)
-    clib_error_report (err);
-  clib_socket_close (&client);
-
-  return 0;
-}
-
-static clib_error_t *
-stats_segment_socket_init (void)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  clib_error_t *error;
-  clib_socket_t *s = clib_mem_alloc (sizeof (clib_socket_t));
-
-  memset (s, 0, sizeof (clib_socket_t));
-  s->config = (char *) sm->socket_name;
-  s->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_SEQPACKET |
-    CLIB_SOCKET_F_ALLOW_GROUP_WRITE | CLIB_SOCKET_F_PASSCRED;
-
-  if ((error = clib_socket_init (s)))
-    return error;
-
-  clib_file_t template = { 0 };
-  template.read_function = stats_socket_accept_ready;
-  template.file_descriptor = s->fd;
-  template.description = format (0, "stats segment listener %s", s->config);
-  clib_file_add (&file_main, &template);
-
-  sm->socket = s;
-
-  return 0;
-}
-
-static clib_error_t *
-stats_segment_socket_exit (vlib_main_t * vm)
-{
-  /*
-   * cleanup the listener socket on exit.
-   */
-  stat_segment_main_t *sm = &stat_segment_main;
-  unlink ((char *) sm->socket_name);
-  return 0;
-}
-
-VLIB_MAIN_LOOP_EXIT_FUNCTION (stats_segment_socket_exit);
-
-/* Overrides weak reference in vlib:node_cli.c */
-f64
-vlib_get_stat_segment_update_rate (void)
-{
-  return stat_segment_main.update_interval;
-}
-
-static uword
-stat_segment_collector_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
-                               vlib_frame_t * f)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-
-  while (1)
-    {
-      do_stat_segment_updates (vm, sm);
-      vlib_process_suspend (vm, sm->update_interval);
-    }
-  return 0;                    /* or not */
-}
-
-/*
- * Add a data provider (via callback) for a given stats entry.
- * TODO: Add support for per-provider interval.
- */
-void
-stat_segment_poll_add (u32 vector_index, stat_segment_update_fn update_fn,
-                      u32 caller_index, u32 interval)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_gauges_pool_t *gauge;
-
-  pool_get (sm->gauges, gauge);
-  gauge->fn = update_fn;
-  gauge->caller_index = caller_index;
-  gauge->directory_index = vector_index;
-
-  return;
-}
-
-/*
- * Create an scalar entry with a data provider.
- * Deprecated, replace with stat_segment_new_entry + stat_segment_pool_add
- */
-clib_error_t *
-stat_segment_register_gauge (u8 *name, stat_segment_update_fn update_fn,
-                            u32 caller_index)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_gauges_pool_t *gauge;
-
-  u32 vector_index = stat_segment_new_entry (name, STAT_DIR_TYPE_SCALAR_INDEX);
-  if (vector_index == ~0) /* Already registered */
-    return clib_error_return (0, "%v is already registered", name);
-
-  pool_get (sm->gauges, gauge);
-  gauge->fn = update_fn;
-  gauge->caller_index = caller_index;
-  gauge->directory_index = vector_index;
-
-  return NULL;
-}
-
-clib_error_t *
-stat_segment_register_state_counter (u8 * name, u32 * index)
-{
-  ASSERT (vlib_get_thread_index () == 0);
-
-  u32 vector_index = stat_segment_new_entry (name, STAT_DIR_TYPE_SCALAR_INDEX);
-  if (vector_index == ~0) /* Already registered */
-    return clib_error_return (0, "%v is already registered", name);
-  *index = vector_index;
-  return 0;
-}
-
-clib_error_t *
-stat_segment_deregister_state_counter (u32 index)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  stat_segment_shared_header_t *shared_header = sm->shared_header;
-  stat_segment_directory_entry_t *e;
-  void *oldheap;
-
-  ASSERT (shared_header);
-
-  if (index > vec_len (sm->directory_vector))
-    return clib_error_return (0, "%u index does not exist", index);
-
-  e = &sm->directory_vector[index];
-  if (e->type != STAT_DIR_TYPE_SCALAR_INDEX)
-    return clib_error_return (0, "%u index cannot be deleted", index);
-
-  oldheap = vlib_stats_push_heap (NULL);
-  vlib_stat_segment_lock ();
-
-  vlib_stats_delete_counter (index, oldheap);
-
-  vlib_stat_segment_unlock ();
-  clib_mem_set_heap (oldheap);
-
-  return 0;
-}
-
-void
-stat_segment_set_state_counter (u32 index, u64 value)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-
-  ASSERT (index < vec_len (sm->directory_vector));
-  sm->directory_vector[index].index = value;
-}
-
-static clib_error_t *
-statseg_config (vlib_main_t * vm, unformat_input_t * input)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  sm->update_interval = 10.0;
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "socket-name %s", &sm->socket_name))
-       ;
-      /* DEPRECATE: default (does nothing) */
-      else if (unformat (input, "default"))
-       ;
-      else if (unformat (input, "size %U",
-                        unformat_memory_size, &sm->memory_size))
-       ;
-      else if (unformat (input, "page-size %U",
-                        unformat_log2_page_size, &sm->log2_page_sz))
-       ;
-      else if (unformat (input, "per-node-counters on"))
-       sm->node_counters_enabled = 1;
-      else if (unformat (input, "per-node-counters off"))
-       sm->node_counters_enabled = 0;
-      else if (unformat (input, "update-interval %f", &sm->update_interval))
-       ;
-      else
-       return clib_error_return (0, "unknown input `%U'",
-                                 format_unformat_error, input);
-    }
-
-  /*
-   * NULL-terminate socket name string
-   * clib_socket_init()->socket_config() use C str*
-   */
-  if (vec_len (sm->socket_name))
-    vec_terminate_c_string (sm->socket_name);
-
-  return 0;
-}
-
-VLIB_EARLY_CONFIG_FUNCTION (statseg_config, "statseg");
-
-static clib_error_t *
-statseg_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
-  vnet_sw_interface_t *si_sup =
-    vnet_get_sup_sw_interface (vnm, si->sw_if_index);
-  vnet_hw_interface_t *hi_sup;
-  u8 *s;
-  u8 *symlink_name = 0;
-  u32 vector_index;
-
-  void *oldheap = vlib_stats_push_heap (sm->interfaces);
-  vlib_stat_segment_lock ();
-
-  vec_validate (sm->interfaces, sw_if_index);
-
-  ASSERT (si_sup->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
-  hi_sup = vnet_get_hw_interface (vnm, si_sup->hw_if_index);
-
-  s = format (0, "%v", hi_sup->name);
-  if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
-    s = format (s, ".%d", si->sub.id);
-  s = format (s, "%c", 0);
-
-  if (is_add)
-    {
-      sm->interfaces[sw_if_index] = s;
-#define _(E, n, p)                                                            \
-  clib_mem_set_heap (oldheap); /* Exit stats segment */                       \
-  vector_index = lookup_hash_index ((u8 *) "/" #p "/" #n);                    \
-  clib_mem_set_heap (sm->heap); /* Re-enter stat segment */                   \
-  vec_reset_length (symlink_name);                                            \
-  symlink_name = format (symlink_name, "/interfaces/%U/" #n "%c",             \
-                        format_vlib_stats_symlink, s, 0);                    \
-  vlib_stats_register_symlink (oldheap, symlink_name, vector_index,           \
-                              sw_if_index, 0 /* don't lock */);
-      foreach_simple_interface_counter_name
-       foreach_combined_interface_counter_name
-#undef _
-         vec_free (symlink_name);
-    }
-  else
-    {
-      vec_free (sm->interfaces[sw_if_index]);
-      sm->interfaces[sw_if_index] = 0;
-#define _(E, n, p)                                                            \
-  vec_reset_length (symlink_name);                                            \
-  symlink_name = format (symlink_name, "/interfaces/%U/" #n "%c",             \
-                        format_vlib_stats_symlink, s, 0);                    \
-  clib_mem_set_heap (oldheap); /* Exit stats segment */                       \
-  vector_index = lookup_hash_index ((u8 *) symlink_name);                     \
-  clib_mem_set_heap (sm->heap); /* Re-enter stat segment */                   \
-  vlib_stats_delete_counter (vector_index, oldheap);
-      foreach_simple_interface_counter_name
-       foreach_combined_interface_counter_name
-#undef _
-
-         vec_free (symlink_name);
-      vec_free (s);
-    }
-
-  stat_segment_directory_entry_t *ep;
-  ep = &sm->directory_vector[STAT_COUNTER_INTERFACE_NAMES];
-  ep->data = sm->interfaces;
-
-  vlib_stat_segment_unlock ();
-  clib_mem_set_heap (oldheap);
-
-  return 0;
-}
-
-VNET_SW_INTERFACE_ADD_DEL_FUNCTION (statseg_sw_interface_add_del);
-
-VLIB_REGISTER_NODE (stat_segment_collector, static) =
-{
-.function = stat_segment_collector_process,
-.name = "statseg-collector-process",
-.type = VLIB_NODE_TYPE_PROCESS,
-};
-
-static clib_error_t *
-statseg_init (vlib_main_t *vm)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-
-  /* set default socket file name when statseg config stanza is empty. */
-  if (!vec_len (sm->socket_name))
-    sm->socket_name = format (0, "%s/%s%c", vlib_unix_get_runtime_dir (),
-                             STAT_SEGMENT_SOCKET_FILENAME, 0);
-  return stats_segment_socket_init ();
-}
-
-VLIB_INIT_FUNCTION (statseg_init) = {
-  .runs_after = VLIB_INITS ("unix_input_init"),
-};
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/vpp/stats/stat_segment.h b/src/vpp/stats/stat_segment.h
deleted file mode 100644 (file)
index f5862a6..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef included_stat_segment_h
-#define included_stat_segment_h
-
-#include <vlib/vlib.h>
-#include <vppinfra/socket.h>
-#include <vpp/stats/stat_segment_shared.h>
-
-typedef enum
-{
-  STAT_COUNTER_NUM_WORKER_THREADS = 0,
-  STAT_COUNTER_INPUT_RATE,
-  STAT_COUNTER_LAST_UPDATE,
-  STAT_COUNTER_LAST_STATS_CLEAR,
-  STAT_COUNTER_HEARTBEAT,
-  STAT_COUNTER_NODE_CLOCKS,
-  STAT_COUNTER_NODE_VECTORS,
-  STAT_COUNTER_NODE_CALLS,
-  STAT_COUNTER_NODE_SUSPENDS,
-  STAT_COUNTER_INTERFACE_NAMES,
-  STAT_COUNTER_NODE_NAMES,
-  STAT_COUNTERS
-} stat_segment_counter_t;
-
-/* clang-format off */
-#define foreach_stat_segment_node_counter_name                                \
-  _ (NODE_CLOCKS, COUNTER_VECTOR_SIMPLE, clocks, /sys/node)                   \
-  _ (NODE_VECTORS, COUNTER_VECTOR_SIMPLE, vectors, /sys/node)                 \
-  _ (NODE_CALLS, COUNTER_VECTOR_SIMPLE, calls, /sys/node)                     \
-  _ (NODE_SUSPENDS, COUNTER_VECTOR_SIMPLE, suspends, /sys/node)
-
-#define foreach_stat_segment_counter_name                                     \
-  _ (NUM_WORKER_THREADS, SCALAR_INDEX, num_worker_threads, /sys)              \
-  _ (INPUT_RATE, SCALAR_INDEX, input_rate, /sys)                              \
-  _ (LAST_UPDATE, SCALAR_INDEX, last_update, /sys)                            \
-  _ (LAST_STATS_CLEAR, SCALAR_INDEX, last_stats_clear, /sys)                  \
-  _ (HEARTBEAT, SCALAR_INDEX, heartbeat, /sys)                                \
-  _ (INTERFACE_NAMES, NAME_VECTOR, names, /if)                                \
-  _ (NODE_NAMES, NAME_VECTOR, names, /sys/node)                               \
-  foreach_stat_segment_node_counter_name
-/* clang-format on */
-
-/* Default stat segment 32m */
-#define STAT_SEGMENT_DEFAULT_SIZE      (32<<20)
-
-/* Shared segment memory layout version */
-#define STAT_SEGMENT_VERSION           2
-
-#define STAT_SEGMENT_INDEX_INVALID     UINT32_MAX
-
-typedef void (*stat_segment_update_fn)(stat_segment_directory_entry_t * e, u32 i);
-
-typedef struct {
-  u32 directory_index;
-  stat_segment_update_fn fn;
-  u32 caller_index;
-} stat_segment_gauges_pool_t;
-
-typedef struct
-{
-  /* internal, does not point to shared memory */
-  stat_segment_gauges_pool_t *gauges;
-
-  /* statistics segment */
-  uword *directory_vector_by_name;
-  stat_segment_directory_entry_t *directory_vector;
-  volatile u64 **error_vector;
-  u8 **interfaces;
-  u8 **nodes;
-
-  /* Update interval */
-  f64 update_interval;
-
-  clib_spinlock_t *stat_segment_lockp;
-  clib_socket_t *socket;
-  u8 *socket_name;
-  ssize_t memory_size;
-  clib_mem_page_sz_t log2_page_sz;
-  u8 node_counters_enabled;
-  void *last;
-  void *heap;
-  stat_segment_shared_header_t *shared_header; /* pointer to shared memory segment */
-  int memfd;
-
-  u64 last_input_packets; // OLE REMOVE?
-} stat_segment_main_t;
-
-extern stat_segment_main_t stat_segment_main;
-
-clib_error_t *
-stat_segment_register_gauge (u8 *names, stat_segment_update_fn update_fn, u32 index);
-clib_error_t *
-stat_segment_register_state_counter(u8 *name, u32 *index);
-clib_error_t *
-stat_segment_deregister_state_counter(u32 index);
-void stat_segment_set_state_counter (u32 index, u64 value);
-void stat_segment_poll_add (u32 vector_index, stat_segment_update_fn update_fn,
-                           u32 caller_index, u32 interval);
-
-u32 stat_segment_new_entry (u8 *name, stat_directory_type_t t);
-void vlib_stats_register_mem_heap (clib_mem_heap_t *heap);
-void vlib_stat_segment_lock (void);
-void vlib_stat_segment_unlock (void);
-void vlib_stats_register_symlink (void *oldheap, u8 *name, u32 index1,
-                                 u32 index2, u8 lock);
-
-void stat_provider_register_vector_rate (u32 num_workers);
-
-#endif
diff --git a/src/vpp/stats/stat_segment_provider.c b/src/vpp/stats/stat_segment_provider.c
deleted file mode 100644 (file)
index 766261c..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (c) 2021 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Counters handled by the stats module directly.
- */
-
-#include <stdbool.h>
-#include <vppinfra/mem.h>
-#include <vppinfra/vec.h>
-#include <vlib/vlib.h>
-#include <vlib/counter.h>
-#include "stat_segment.h"
-
-clib_mem_heap_t **memory_heaps_vec;
-u32 mem_vector_index;
-bool initialized = false;
-
-enum
-{
-  STAT_MEM_TOTAL = 0,
-  STAT_MEM_USED,
-  STAT_MEM_FREE,
-  STAT_MEM_USED_MMAP,
-  STAT_MEM_TOTAL_ALLOC,
-  STAT_MEM_FREE_CHUNKS,
-  STAT_MEM_RELEASABLE,
-} stat_mem_usage_e;
-
-/*
- * Called from the stats periodic process to update memory counters.
- */
-static void
-stat_provider_mem_usage_update_fn (stat_segment_directory_entry_t *e,
-                                  u32 index)
-{
-  clib_mem_usage_t usage;
-  clib_mem_heap_t *heap;
-  counter_t **counters = e->data;
-  counter_t *cb;
-
-  heap = vec_elt (memory_heaps_vec, index);
-  clib_mem_get_heap_usage (heap, &usage);
-  cb = counters[0];
-  cb[STAT_MEM_TOTAL] = usage.bytes_total;
-  cb[STAT_MEM_USED] = usage.bytes_used;
-  cb[STAT_MEM_FREE] = usage.bytes_free;
-  cb[STAT_MEM_USED_MMAP] = usage.bytes_used_mmap;
-  cb[STAT_MEM_TOTAL_ALLOC] = usage.bytes_max;
-  cb[STAT_MEM_FREE_CHUNKS] = usage.bytes_free_reclaimed;
-  cb[STAT_MEM_RELEASABLE] = usage.bytes_overhead;
-}
-
-static counter_t **
-stat_validate_counter_vector3 (counter_t **counters, u32 max1, u32 max2)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  int i;
-  void *oldheap = clib_mem_set_heap (sm->heap);
-  vec_validate_aligned (counters, max1, CLIB_CACHE_LINE_BYTES);
-  for (i = 0; i <= max1; i++)
-    vec_validate_aligned (counters[i], max2, CLIB_CACHE_LINE_BYTES);
-  clib_mem_set_heap (oldheap);
-  return counters;
-}
-
-/*
- * Provide memory heap counters.
- * Two dimensional array of heap index and per-heap gauges.
- */
-void
-vlib_stats_register_mem_heap (clib_mem_heap_t *heap)
-{
-  stat_segment_main_t *sm = &stat_segment_main;
-  vec_add1 (memory_heaps_vec, heap);
-  u32 heap_index = vec_len (memory_heaps_vec) - 1;
-
-  /* Memory counters provider */
-  u8 *s = format (0, "/mem/%s%c", heap->name, 0);
-  u8 *s_used = format (0, "/mem/%s/used%c", heap->name, 0);
-  u8 *s_total = format (0, "/mem/%s/total%c", heap->name, 0);
-  u8 *s_free = format (0, "/mem/%s/free%c", heap->name, 0);
-  mem_vector_index =
-    stat_segment_new_entry (s, STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE);
-  vec_free (s);
-  if (mem_vector_index == ~0)
-    ASSERT (0);
-
-  vlib_stat_segment_lock ();
-  stat_segment_directory_entry_t *ep = &sm->directory_vector[mem_vector_index];
-  ep->data = stat_validate_counter_vector3 (ep->data, 0, STAT_MEM_RELEASABLE);
-
-  /* Create symlink */
-  void *oldheap = clib_mem_set_heap (sm->heap);
-  vlib_stats_register_symlink (oldheap, s_total, mem_vector_index,
-                              STAT_MEM_TOTAL, 0);
-  vlib_stats_register_symlink (oldheap, s_used, mem_vector_index,
-                              STAT_MEM_USED, 0);
-  vlib_stats_register_symlink (oldheap, s_free, mem_vector_index,
-                              STAT_MEM_FREE, 0);
-  vlib_stat_segment_unlock ();
-  clib_mem_set_heap (oldheap);
-  vec_free (s_used);
-  vec_free (s_total);
-  vec_free (s_free);
-
-  stat_segment_poll_add (mem_vector_index, stat_provider_mem_usage_update_fn,
-                        heap_index, 10);
-}
-
-static void
-stat_provider_vector_rate_per_thread_update_fn (
-  stat_segment_directory_entry_t *e, u32 index)
-{
-  vlib_main_t *this_vlib_main;
-  int i;
-  ASSERT (e->data);
-  counter_t **counters = e->data;
-
-  for (i = 0; i < vlib_get_n_threads (); i++)
-    {
-
-      f64 this_vector_rate;
-
-      this_vlib_main = vlib_get_main_by_index (i);
-
-      this_vector_rate = vlib_internal_node_vector_rate (this_vlib_main);
-      vlib_clear_internal_node_vector_rate (this_vlib_main);
-      /* Set the per-worker rate */
-      counter_t *cb = counters[i];
-      cb[0] = this_vector_rate;
-    }
-}
-
-static void
-stat_provider_vector_rate_update_fn (stat_segment_directory_entry_t *e,
-                                    u32 index)
-{
-  vlib_main_t *this_vlib_main;
-  int i;
-  f64 vector_rate = 0.0;
-  for (i = 0; i < vlib_get_n_threads (); i++)
-    {
-
-      f64 this_vector_rate;
-
-      this_vlib_main = vlib_get_main_by_index (i);
-
-      this_vector_rate = vlib_internal_node_vector_rate (this_vlib_main);
-      vlib_clear_internal_node_vector_rate (this_vlib_main);
-
-      vector_rate += this_vector_rate;
-    }
-
-  /* And set the system average rate */
-  vector_rate /= (f64) (i > 1 ? i - 1 : 1);
-  e->value = vector_rate;
-}
-
-void
-stat_provider_register_vector_rate (u32 num_workers)
-{
-  int i;
-
-  u8 *s = format (0, "/sys/vector_rate%c", 0);
-
-  i = stat_segment_new_entry (s, STAT_DIR_TYPE_SCALAR_INDEX);
-  if (i == ~0)
-    ASSERT (0);
-  vec_free (s);
-  stat_segment_poll_add (i, stat_provider_vector_rate_update_fn, ~0, 10);
-
-  s = format (0, "/sys/vector_rate_per_worker%c", 0);
-  i = stat_segment_new_entry (s, STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE);
-  if (i == ~0)
-    ASSERT (0);
-  vec_free (s);
-  stat_segment_poll_add (i, stat_provider_vector_rate_per_thread_update_fn, ~0,
-                        10);
-
-  stat_segment_main_t *sm = &stat_segment_main;
-  vlib_stat_segment_lock ();
-  stat_segment_directory_entry_t *ep = &sm->directory_vector[i];
-  ep->data = stat_validate_counter_vector3 (ep->data, num_workers, 0);
-  vlib_stat_segment_unlock ();
-}
diff --git a/src/vpp/stats/stat_segment_shared.h b/src/vpp/stats/stat_segment_shared.h
deleted file mode 100644 (file)
index 6f26d4b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef included_stat_segment_shared_h
-#define included_stat_segment_shared_h
-
-typedef enum
-{
-  STAT_DIR_TYPE_ILLEGAL = 0,
-  STAT_DIR_TYPE_SCALAR_INDEX,
-  STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
-  STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
-  STAT_DIR_TYPE_ERROR_INDEX,
-  STAT_DIR_TYPE_NAME_VECTOR,
-  STAT_DIR_TYPE_EMPTY,
-  STAT_DIR_TYPE_SYMLINK,
-} stat_directory_type_t;
-
-typedef struct
-{
-  stat_directory_type_t type;
-  union {
-    struct
-    {
-      uint32_t index1;
-      uint32_t index2;
-    };
-    uint64_t index;
-    uint64_t value;
-    void *data;
-  };
-  char name[128]; // TODO change this to pointer to "somewhere"
-} stat_segment_directory_entry_t;
-
-/*
- * Shared header first in the shared memory segment.
- */
-typedef struct
-{
-  uint64_t version;
-  void *base;
-  volatile uint64_t epoch;
-  volatile uint64_t in_progress;
-  volatile stat_segment_directory_entry_t *directory_vector;
-  volatile uint64_t **error_vector;
-} stat_segment_shared_header_t;
-
-static inline void *
-stat_segment_pointer (void *start, uint64_t offset)
-{
-  return ((char *) start + offset);
-}
-
-#endif /* included_stat_segment_shared_h */