FD.io VPP  v21.06-3-gbb25fbf28
Vector Packet Processing
stat_client.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * stat_client.c - Library for access to VPP statistics segment
4  *
5  * Copyright (c) 2018 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 
20 #include <stdio.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <stdbool.h>
26 #include <sys/stat.h>
27 #include <regex.h>
28 #include <assert.h>
29 #include <vppinfra/vec.h>
30 #include <vppinfra/lock.h>
31 #include <stdatomic.h>
32 #include <vpp/stats/stat_segment.h>
34 
36 
39 {
41  sm = (stat_client_main_t *) malloc (sizeof (stat_client_main_t));
42  clib_memset (sm, 0, sizeof (stat_client_main_t));
43  return sm;
44 }
45 
46 void
48 {
49  free (sm);
50 }
51 
52 static int
53 recv_fd (int sock)
54 {
55  struct msghdr msg = { 0 };
56  struct cmsghdr *cmsg;
57  int fd = -1;
58  char iobuf[1];
59  struct iovec io = {.iov_base = iobuf,.iov_len = sizeof (iobuf) };
60  union
61  {
62  char buf[CMSG_SPACE (sizeof (fd))];
63  struct cmsghdr align;
64  } u;
65  msg.msg_iov = &io;
66  msg.msg_iovlen = 1;
67  msg.msg_control = u.buf;
68  msg.msg_controllen = sizeof (u.buf);
69 
70  ssize_t size;
71  if ((size = recvmsg (sock, &msg, 0)) < 0)
72  {
73  perror ("recvmsg failed");
74  return -1;
75  }
76  cmsg = CMSG_FIRSTHDR (&msg);
77  if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
78  {
79  memmove (&fd, CMSG_DATA (cmsg), sizeof (fd));
80  }
81  return fd;
82 }
83 
86 {
87  ASSERT (sm->shared_header);
88  return stat_segment_adjust (sm,
89  (void *) sm->shared_header->directory_vector);
90 }
91 
92 int
93 stat_segment_connect_r (const char *socket_name, stat_client_main_t * sm)
94 {
95  int mfd = -1;
96  int sock;
97 
98  clib_memset (sm, 0, sizeof (*sm));
99  if ((sock = socket (AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
100  {
101  perror ("Stat client couldn't open socket");
102  return -1;
103  }
104 
105  struct sockaddr_un un = { 0 };
106  un.sun_family = AF_UNIX;
107  strncpy ((char *) un.sun_path, socket_name, sizeof (un.sun_path) - 1);
108  if (connect (sock, (struct sockaddr *) &un, sizeof (struct sockaddr_un)) <
109  0)
110  {
111  close (sock);
112  return -2;
113  }
114 
115  if ((mfd = recv_fd (sock)) < 0)
116  {
117  close (sock);
118  fprintf (stderr, "Receiving file descriptor failed\n");
119  return -3;
120  }
121  close (sock);
122 
123  /* mmap shared memory segment. */
124  void *memaddr;
125  struct stat st = { 0 };
126 
127  if (fstat (mfd, &st) == -1)
128  {
129  close (mfd);
130  perror ("mmap fstat failed");
131  return -4;
132  }
133  if ((memaddr =
134  mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, mfd, 0)) == MAP_FAILED)
135  {
136  close (mfd);
137  perror ("mmap map failed");
138  return -5;
139  }
140 
141  close (mfd);
142  sm->memory_size = st.st_size;
143  sm->shared_header = memaddr;
144  sm->directory_vector =
146 
147  return 0;
148 }
149 
150 int
151 stat_segment_connect (const char *socket_name)
152 {
154  return stat_segment_connect_r (socket_name, sm);
155 }
156 
157 void
159 {
160  munmap (sm->shared_header, sm->memory_size);
161  return;
162 }
163 
164 void
166 {
168  return stat_segment_disconnect_r (sm);
169 }
170 
171 double
173 {
176 
177  /* Has directory been updated? */
178  if (sm->shared_header->epoch != sm->current_epoch)
179  return 0;
180  if (stat_segment_access_start (&sa, sm))
181  return 0;
183  if (!stat_segment_access_end (&sa, sm))
184  return 0.0;
185  return ep->value;
186 }
187 
188 double
190 {
192  return stat_segment_heartbeat_r (sm);
193 }
194 
195 #define stat_vec_dup(S,V) \
196  ({ \
197  __typeof__ ((V)[0]) * _v(v) = 0; \
198  if (V && ((void *)V > (void *)S->shared_header) && \
199  (((void*)V + vec_bytes(V)) < \
200  ((void *)S->shared_header + S->memory_size))) \
201  _v(v) = vec_dup(V); \
202  _v(v); \
203 })
204 
205 static counter_t *
207 {
208  counter_t *v = 0;
209  vec_add1 (v, c);
210  return v;
211 }
212 
213 static vlib_counter_t *
215 {
216  vlib_counter_t *v = 0;
217  vec_add1 (v, c);
218  return v;
219 }
220 
221 /*
222  * If index2 is specified copy out the column (the indexed value across all
223  * threads), otherwise copy out all values.
224  */
225 static stat_segment_data_t
227  stat_client_main_t *sm)
228 {
229  stat_segment_data_t result = { 0 };
230  int i;
231  vlib_counter_t **combined_c; /* Combined counter */
232  counter_t **simple_c; /* Simple counter */
233  uint64_t *error_vector;
234 
235  assert (sm->shared_header);
236 
237  result.type = ep->type;
238  result.name = strdup (name ? name : ep->name);
239 
240  switch (ep->type)
241  {
243  result.scalar_value = ep->value;
244  break;
245 
247  simple_c = stat_segment_adjust (sm, ep->data);
248  result.simple_counter_vec = stat_vec_dup (sm, simple_c);
249  for (i = 0; i < vec_len (simple_c); i++)
250  {
251  counter_t *cb = stat_segment_adjust (sm, simple_c[i]);
252  if (index2 != ~0)
253  result.simple_counter_vec[i] = stat_vec_simple_init (cb[index2]);
254  else
255  result.simple_counter_vec[i] = stat_vec_dup (sm, cb);
256  }
257  break;
258 
260  combined_c = stat_segment_adjust (sm, ep->data);
261  result.combined_counter_vec = stat_vec_dup (sm, combined_c);
262  for (i = 0; i < vec_len (combined_c); i++)
263  {
264  vlib_counter_t *cb = stat_segment_adjust (sm, combined_c[i]);
265  if (index2 != ~0)
266  result.combined_counter_vec[i] =
267  stat_vec_combined_init (cb[index2]);
268  else
269  result.combined_counter_vec[i] = stat_vec_dup (sm, cb);
270  }
271  break;
272 
274  /* Gather errors from all threads into a vector */
275  error_vector =
276  stat_segment_adjust (sm, (void *) sm->shared_header->error_vector);
277  vec_validate (result.error_vector, vec_len (error_vector) - 1);
278  for (i = 0; i < vec_len (error_vector); i++)
279  {
280  counter_t *cb = stat_segment_adjust (sm, (void *) error_vector[i]);
281  result.error_vector[i] = cb[ep->index];
282  }
283  break;
284 
286  {
287  uint8_t **name_vector = stat_segment_adjust (sm, ep->data);
288  result.name_vector = stat_vec_dup (sm, name_vector);
289  for (i = 0; i < vec_len (name_vector); i++)
290  {
291  u8 *name = stat_segment_adjust (sm, name_vector[i]);
292  result.name_vector[i] = stat_vec_dup (sm, name);
293  }
294  }
295  break;
296 
298  /* Gather info from all threads into a vector */
299  {
301  ep2 = vec_elt_at_index (sm->directory_vector, ep->index1);
302  return copy_data (ep2, ep->index2, ep->name, sm);
303  }
304 
305  case STAT_DIR_TYPE_EMPTY:
306  break;
307 
308  default:
309  fprintf (stderr, "Unknown type: %d\n", ep->type);
310  }
311  return result;
312 }
313 
314 void
316 {
317  int i, j;
318  for (i = 0; i < vec_len (res); i++)
319  {
320  switch (res[i].type)
321  {
323  for (j = 0; j < vec_len (res[i].simple_counter_vec); j++)
324  vec_free (res[i].simple_counter_vec[j]);
325  vec_free (res[i].simple_counter_vec);
326  break;
328  for (j = 0; j < vec_len (res[i].combined_counter_vec); j++)
329  vec_free (res[i].combined_counter_vec[j]);
330  vec_free (res[i].combined_counter_vec);
331  break;
333  for (j = 0; j < vec_len (res[i].name_vector); j++)
334  vec_free (res[i].name_vector[j]);
335  vec_free (res[i].name_vector);
336  break;
338  vec_free (res[i].error_vector);
339  break;
341  break;
342  default:
343  assert (0);
344  }
345  free (res[i].name);
346  }
347  vec_free (res);
348 }
349 
350 uint32_t *
351 stat_segment_ls_r (uint8_t ** patterns, stat_client_main_t * sm)
352 {
354 
355  uint32_t *dir = 0;
356  regex_t regex[vec_len (patterns)];
357 
358  int i, j;
359  for (i = 0; i < vec_len (patterns); i++)
360  {
361  int rv = regcomp (&regex[i], (const char *) patterns[i], 0);
362  if (rv)
363  {
364  fprintf (stderr, "Could not compile regex %s\n", patterns[i]);
365  return dir;
366  }
367  }
368 
369  if (stat_segment_access_start (&sa, sm))
370  return 0;
371 
373  for (j = 0; j < vec_len (counter_vec); j++)
374  {
375  for (i = 0; i < vec_len (patterns); i++)
376  {
377  int rv = regexec (&regex[i], counter_vec[j].name, 0, NULL, 0);
378  if (rv == 0)
379  {
380  vec_add1 (dir, j);
381  break;
382  }
383  }
384  if (vec_len (patterns) == 0)
385  vec_add1 (dir, j);
386  }
387 
388  for (i = 0; i < vec_len (patterns); i++)
389  regfree (&regex[i]);
390 
391  if (!stat_segment_access_end (&sa, sm))
392  {
393  /* Failed, clean up */
394  vec_free (dir);
395  return 0;
396 
397  }
398 
399  /* Update last version */
400  sm->current_epoch = sa.epoch;
401  return dir;
402 }
403 
404 uint32_t *
405 stat_segment_ls (uint8_t ** patterns)
406 {
408  return stat_segment_ls_r ((uint8_t **) patterns, sm);
409 }
410 
413 {
414  int i;
416  stat_segment_data_t *res = 0;
418 
419  /* Has directory been update? */
420  if (sm->shared_header->epoch != sm->current_epoch)
421  return 0;
422 
423  if (stat_segment_access_start (&sa, sm))
424  return 0;
425 
426  for (i = 0; i < vec_len (stats); i++)
427  {
428  /* Collect counter */
430  vec_add1 (res, copy_data (ep, ~0, 0, sm));
431  }
432 
433  if (stat_segment_access_end (&sa, sm))
434  return res;
435 
436  fprintf (stderr, "Epoch changed while reading, invalid results\n");
437  // TODO increase counter
438  return 0;
439 }
440 
443 {
445  return stat_segment_dump_r (stats, sm);
446 }
447 
448 /* Wrapper for accessing vectors from other languages */
449 int
451 {
452  return vec_len (vec);
453 }
454 
455 void
457 {
458  vec_free (vec);
459 }
460 
461 /* Create a vector from a string (or add to existing) */
462 uint8_t **
463 stat_segment_string_vector (uint8_t ** string_vector, const char *string)
464 {
465  uint8_t *name = 0;
466  size_t len = strlen (string);
467 
469  vec_add1 (string_vector, name);
470  return string_vector;
471 }
472 
475 {
477  stat_segment_data_t *res = 0;
479 
480  /* Has directory been update? */
481  if (sm->shared_header->epoch != sm->current_epoch)
482  return 0;
483 
484  if (stat_segment_access_start (&sa, sm))
485  return 0;
486 
487  /* Collect counter */
489  vec_add1 (res, copy_data (ep, ~0, 0, sm));
490 
491  if (stat_segment_access_end (&sa, sm))
492  return res;
493  return 0;
494 }
495 
498 {
500  return stat_segment_dump_entry_r (index, sm);
501 }
502 
503 char *
505 {
509 
510  /* Has directory been update? */
511  if (sm->shared_header->epoch != sm->current_epoch)
512  return 0;
513  if (stat_segment_access_start (&sa, sm))
514  return 0;
515  vec = get_stat_vector_r (sm);
516  ep = vec_elt_at_index (vec, index);
517  if (!stat_segment_access_end (&sa, sm))
518  return 0;
519  return strdup (ep->name);
520 }
521 
522 char *
524 {
526  return stat_segment_index_to_name_r (index, sm);
527 }
528 
529 uint64_t
531 {
532  ASSERT (sm->shared_header);
533  return sm->shared_header->version;
534 }
535 
536 uint64_t
538 {
540  return stat_segment_version_r (sm);
541 }
542 
543 /*
544  * fd.io coding-style-patch-verification: ON
545  *
546  * Local Variables:
547  * eval: (c-set-style "gnu")
548  * End:
549  */
stat_client_main_t::directory_vector
stat_segment_directory_entry_t * directory_vector
Definition: stat_client.h:53
STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED
@ STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED
Definition: stat_segment_shared.h:24
stat_segment_shared_header_t::error_vector
volatile uint64_t ** error_vector
Definition: stat_segment_shared.h:57
stat_segment_vec_free
void stat_segment_vec_free(void *vec)
Definition: stat_client.c:456
assert
#define assert(x)
Definition: dlmalloc.c:31
stat_segment_data_t::simple_counter_vec
counter_t ** simple_counter_vec
Definition: stat_client.h:43
stat_segment_directory_entry_t::data
void * data
Definition: stat_segment_shared.h:42
stat_vec_combined_init
static vlib_counter_t * stat_vec_combined_init(vlib_counter_t c)
Definition: stat_client.c:214
stat_segment_string_vector
uint8_t ** stat_segment_string_vector(uint8_t **string_vector, const char *string)
Definition: stat_client.c:463
stat_segment_data_t::error_vector
counter_t * error_vector
Definition: stat_client.h:42
name
string name[64]
Definition: fib.api:25
stat_segment_access_t
Definition: stat_client.h:88
STAT_DIR_TYPE_NAME_VECTOR
@ STAT_DIR_TYPE_NAME_VECTOR
Definition: stat_segment_shared.h:26
stat_segment_connect_r
int stat_segment_connect_r(const char *socket_name, stat_client_main_t *sm)
Definition: stat_client.c:93
stat_segment_data_t::name_vector
uint8_t ** name_vector
Definition: stat_client.h:45
stat_segment_access_t::epoch
uint64_t epoch
Definition: stat_client.h:90
stat_segment_disconnect_r
void stat_segment_disconnect_r(stat_client_main_t *sm)
Definition: stat_client.c:158
STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE
@ STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE
Definition: stat_segment_shared.h:23
stat_segment_directory_entry_t::index1
uint32_t index1
Definition: stat_segment_shared.h:37
stat_segment_index_to_name
char * stat_segment_index_to_name(uint32_t index)
Definition: stat_client.c:523
stats
vl_api_ikev2_sa_stats_t stats
Definition: ikev2_types.api:162
stat_segment_shared_header_t::version
uint64_t version
Definition: stat_segment_shared.h:52
stat_segment_directory_entry_t::index
uint64_t index
Definition: stat_segment_shared.h:40
stat_segment_data_t::scalar_value
double scalar_value
Definition: stat_client.h:41
stat_segment_access_start
static int stat_segment_access_start(stat_segment_access_t *sa, stat_client_main_t *sm)
Definition: stat_client.h:115
STAT_DIR_TYPE_EMPTY
@ STAT_DIR_TYPE_EMPTY
Definition: stat_segment_shared.h:27
stat_segment_ls
uint32_t * stat_segment_ls(uint8_t **patterns)
Definition: stat_client.c:405
stat_segment_access_end
static bool stat_segment_access_end(stat_segment_access_t *sa, stat_client_main_t *sm)
Definition: stat_client.h:165
stat_segment_version
uint64_t stat_segment_version(void)
Definition: stat_client.c:537
stat_segment_disconnect
void stat_segment_disconnect(void)
Definition: stat_client.c:165
stat_segment_index_to_name_r
char * stat_segment_index_to_name_r(uint32_t index, stat_client_main_t *sm)
Definition: stat_client.c:504
stat_segment_version_r
uint64_t stat_segment_version_r(stat_client_main_t *sm)
Definition: stat_client.c:530
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
stat_client_main_t::current_epoch
uint64_t current_epoch
Definition: stat_client.h:51
stat_segment_data_free
void stat_segment_data_free(stat_segment_data_t *res)
Definition: stat_client.c:315
len
u8 len
Definition: ip_types.api:103
recv_fd
static int recv_fd(int sock)
Definition: stat_client.c:53
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
stat_segment_connect
int stat_segment_connect(const char *socket_name)
Definition: stat_client.c:151
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
stat_segment_vec_len
int stat_segment_vec_len(void *vec)
Definition: stat_client.c:450
lock.h
vlib_counter_t
Combined counter to hold both packets and byte differences.
Definition: counter_types.h:26
stat_client_get
stat_client_main_t * stat_client_get(void)
Definition: stat_client.c:38
stat_segment_directory_entry_t::value
uint64_t value
Definition: stat_segment_shared.h:41
counter_t
uint64_t counter_t
64bit counters
Definition: counter_types.h:22
stat_client_main_t::shared_header
stat_segment_shared_header_t * shared_header
Definition: stat_client.h:52
stat_segment_ls_r
uint32_t * stat_segment_ls_r(uint8_t **patterns, stat_client_main_t *sm)
Definition: stat_client.c:351
c
svmdb_client_t * c
Definition: vpp_get_metrics.c:48
stat_segment_shared_header_t::directory_vector
volatile stat_segment_directory_entry_t * directory_vector
Definition: stat_segment_shared.h:56
get_stat_vector_r
static stat_segment_directory_entry_t * get_stat_vector_r(stat_client_main_t *sm)
Definition: stat_client.c:85
i
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
vec_validate
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment)
Definition: vec.h:523
stat_segment_directory_entry_t::name
char name[128]
Definition: stat_segment_shared.h:44
stat_vec_simple_init
static counter_t * stat_vec_simple_init(counter_t c)
Definition: stat_client.c:206
stat_client_main_t::memory_size
ssize_t memory_size
Definition: stat_client.h:54
copy_data
static stat_segment_data_t copy_data(stat_segment_directory_entry_t *ep, u32 index2, char *name, stat_client_main_t *sm)
Definition: stat_client.c:226
stat_segment.h
STAT_DIR_TYPE_SYMLINK
@ STAT_DIR_TYPE_SYMLINK
Definition: stat_segment_shared.h:28
vec_validate_init_c_string
#define vec_validate_init_c_string(V, S, L)
Make a vector containing a NULL terminated c-string.
Definition: vec.h:1109
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
stat_segment_directory_entry_t
Definition: stat_segment_shared.h:31
size
u32 size
Definition: vhost_user.h:125
index
u32 index
Definition: flow_types.api:221
stat_segment_data_t
Definition: stat_client.h:35
stat_segment_heartbeat_r
double stat_segment_heartbeat_r(stat_client_main_t *sm)
Definition: stat_client.c:172
stat_segment_data_t::combined_counter_vec
vlib_counter_t ** combined_counter_vec
Definition: stat_client.h:44
STAT_COUNTER_HEARTBEAT
@ STAT_COUNTER_HEARTBEAT
Definition: stat_segment.h:29
stat_segment_data_t::type
stat_directory_type_t type
Definition: stat_client.h:38
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
buf
u64 buf
Definition: application.c:493
u32
unsigned int u32
Definition: types.h:88
STAT_DIR_TYPE_SCALAR_INDEX
@ STAT_DIR_TYPE_SCALAR_INDEX
Definition: stat_segment_shared.h:22
stat_client_main
stat_client_main_t stat_client_main
Definition: stat_client.c:35
stat_segment_directory_entry_t::index2
uint32_t index2
Definition: stat_segment_shared.h:38
stat_vec_dup
#define stat_vec_dup(S, V)
Definition: stat_client.c:195
stat_segment_adjust
static void * stat_segment_adjust(stat_client_main_t *sm, void *data)
Definition: stat_client.h:102
vec.h
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
stat_segment_dump_entry_r
stat_segment_data_t * stat_segment_dump_entry_r(uint32_t index, stat_client_main_t *sm)
Definition: stat_client.c:474
u8
unsigned char u8
Definition: types.h:56
stat_segment_heartbeat
double stat_segment_heartbeat(void)
Definition: stat_client.c:189
stat_client_main_t
Definition: stat_client.h:49
stat_segment_data_t::name
char * name
Definition: stat_client.h:37
free
void free(void *p)
Definition: mem.c:42
malloc
void * malloc(size_t size)
Definition: mem.c:33
stat_client.h
rv
int __clib_unused rv
Definition: application.c:491
stat_segment_dump_r
stat_segment_data_t * stat_segment_dump_r(uint32_t *stats, stat_client_main_t *sm)
Definition: stat_client.c:412
stat_segment_dump
stat_segment_data_t * stat_segment_dump(uint32_t *stats)
Definition: stat_client.c:442
stat_segment_dump_entry
stat_segment_data_t * stat_segment_dump_entry(uint32_t index)
Definition: stat_client.c:497
stat_client_free
void stat_client_free(stat_client_main_t *sm)
Definition: stat_client.c:47
stat_segment_directory_entry_t::type
stat_directory_type_t type
Definition: stat_segment_shared.h:33
STAT_DIR_TYPE_ERROR_INDEX
@ STAT_DIR_TYPE_ERROR_INDEX
Definition: stat_segment_shared.h:25
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
stat_segment_shared_header_t::epoch
volatile uint64_t epoch
Definition: stat_segment_shared.h:54
un
vl_api_address_union_t un
Definition: ip_types.api:98