+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)
+ {
+ memcpy (e.name, name, vec_len (name));
+ e.name[vec_len (name)] = '\0';
+ 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);
+
+ if (index > vec_len (sm->directory_vector))
+ return;
+
+ e = &sm->directory_vector[index];
+
+ clib_mem_set_heap (oldheap);
+ hash_unset (sm->directory_vector_by_name, &e->name);
+ clib_mem_set_heap (sm->heap);
+
+ strncpy (e->name, (char *) new_name, 128 - 1);
+ clib_mem_set_heap (oldheap);
+ hash_set (sm->directory_vector_by_name, &e->name, index);
+ clib_mem_set_heap (sm->heap);
+}
+