blob: 19edaf0866d7b0f2836d9f35ecbcb6829c4269d6 [file] [log] [blame]
Damjan Marion8973b072022-03-01 15:51:18 +01001/* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2022 Cisco Systems, Inc.
3 */
4
5#include <vlib/vlib.h>
6#include <vlib/stats/stats.h>
7
8vlib_stats_main_t vlib_stats_main;
9
10/*
11 * Used only by VPP writers
12 */
13
14void
15vlib_stats_segment_lock (void)
16{
17 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
18 clib_spinlock_lock (sm->stat_segment_lockp);
19 sm->shared_header->in_progress = 1;
20}
21
22void
23vlib_stats_segment_unlock (void)
24{
25 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
26 sm->shared_header->epoch++;
27 sm->shared_header->in_progress = 0;
28 clib_spinlock_unlock (sm->stat_segment_lockp);
29}
30
31/*
32 * Change heap to the stats shared memory segment
33 */
34void *
35vlib_stats_set_heap ()
36{
37 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
38
39 ASSERT (sm && sm->shared_header);
40 return clib_mem_set_heap (sm->heap);
41}
42
43u32
44vlib_stats_find_entry_index (char *fmt, ...)
45{
46 u8 *name;
47 va_list va;
48
49 va_start (va, fmt);
50 name = va_format (0, fmt, &va);
51 va_end (va);
52 vec_add1 (name, 0);
53
54 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
55 hash_pair_t *hp = hash_get_pair (sm->directory_vector_by_name, name);
56 vec_free (name);
57 return hp ? hp->value[0] : STAT_SEGMENT_INDEX_INVALID;
58}
59
60static void
61hash_set_str_key_alloc (uword **h, const char *key, uword v)
62{
63 int size = strlen (key) + 1;
64 void *copy = clib_mem_alloc (size);
65 clib_memcpy_fast (copy, key, size);
66 hash_set_mem (*h, copy, v);
67}
68
69static void
70hash_unset_str_key_free (uword **h, const char *key)
71{
72 hash_pair_t *hp = hash_get_pair_mem (*h, key);
73 if (hp)
74 {
75 void *_k = uword_to_pointer (hp->key, void *);
76 hash_unset_mem (*h, _k);
77 clib_mem_free (_k);
78 }
79}
80
81u32
82vlib_stats_create_counter (vlib_stats_entry_t *e)
83{
84 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
85 void *oldheap;
86 u32 index = ~0;
87 int i;
88
89 oldheap = clib_mem_set_heap (sm->heap);
90 vec_foreach_index_backwards (i, sm->directory_vector)
91 if (sm->directory_vector[i].type == STAT_DIR_TYPE_EMPTY)
92 {
93 index = i;
94 break;
95 }
96
97 index = index == ~0 ? vec_len (sm->directory_vector) : index;
98
99 vec_validate (sm->directory_vector, index);
100 sm->directory_vector[index] = *e;
101
102 clib_mem_set_heap (oldheap);
103 hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index);
104
105 return index;
106}
107
108void
109vlib_stats_remove_entry (u32 entry_index)
110{
111 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
112 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
113 void *oldheap;
114 counter_t **c;
115 u32 i;
116
117 if (entry_index >= vec_len (sm->directory_vector))
118 return;
119
120 oldheap = clib_mem_set_heap (sm->heap);
121
122 switch (e->type)
123 {
124 case STAT_DIR_TYPE_NAME_VECTOR:
125 for (i = 0; i < vec_len (e->string_vector); i++)
126 vec_free (e->string_vector[i]);
127 vec_free (e->string_vector);
128 break;
129
130 case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
131 c = e->data;
132 e->data = 0;
133 for (i = 0; i < vec_len (c); i++)
134 vec_free (c[i]);
135 vec_free (c);
136 break;
137
138 case STAT_DIR_TYPE_SCALAR_INDEX:
139 case STAT_DIR_TYPE_SYMLINK:
140 break;
141 default:
142 ASSERT (0);
143 }
144
145 clib_mem_set_heap (oldheap);
146 hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
147
148 memset (e, 0, sizeof (*e));
149 e->type = STAT_DIR_TYPE_EMPTY;
150}
151
152static void
153vlib_stats_set_entry_name (vlib_stats_entry_t *e, char *s)
154{
155 u32 i, len = VLIB_STATS_MAX_NAME_SZ - 1;
156
157 for (i = 0; i < len; i++)
158 {
159 e->name[i] = s[i];
160 if (s[i] == 0)
161 return;
162 }
163 ASSERT (i < VLIB_STATS_MAX_NAME_SZ - 1);
164 s[i] = 0;
165}
166
167void
168vlib_stats_update_counter (void *cm_arg, u32 cindex,
169 stat_directory_type_t type)
170{
171 vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
172 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
173 vlib_stats_shared_header_t *shared_header = sm->shared_header;
174 char *stat_segment_name;
175 vlib_stats_entry_t e = { 0 };
176
177 /* Not all counters have names / hash-table entries */
178 if (!cm->name && !cm->stat_segment_name)
179 return;
180
181 ASSERT (shared_header);
182
183 vlib_stats_segment_lock ();
184
185 /* Lookup hash-table is on the main heap */
186 stat_segment_name = cm->stat_segment_name ? cm->stat_segment_name : cm->name;
187
188 u32 vector_index = vlib_stats_find_entry_index ("%s", stat_segment_name);
189
190 /* Update the vector */
191 if (vector_index == STAT_SEGMENT_INDEX_INVALID)
192 {
193 vlib_stats_set_entry_name (&e, stat_segment_name);
194 e.type = type;
195 vector_index = vlib_stats_create_counter (&e);
196 }
197
198 vlib_stats_entry_t *ep = &sm->directory_vector[vector_index];
199 ep->data = cm->counters;
200
201 /* Reset the client hash table pointer, since it WILL change! */
202 shared_header->directory_vector = sm->directory_vector;
203
204 vlib_stats_segment_unlock ();
205}
206
207void
208vlib_stats_register_error_index (u64 *em_vec, u64 index, char *fmt, ...)
209{
210 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
211 vlib_stats_shared_header_t *shared_header = sm->shared_header;
212 vlib_stats_entry_t e = {};
213 va_list va;
214 u8 *name;
215
216 va_start (va, fmt);
217 name = va_format (0, fmt, &va);
218 va_end (va);
219
220 ASSERT (shared_header);
221
222 vlib_stats_segment_lock ();
223 u32 vector_index = vlib_stats_find_entry_index ("%v", name);
224
225 if (vector_index == STAT_SEGMENT_INDEX_INVALID)
226 {
227 vec_add1 (name, 0);
228 vlib_stats_set_entry_name (&e, (char *) name);
229 e.type = STAT_DIR_TYPE_ERROR_INDEX;
230 e.index = index;
231 vector_index = vlib_stats_create_counter (&e);
232
233 /* Warn clients to refresh any pointers they might be holding */
234 shared_header->directory_vector = sm->directory_vector;
235 }
236
237 vlib_stats_segment_unlock ();
238 vec_free (name);
239}
240
241void
242vlib_stats_update_error_vector (u64 *error_vector, u32 thread_index, int lock)
243{
244 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
245 vlib_stats_shared_header_t *shared_header = sm->shared_header;
246 void *oldheap = clib_mem_set_heap (sm->heap);
247
248 ASSERT (shared_header);
249
250 if (lock)
251 vlib_stats_segment_lock ();
252
253 /* Reset the client hash table pointer, since it WILL change! */
254 vec_validate (sm->error_vector, thread_index);
255 sm->error_vector[thread_index] = error_vector;
256
257 shared_header->error_vector = sm->error_vector;
258 shared_header->directory_vector = sm->directory_vector;
259
260 if (lock)
261 vlib_stats_segment_unlock ();
262 clib_mem_set_heap (oldheap);
263}
264
265void
266vlib_stats_delete_cm (void *cm_arg)
267{
268 vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
269 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
270 vlib_stats_entry_t *e;
271
272 /* Not all counters have names / hash-table entries */
273 if (!cm->name && !cm->stat_segment_name)
274 return;
275
276 vlib_stats_segment_lock ();
277
278 /* Lookup hash-table is on the main heap */
279 char *stat_segment_name =
280 cm->stat_segment_name ? cm->stat_segment_name : cm->name;
281 u32 index = vlib_stats_find_entry_index ("%s", stat_segment_name);
282
283 e = &sm->directory_vector[index];
284
285 hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
286
287 memset (e, 0, sizeof (*e));
288 e->type = STAT_DIR_TYPE_EMPTY;
289
290 vlib_stats_segment_unlock ();
291}
292
293static u32
294vlib_stats_new_entry_internal (stat_directory_type_t t, u8 *name)
295{
296 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
297 vlib_stats_shared_header_t *shared_header = sm->shared_header;
298 vlib_stats_entry_t e = { .type = t };
299
300 ASSERT (shared_header);
301
302 u32 vector_index = vlib_stats_find_entry_index ("%v", name);
303 if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
304 {
305 vector_index = ~0;
306 goto done;
307 }
308
309 vec_add1 (name, 0);
310 vlib_stats_set_entry_name (&e, (char *) name);
311
312 vlib_stats_segment_lock ();
313 vector_index = vlib_stats_create_counter (&e);
314
315 shared_header->directory_vector = sm->directory_vector;
316
317 vlib_stats_segment_unlock ();
318
319done:
320 vec_free (name);
321 return vector_index;
322}
323
324u32
325vlib_stats_add_gauge (char *fmt, ...)
326{
327 va_list va;
328 u8 *name;
329
330 va_start (va, fmt);
331 name = va_format (0, fmt, &va);
332 va_end (va);
333 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
334}
335
336void
337vlib_stats_set_gauge (u32 index, u64 value)
338{
339 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
340
341 ASSERT (index < vec_len (sm->directory_vector));
342 sm->directory_vector[index].value = value;
343}
344
345u32
346vlib_stats_add_timestamp (char *fmt, ...)
347{
348 va_list va;
349 u8 *name;
350
351 va_start (va, fmt);
352 name = va_format (0, fmt, &va);
353 va_end (va);
354 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name);
355}
356
357void
358vlib_stats_set_timestamp (u32 entry_index, f64 value)
359{
360 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
361
362 ASSERT (entry_index < vec_len (sm->directory_vector));
363 sm->directory_vector[entry_index].value = value;
364}
365
366u32
367vlib_stats_add_string_vector (char *fmt, ...)
368{
369 va_list va;
370 u8 *name;
371
372 va_start (va, fmt);
373 name = va_format (0, fmt, &va);
374 va_end (va);
375 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_NAME_VECTOR, name);
376}
377
378void
379vlib_stats_set_string_vector (u32 entry_index, u32 vector_index, char *fmt,
380 ...)
381{
382 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
383 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
384 va_list va;
385 void *oldheap;
386
387 oldheap = clib_mem_set_heap (sm->heap);
388 vlib_stats_segment_lock ();
389
390 vec_validate (e->string_vector, vector_index);
391 vec_reset_length (e->string_vector[vector_index]);
392
393 va_start (va, fmt);
394 e->string_vector[vector_index] =
395 va_format (e->string_vector[vector_index], fmt, &va);
396 va_end (va);
397
398 vlib_stats_segment_unlock ();
399 clib_mem_set_heap (oldheap);
400}
401
402u32
403vlib_stats_add_counter_vector (char *fmt, ...)
404{
405 va_list va;
406 u8 *name;
407
408 va_start (va, fmt);
409 name = va_format (0, fmt, &va);
410 va_end (va);
411 return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
412 name);
413}
414
415void
416vlib_stats_validate_counter_vector (u32 entry_index, u32 vector_index)
417{
418 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
419 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
420 void *oldheap;
421 counter_t **c = e->data;
422
423 if (vec_len (c) > 0 && vec_len (c[0]) > vector_index)
424 return;
425
426 oldheap = clib_mem_set_heap (sm->heap);
427 vlib_stats_segment_lock ();
428
429 vec_validate_aligned (c, 0, CLIB_CACHE_LINE_BYTES);
430 vec_validate_aligned (c[0], vector_index, CLIB_CACHE_LINE_BYTES);
431 e->data = c;
432
433 vlib_stats_segment_unlock ();
434 clib_mem_set_heap (oldheap);
435}
436
437u32
438vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...)
439{
440 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
441 vlib_stats_shared_header_t *shared_header = sm->shared_header;
442 vlib_stats_entry_t e;
443 va_list va;
444 u8 *name;
445
446 ASSERT (shared_header);
447 ASSERT (entry_index < vec_len (sm->directory_vector));
448
449 va_start (va, fmt);
450 name = va_format (0, fmt, &va);
451 va_end (va);
452
453 if (vlib_stats_find_entry_index ("%v", name) == STAT_SEGMENT_INDEX_INVALID)
454 {
455 vec_add1 (name, 0);
456 vlib_stats_set_entry_name (&e, (char *) name);
457 e.type = STAT_DIR_TYPE_SYMLINK;
458 e.index1 = entry_index;
459 e.index2 = vector_index;
460 vector_index = vlib_stats_create_counter (&e);
461
462 /* Warn clients to refresh any pointers they might be holding */
463 shared_header->directory_vector = sm->directory_vector;
464 }
465 else
466 vector_index = ~0;
467
468 vec_free (name);
469 return vector_index;
470}
471
472void
473vlib_stats_rename_symlink (u64 entry_index, char *fmt, ...)
474{
475 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
476 vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index);
477 va_list va;
478 u8 *new_name;
479
480 hash_unset_str_key_free (&sm->directory_vector_by_name, e->name);
481
482 va_start (va, fmt);
483 new_name = va_format (0, fmt, &va);
484 va_end (va);
485
486 vec_add1 (new_name, 0);
487 vlib_stats_set_entry_name (e, (char *) new_name);
488 hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, entry_index);
489 vec_free (new_name);
490}
491
492f64
493vlib_stats_get_segment_update_rate (void)
494{
495 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
496 return sm->update_interval;
497}
498
499void
500vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *reg)
501{
502 vlib_stats_segment_t *sm = vlib_stats_get_segment ();
503 vlib_stats_collector_t *c;
504
505 ASSERT (reg->entry_index != ~0);
506
507 pool_get_zero (sm->collectors, c);
508 c->fn = reg->collect_fn;
509 c->entry_index = reg->entry_index;
510 c->vector_index = reg->vector_index;
511 c->private_data = reg->private_data;
512
513 return;
514}