FD.io VPP  v18.10-32-g1161dda
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 "stat_client.h"
32 #include <stdatomic.h>
33 
34 typedef struct
35 {
36  uint64_t current_epoch;
39  ssize_t memory_size;
41 
43 
44 static int
45 recv_fd (int sock)
46 {
47  struct msghdr msg = { 0 };
48  struct cmsghdr *cmsg;
49  int fd = -1;
50  char iobuf[1];
51  struct iovec io = {.iov_base = iobuf,.iov_len = sizeof (iobuf) };
52  union
53  {
54  char buf[CMSG_SPACE (sizeof (fd))];
55  struct cmsghdr align;
56  } u;
57  msg.msg_iov = &io;
58  msg.msg_iovlen = 1;
59  msg.msg_control = u.buf;
60  msg.msg_controllen = sizeof (u.buf);
61 
62  ssize_t size;
63  if ((size = recvmsg (sock, &msg, 0)) < 0)
64  {
65  perror ("recvmsg failed");
66  return -1;
67  }
68  cmsg = CMSG_FIRSTHDR (&msg);
69  if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
70  {
71  memmove (&fd, CMSG_DATA (cmsg), sizeof (fd));
72  }
73  return fd;
74 }
75 
78 {
80  ASSERT (sm->shared_header);
83 }
84 
85 int
86 stat_segment_connect (char *socket_name)
87 {
89  int mfd = -1;
90  int sock;
91 
92  memset (sm, 0, sizeof (*sm));
93  if ((sock = socket (AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
94  {
95  perror ("Couldn't open socket");
96  return -1;
97  }
98 
99  struct sockaddr_un un = { 0 };
100  un.sun_family = AF_UNIX;
101  strncpy ((char *) un.sun_path, socket_name, sizeof (un.sun_path) - 1);
102  if (connect (sock, (struct sockaddr *) &un, sizeof (struct sockaddr_un)) <
103  0)
104  {
105  close (sock);
106  perror ("connect");
107  return -1;
108  }
109 
110  if ((mfd = recv_fd (sock)) < 0)
111  {
112  close (sock);
113  fprintf (stderr, "Receiving file descriptor failed\n");
114  return -1;
115  }
116  close (sock);
117 
118  /* mmap shared memory segment. */
119  void *memaddr;
120  struct stat st = { 0 };
121 
122  if (fstat (mfd, &st) == -1)
123  {
124  perror ("mmap");
125  return -1;
126  }
127  if ((memaddr =
128  mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, mfd, 0)) == MAP_FAILED)
129  {
130  perror ("mmap");
131  return -1;
132  }
133 
134  sm->memory_size = st.st_size;
135  sm->shared_header = memaddr;
136  sm->directory_vector =
138 
139  return 0;
140 }
141 
142 void
144 {
146  munmap (sm->shared_header, sm->memory_size);
147 
148  return;
149 }
150 
151 double
153 {
156  double *hb = stat_segment_pointer (sm->shared_header, vec[4].offset);
157  return *hb;
158 }
159 
162 {
164  stat_segment_data_t result = { 0 };
165  int i;
166  vlib_counter_t **combined_c; /* Combined counter */
167  counter_t **simple_c; /* Simple counter */
168  counter_t *error_base;
169  uint64_t *offset_vector;
170 
171  assert (sm->shared_header);
172 
173  result.type = ep->type;
174  result.name = strdup (ep->name);
175  switch (ep->type)
176  {
178  result.scalar_value = ep->value;
179  break;
180 
182  if (ep->offset == 0)
183  return result;
184  simple_c = stat_segment_pointer (sm->shared_header, ep->offset);
185  result.simple_counter_vec = vec_dup (simple_c);
186  offset_vector =
188  for (i = 0; i < vec_len (simple_c); i++)
189  {
190  counter_t *cb =
191  stat_segment_pointer (sm->shared_header, offset_vector[i]);
192  result.simple_counter_vec[i] = vec_dup (cb);
193  }
194  break;
195 
197  if (ep->offset == 0)
198  return result;
199  combined_c = stat_segment_pointer (sm->shared_header, ep->offset);
200  result.combined_counter_vec = vec_dup (combined_c);
201  offset_vector =
203  for (i = 0; i < vec_len (combined_c); i++)
204  {
205  vlib_counter_t *cb =
206  stat_segment_pointer (sm->shared_header, offset_vector[i]);
207  result.combined_counter_vec[i] = vec_dup (cb);
208  }
209  break;
210 
212  error_base =
215  result.error_value = error_base[ep->index];
216  break;
217 
218  default:
219  fprintf (stderr, "Unknown type: %d", ep->type);
220  }
221  return result;
222 }
223 
224 void
226 {
227  int i, j;
228  for (i = 0; i < vec_len (res); i++)
229  {
230  switch (res[i].type)
231  {
233  for (j = 0; j < vec_len (res[i].simple_counter_vec); j++)
234  vec_free (res[i].simple_counter_vec[j]);
235  vec_free (res[i].simple_counter_vec);
236  break;
238  for (j = 0; j < vec_len (res[i].combined_counter_vec); j++)
239  vec_free (res[i].combined_counter_vec[j]);
240  vec_free (res[i].combined_counter_vec);
241  break;
242  default:
243  ;
244  }
245  free (res[i].name);
246  }
247  vec_free (res);
248 }
249 
250 
251 typedef struct
252 {
253  uint64_t epoch;
255 
256 static void
258 {
260  stat_segment_shared_header_t *shared_header = sm->shared_header;
261  sa->epoch = shared_header->epoch;
262  while (shared_header->in_progress != 0)
263  ;
264 }
265 
266 static bool
268 {
270  stat_segment_shared_header_t *shared_header = sm->shared_header;
271 
272  if (shared_header->epoch != sa->epoch || shared_header->in_progress)
273  return false;
274  return true;
275 }
276 
277 uint32_t *
278 stat_segment_ls (uint8_t ** patterns)
279 {
282 
283  uint32_t *dir = 0;
284  regex_t regex[vec_len (patterns)];
285 
286  int i, j;
287  for (i = 0; i < vec_len (patterns); i++)
288  {
289  int rv = regcomp (&regex[i], (char *) patterns[i], 0);
290  if (rv)
291  {
292  fprintf (stderr, "Could not compile regex %s\n", patterns[i]);
293  return dir;
294  }
295  }
296 
298 
300  for (j = 0; j < vec_len (counter_vec); j++)
301  {
302  for (i = 0; i < vec_len (patterns); i++)
303  {
304  int rv = regexec (&regex[i], counter_vec[j].name, 0, NULL, 0);
305  if (rv == 0)
306  {
307  vec_add1 (dir, j);
308  break;
309  }
310  }
311  if (vec_len (patterns) == 0)
312  vec_add1 (dir, j);
313  }
314 
315  for (i = 0; i < vec_len (patterns); i++)
316  regfree (&regex[i]);
317 
318  if (!stat_segment_access_end (&sa))
319  {
320  /* Failed, clean up */
321  vec_free (dir);
322  return 0;
323 
324  }
325 
326  /* Update last version */
327  sm->current_epoch = sa.epoch;
328  return dir;
329 }
330 
332 stat_segment_dump (uint32_t * stats)
333 {
334  int i;
337  stat_segment_data_t *res = 0;
339 
340  /* Has directory been update? */
341  if (sm->shared_header->epoch != sm->current_epoch)
342  return 0;
343 
345  for (i = 0; i < vec_len (stats); i++)
346  {
347  /* Collect counter */
348  ep = vec_elt_at_index (sm->directory_vector, stats[i]);
349  vec_add1 (res, copy_data (ep));
350  }
351 
352  if (stat_segment_access_end (&sa))
353  return res;
354 
355  fprintf (stderr, "Epoch changed while reading, invalid results\n");
356  // TODO increase counter
357  return 0;
358 }
359 
360 /* Wrapper for accessing vectors from other languages */
361 int
363 {
364  return vec_len (vec);
365 }
366 
367 void
369 {
370  vec_free (vec);
371 }
372 
373 /* Create a vector from a string (or add to existing) */
374 u8 **
375 stat_segment_string_vector (u8 ** string_vector, char *string)
376 {
377  u8 *name = 0;
378  name = vec_dup ((u8 *) string);
379  vec_add1 (string_vector, (u8 *) name);
380  return string_vector;
381 }
382 
384 stat_segment_dump_entry (uint32_t index)
385 {
388  stat_segment_data_t *res = 0;
390 
392 
393  /* Collect counter */
394  ep = vec_elt_at_index (sm->directory_vector, index);
395  vec_add1 (res, copy_data (ep));
396 
397  if (stat_segment_access_end (&sa))
398  return res;
399  return 0;
400 }
401 
402 char *
404 {
405  char *name;
408  ep = vec_elt_at_index (counter_vec, index);
409  name = strdup (ep->name);
410  return name;
411 }
412 
413 /*
414  * fd.io coding-style-patch-verification: ON
415  *
416  * Local Variables:
417  * eval: (c-set-style "gnu")
418  * End:
419  */
stat_segment_data_t copy_data(stat_segment_directory_entry_t *ep)
Definition: stat_client.c:161
static stat_segment_directory_entry_t * get_stat_vector(void)
Definition: stat_client.c:77
int stat_segment_connect(char *socket_name)
Definition: stat_client.c:86
Definition: stat_segment.h:60
stat_segment_data_t * stat_segment_dump_entry(uint32_t index)
Definition: stat_client.c:384
uint64_t index
Definition: stat_segment.h:65
stat_segment_directory_entry_t * directory_vector
Definition: stat_client.c:38
void stat_segment_data_free(stat_segment_data_t *res)
Definition: stat_client.c:225
counter_t ** simple_counter_vec
Definition: stat_client.h:32
#define NULL
Definition: clib.h:57
stat_client_main_t stat_client_main
Definition: stat_client.c:42
static void stat_segment_access_start(stat_segment_access_t *sa)
Definition: stat_client.c:257
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
Combined counter to hold both packets and byte differences.
Definition: counter_types.h:26
int i
unsigned char u8
Definition: types.h:56
atomic_int_fast64_t in_progress
Definition: stat_segment.h:81
#define assert(x)
Definition: dlmalloc.c:30
stat_segment_shared_header_t * shared_header
Definition: stat_client.c:37
static bool stat_segment_access_end(stat_segment_access_t *sa)
Definition: stat_client.c:267
uint64_t value
Definition: stat_segment.h:66
memset(h->entries, 0, sizeof(h->entries[0])*entries)
uint64_t current_epoch
Definition: stat_client.c:36
uint64_t counter_t
64bit counters
Definition: counter_types.h:22
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
uword size
static void * stat_segment_pointer(void *start, uint64_t offset)
Definition: stat_segment.h:94
uint64_t offset
Definition: stat_segment.h:64
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:373
stat_directory_type_t type
Definition: stat_client.h:27
u8 name[64]
Definition: memclnt.api:151
void stat_segment_disconnect(void)
Definition: stat_client.c:143
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
char * stat_segment_index_to_name(uint32_t index)
Definition: stat_client.c:403
uint64_t offset_vector
Definition: stat_segment.h:68
char name[128]
Definition: stat_segment.h:69
uint32_t * stat_segment_ls(uint8_t **patterns)
Definition: stat_client.c:278
u8 ** stat_segment_string_vector(u8 **string_vector, char *string)
Definition: stat_client.c:375
#define ASSERT(truth)
stat_segment_data_t * stat_segment_dump(uint32_t *stats)
Definition: stat_client.c:332
atomic_int_fast64_t epoch
Definition: stat_segment.h:80
static int recv_fd(int sock)
Definition: stat_client.c:45
vlib_counter_t ** combined_counter_vec
Definition: stat_client.h:33
void stat_segment_vec_free(void *vec)
Definition: stat_client.c:368
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
uint64_t error_value
Definition: stat_client.h:31
int stat_segment_vec_len(void *vec)
Definition: stat_client.c:362
atomic_int_fast64_t error_offset
Definition: stat_segment.h:83
double stat_segment_heartbeat(void)
Definition: stat_client.c:152
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".
atomic_int_fast64_t directory_offset
Definition: stat_segment.h:82
stat_directory_type_t type
Definition: stat_segment.h:62