FD.io VPP  v18.01.1-37-g7ea3975
Vector Packet Processing
memory_vlib.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * memory_vlib.c
4  *
5  * Copyright (c) 2009 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 <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <pthread.h>
29 #include <vppinfra/vec.h>
30 #include <vppinfra/hash.h>
31 #include <vppinfra/pool.h>
32 #include <vppinfra/format.h>
33 #include <vppinfra/byte_order.h>
34 #include <vppinfra/elog.h>
35 #include <stdarg.h>
36 #include <vlib/vlib.h>
37 #include <vlib/unix/unix.h>
38 #include <vlibapi/api.h>
39 #include <vlibmemory/api.h>
40 
41 /**
42  * @file
43  * @brief Binary API messaging via shared memory
44  * Low-level, primary provisioning interface
45  */
46 /*? %%clicmd:group_label Binary API CLI %% ?*/
47 /*? %%syscfg:group_label Binary API configuration %% ?*/
48 
49 #define TRACE_VLIB_MEMORY_QUEUE 0
50 
51 #include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */
52 
53 #define vl_typedefs /* define message structures */
55 #undef vl_typedefs
56 
57 /* instantiate all the print functions we know about */
58 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
59 #define vl_printfun
61 #undef vl_printfun
62 
63 static inline void *
65 {
66  vl_print (handle, "vl_api_memclnt_create_t:\n");
67  vl_print (handle, "name: %s\n", a->name);
68  vl_print (handle, "input_queue: 0x%wx\n", a->input_queue);
69  vl_print (handle, "context: %u\n", (unsigned) a->context);
70  vl_print (handle, "ctx_quota: %ld\n", (long) a->ctx_quota);
71  return handle;
72 }
73 
74 static inline void *
76 {
77  vl_print (handle, "vl_api_memclnt_delete_t:\n");
78  vl_print (handle, "index: %u\n", (unsigned) a->index);
79  vl_print (handle, "handle: 0x%wx\n", a->handle);
80  return handle;
81 }
82 
83 static inline void *
85  void *handle)
86 {
87  vl_print (handle, "vl_api_trace_plugin_msg_ids: %s first %u last %u\n",
88  a->plugin_name,
89  clib_host_to_net_u16 (a->first_msg_id),
90  clib_host_to_net_u16 (a->last_msg_id));
91  return handle;
92 }
93 
94 /* instantiate all the endian swap functions we know about */
95 #define vl_endianfun
97 #undef vl_endianfun
98 
99 extern void vl_socket_api_send (vl_api_registration_t * rp, u8 * elem);
100 
101 void
103 {
105  {
106  vl_socket_api_send (rp, elem);
107  }
108  else
109  {
110  vl_msg_api_send_shmem (rp->vl_input_queue, (u8 *) & elem);
111  }
112 }
113 
114 u8 *
116 {
117  serialize_main_t _sm, *sm = &_sm;
118  hash_pair_t *hp;
120 
121  serialize_open_vector (sm, vector);
122 
123  /* serialize the count */
124  serialize_integer (sm, nmsg, sizeof (u32));
125 
126  /* *INDENT-OFF* */
128  ({
129  serialize_likely_small_unsigned_integer (sm, hp->value[0]);
130  serialize_cstring (sm, (char *) hp->key);
131  }));
132  /* *INDENT-ON* */
133 
134  return serialize_close_vector (sm);
135 }
136 
137 /*
138  * vl_api_memclnt_create_internal
139  */
140 
141 u32
143 {
144  vl_api_registration_t **regpp;
145  vl_api_registration_t *regp;
146  svm_region_t *svm;
147  void *oldheap;
148  api_main_t *am = &api_main;
149 
150  ASSERT (vlib_get_thread_index () == 0);
151  pool_get (am->vl_clients, regpp);
152 
153  svm = am->vlib_rp;
154 
155  pthread_mutex_lock (&svm->mutex);
156  oldheap = svm_push_data_heap (svm);
157  *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
158 
159  regp = *regpp;
160  memset (regp, 0, sizeof (*regp));
162  regp->vl_api_registration_pool_index = regpp - am->vl_clients;
163  regp->vlib_rp = svm;
164  regp->shmem_hdr = am->shmem_hdr;
165 
166  regp->vl_input_queue = q;
167  regp->name = format (0, "%s%c", name, 0);
168 
169  pthread_mutex_unlock (&svm->mutex);
170  svm_pop_heap (oldheap);
174 }
175 
176 
177 /*
178  * vl_api_memclnt_create_t_handler
179  */
180 void
182 {
183  vl_api_registration_t **regpp;
184  vl_api_registration_t *regp;
186  svm_region_t *svm;
188  int rv = 0;
189  void *oldheap;
190  api_main_t *am = &api_main;
191 
192  /*
193  * This is tortured. Maintain a vlib-address-space private
194  * pool of client registrations. We use the shared-memory virtual
195  * address of client structure as a handle, to allow direct
196  * manipulation of context quota vbls from the client library.
197  *
198  * This scheme causes trouble w/ API message trace replay, since
199  * some random VA from clib_mem_alloc() certainly won't
200  * occur in the Linux sim. The (very) few places
201  * that care need to use the pool index.
202  *
203  * Putting the registration object(s) into a pool in shared memory and
204  * using the pool index as a handle seems like a great idea.
205  * Unfortunately, each and every reference to that pool would need
206  * to be protected by a mutex:
207  *
208  * Client VLIB
209  * ------ ----
210  * convert pool index to
211  * pointer.
212  * <deschedule>
213  * expand pool
214  * <deschedule>
215  * kaboom!
216  */
217 
218  pool_get (am->vl_clients, regpp);
219 
220  svm = am->vlib_rp;
221 
222  pthread_mutex_lock (&svm->mutex);
223  oldheap = svm_push_data_heap (svm);
224  *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
225 
226  regp = *regpp;
227  memset (regp, 0, sizeof (*regp));
229  regp->vl_api_registration_pool_index = regpp - am->vl_clients;
230  regp->vlib_rp = svm;
231  regp->shmem_hdr = am->shmem_hdr;
232 
234  mp->input_queue;
235 
236  regp->name = format (0, "%s", mp->name);
237  vec_add1 (regp->name, 0);
238 
242 
243  pthread_mutex_unlock (&svm->mutex);
244  svm_pop_heap (oldheap);
245 
246  rp = vl_msg_api_alloc (sizeof (*rp));
247  rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_REPLY);
248  rp->handle = (uword) regp;
252  rp->context = mp->context;
253  rp->response = ntohl (rv);
254  rp->message_table =
256 
257  vl_msg_api_send_shmem (q, (u8 *) & rp);
258 }
259 
260 static int
262 {
263  clib_error_t *error = 0;
264  _vl_msg_api_function_list_elt_t *i;
265 
267  while (i)
268  {
269  error = i->f (client_index);
270  if (error)
271  clib_error_report (error);
272  i = i->next_init_function;
273  }
274  return 0;
275 }
276 
277 /*
278  * vl_api_memclnt_delete_t_handler
279  */
280 void
282 {
283  vl_api_registration_t **regpp;
284  vl_api_registration_t *regp;
286  svm_region_t *svm;
287  void *oldheap;
288  api_main_t *am = &api_main;
289  u32 handle, client_index, epoch;
290 
291  handle = mp->index;
292 
293  if (call_reaper_functions (handle))
294  return;
295 
296  epoch = vl_msg_api_handle_get_epoch (handle);
297  client_index = vl_msg_api_handle_get_index (handle);
298 
299  if (epoch != (am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK))
300  {
302  ("Stale clnt delete index %d old epoch %d cur epoch %d",
303  client_index, epoch,
305  return;
306  }
307 
308  regpp = am->vl_clients + client_index;
309 
310  if (!pool_is_free (am->vl_clients, regpp))
311  {
312  int i;
313  regp = *regpp;
314  svm = am->vlib_rp;
315  int private_registration = 0;
316 
317  /*
318  * Note: the API message handling path will set am->vlib_rp
319  * as appropriate for pairwise / private memory segments
320  */
321  rp = vl_msg_api_alloc (sizeof (*rp));
322  rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE_REPLY);
323  rp->handle = mp->handle;
324  rp->response = 1;
325 
326  vl_msg_api_send_shmem (regp->vl_input_queue, (u8 *) & rp);
327 
328  if (client_index != regp->vl_api_registration_pool_index)
329  {
330  clib_warning ("mismatch client_index %d pool_index %d",
331  client_index, regp->vl_api_registration_pool_index);
332  vl_msg_api_free (rp);
333  return;
334  }
335 
336  /* For horizontal scaling, add a hash table... */
337  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
338  {
339  /* Is this a pairwise / private API segment? */
340  if (am->vlib_private_rps[i] == svm)
341  {
342  /* Note: account for the memfd header page */
343  u64 virtual_base = svm->virtual_base - MMAP_PAGESIZE;
344  u64 virtual_size = svm->virtual_size + MMAP_PAGESIZE;
345 
346  /*
347  * Kill the registration pool element before we make
348  * the index vanish forever
349  */
352 
353  vec_delete (am->vlib_private_rps, 1, i);
354  /* Kill it, accounting for the memfd header page */
355  if (munmap ((void *) virtual_base, virtual_size) < 0)
356  clib_unix_warning ("munmap");
357  /* Reset the queue-length-address cache */
359  private_registration = 1;
360  break;
361  }
362  }
363 
364  /* No dangling references, please */
365  *regpp = 0;
366 
367  if (private_registration == 0)
368  {
371  pthread_mutex_lock (&svm->mutex);
372  oldheap = svm_push_data_heap (svm);
373  /* Poison the old registration */
374  memset (regp, 0xF1, sizeof (*regp));
375  clib_mem_free (regp);
376  pthread_mutex_unlock (&svm->mutex);
377  svm_pop_heap (oldheap);
378  /*
379  * These messages must be freed manually, since they're set up
380  * as "bounce" messages. In the private_registration == 1 case,
381  * we kill the shared-memory segment which contains the message
382  * with munmap.
383  */
384  vl_msg_api_free (mp);
385  }
386  }
387  else
388  {
389  clib_warning ("unknown client ID %d", mp->index);
390  }
391 }
392 
393 void
395 {
398  uword *p;
399  api_main_t *am = &api_main;
400  vl_api_msg_range_t *rp;
401  u8 name[64];
402  u16 first_msg_id = ~0;
403  int rv = -7; /* VNET_API_ERROR_INVALID_VALUE */
404 
406  if (!q)
407  return;
408 
409  if (am->msg_range_by_name == 0)
410  goto out;
411 
412  strncpy ((char *) name, (char *) mp->name, ARRAY_LEN (name) - 1);
413 
414  p = hash_get_mem (am->msg_range_by_name, name);
415  if (p == 0)
416  goto out;
417 
418  rp = vec_elt_at_index (am->msg_ranges, p[0]);
419 
420  first_msg_id = rp->first_msg_id;
421  rv = 0;
422 
423 out:
424 
425  rmp = vl_msg_api_alloc (sizeof (*rmp));
426  rmp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID_REPLY);
427  rmp->context = mp->context;
428  rmp->retval = ntohl (rv);
429  rmp->first_msg_id = ntohs (first_msg_id);
430  vl_msg_api_send_shmem (q, (u8 *) & rmp);
431 }
432 
433 /**
434  * client answered a ping, stave off the grim reaper...
435  */
436 
437 void
439  (vl_api_memclnt_keepalive_reply_t * mp)
440 {
441  vl_api_registration_t *regp;
443 
444  regp = vl_api_client_index_to_registration (mp->context);
445  if (regp)
446  {
447  regp->last_heard = vlib_time_now (vm);
448  regp->unanswered_pings = 0;
449  }
450  else
451  clib_warning ("BUG: anonymous memclnt_keepalive_reply");
452 }
453 
454 /**
455  * We can send ourselves these messages if someone uses the
456  * builtin binary api test tool...
457  */
458 static void
460 {
461  vl_api_memclnt_keepalive_reply_t *rmp;
462  api_main_t *am;
464 
465  am = &api_main;
466  shmem_hdr = am->shmem_hdr;
467 
468  rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
469  memset (rmp, 0, sizeof (*rmp));
470  rmp->_vl_msg_id = ntohs (VL_API_MEMCLNT_KEEPALIVE_REPLY);
471  rmp->context = mp->context;
472  vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & rmp);
473 }
474 
475 void
477 {
478  api_main_t *am = &api_main;
481  u32 nmsg = vec_len (am->api_version_list);
482  int msg_size = sizeof (*rmp) + sizeof (rmp->api_versions[0]) * nmsg;
483  int i;
484 
486  if (q == 0)
487  return;
488 
489  rmp = vl_msg_api_alloc (msg_size);
490  memset (rmp, 0, msg_size);
491  rmp->_vl_msg_id = ntohs (VL_API_API_VERSIONS_REPLY);
492 
493  /* fill in the message */
494  rmp->context = mp->context;
495  rmp->count = htonl (nmsg);
496 
497  for (i = 0; i < nmsg; ++i)
498  {
500  rmp->api_versions[i].major = htonl (vl->major);
501  rmp->api_versions[i].minor = htonl (vl->minor);
502  rmp->api_versions[i].patch = htonl (vl->patch);
503  strncpy ((char *) rmp->api_versions[i].name, vl->name, 64 - 1);
504  }
505 
506  vl_msg_api_send_shmem (q, (u8 *) & rmp);
507 
508 }
509 
510 #define foreach_vlib_api_msg \
511 _(MEMCLNT_CREATE, memclnt_create) \
512 _(MEMCLNT_DELETE, memclnt_delete) \
513 _(GET_FIRST_MSG_ID, get_first_msg_id) \
514 _(MEMCLNT_KEEPALIVE, memclnt_keepalive) \
515 _(MEMCLNT_KEEPALIVE_REPLY, memclnt_keepalive_reply) \
516 _(API_VERSIONS, api_versions)
517 
518 /*
519  * vl_api_init
520  */
521 static int
522 memory_api_init (const char *region_name)
523 {
524  int rv;
525  api_main_t *am = &api_main;
527  vl_msg_api_msg_config_t *c = &cfg;
528 
529  memset (c, 0, sizeof (*c));
530 
531  if ((rv = vl_map_shmem (region_name, 1 /* is_vlib */ )) < 0)
532  return rv;
533 
534 #define _(N,n) do { \
535  c->id = VL_API_##N; \
536  c->name = #n; \
537  c->handler = vl_api_##n##_t_handler; \
538  c->cleanup = vl_noop_handler; \
539  c->endian = vl_api_##n##_t_endian; \
540  c->print = vl_api_##n##_t_print; \
541  c->size = sizeof(vl_api_##n##_t); \
542  c->traced = 1; /* trace, so these msgs print */ \
543  c->replay = 0; /* don't replay client create/delete msgs */ \
544  c->message_bounce = 0; /* don't bounce this message */ \
545  vl_msg_api_config(c);} while (0);
546 
548 #undef _
549 
550  /*
551  * special-case freeing of memclnt_delete messages, so we can
552  * simply munmap pairwise / private API segments...
553  */
554  am->message_bounce[VL_API_MEMCLNT_DELETE] = 1;
555  am->is_mp_safe[VL_API_MEMCLNT_KEEPALIVE_REPLY] = 1;
556 
557  return 0;
558 }
559 
560 #define foreach_histogram_bucket \
561 _(400) \
562 _(200) \
563 _(100) \
564 _(10)
565 
566 typedef enum
567 {
568 #define _(n) SLEEP_##n##_US,
570 #undef _
573 
575 
576 static void memclnt_queue_callback (vlib_main_t * vm);
577 
578 /*
579  * Callback to send ourselves a plugin numbering-space trace msg
580  */
581 static void
582 send_one_plugin_msg_ids_msg (u8 * name, u16 first_msg_id, u16 last_msg_id)
583 {
585  api_main_t *am = &api_main;
588 
589  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
590  memset (mp, 0, sizeof (*mp));
591 
592  mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_TRACE_PLUGIN_MSG_IDS);
593  strncpy ((char *) mp->plugin_name, (char *) name,
594  sizeof (mp->plugin_name) - 1);
595  mp->first_msg_id = clib_host_to_net_u16 (first_msg_id);
596  mp->last_msg_id = clib_host_to_net_u16 (last_msg_id);
597 
598  q = shmem_hdr->vl_input_queue;
599 
600  vl_msg_api_send_shmem (q, (u8 *) & mp);
601 }
602 
603 static void
605 {
608  api_main_t *am = &api_main;
609  svm_region_t *save_vlib_rp = am->vlib_rp;
610  vl_shmem_hdr_t *save_shmem_hdr = am->shmem_hdr;
611 
612  q = regp->vl_input_queue;
613 
614  /*
615  * If the queue head is moving, assume that the client is processing
616  * messages and skip the ping. This heuristic may fail if the queue
617  * is in the same position as last time, net of wrapping; in which
618  * case, the client will receive a keepalive.
619  */
620  if (regp->last_queue_head != q->head)
621  {
622  regp->last_heard = now;
623  regp->unanswered_pings = 0;
624  regp->last_queue_head = q->head;
625  return;
626  }
627 
628  /*
629  * push/pop shared memory segment, so this routine
630  * will work with "normal" as well as "private segment"
631  * memory clients..
632  */
633 
634  am->vlib_rp = regp->vlib_rp;
635  am->shmem_hdr = regp->shmem_hdr;
636 
637  mp = vl_msg_api_alloc (sizeof (*mp));
638  memset (mp, 0, sizeof (*mp));
639  mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MEMCLNT_KEEPALIVE);
640  mp->context = mp->client_index =
644 
645  regp->unanswered_pings++;
646 
647  /* Failure-to-send due to a stuffed queue is absolutely expected */
648  if (unix_shared_memory_queue_add (q, (u8 *) & mp, 1 /* nowait */ ))
649  vl_msg_api_free (mp);
650 
651  am->vlib_rp = save_vlib_rp;
652  am->shmem_hdr = save_shmem_hdr;
653 }
654 
655 static void
657 {
658 
659  vl_api_registration_t **regpp;
660  vl_api_registration_t *regp;
661  static u32 *dead_indices;
662  static u32 *confused_indices;
663 
664  vec_reset_length (dead_indices);
665  vec_reset_length (confused_indices);
666 
667  /* *INDENT-OFF* */
668  pool_foreach (regpp, am->vl_clients,
669  ({
670  regp = *regpp;
671  if (regp)
672  {
673  /* If we haven't heard from this client recently... */
674  if (regp->last_heard < (now - 10.0))
675  {
676  if (regp->unanswered_pings == 2)
677  {
678  unix_shared_memory_queue_t *q;
679  q = regp->vl_input_queue;
680  if (kill (q->consumer_pid, 0) >=0)
681  {
682  clib_warning ("REAPER: lazy binary API client '%s'",
683  regp->name);
684  regp->unanswered_pings = 0;
685  regp->last_heard = now;
686  }
687  else
688  {
689  clib_warning ("REAPER: binary API client '%s' died",
690  regp->name);
691  vec_add1(dead_indices, regpp - am->vl_clients);
692  }
693  }
694  else
695  send_memclnt_keepalive (regp, now);
696  }
697  else
698  regp->unanswered_pings = 0;
699  }
700  else
701  {
702  clib_warning ("NULL client registration index %d",
703  regpp - am->vl_clients);
704  vec_add1 (confused_indices, regpp - am->vl_clients);
705  }
706  }));
707  /* *INDENT-ON* */
708  /* This should "never happen," but if it does, fix it... */
709  if (PREDICT_FALSE (vec_len (confused_indices) > 0))
710  {
711  int i;
712  for (i = 0; i < vec_len (confused_indices); i++)
713  {
714  pool_put_index (am->vl_clients, confused_indices[i]);
715  }
716  }
717 
718  if (PREDICT_FALSE (vec_len (dead_indices) > 0))
719  {
720  int i;
721  svm_region_t *svm;
722  void *oldheap;
723 
724  /* Allow the application to clean up its registrations */
725  for (i = 0; i < vec_len (dead_indices); i++)
726  {
727  regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
728  if (regpp)
729  {
730  u32 handle;
731 
733  (dead_indices[i], shm->application_restarts);
734  (void) call_reaper_functions (handle);
735  }
736  }
737 
738  svm = am->vlib_rp;
739  pthread_mutex_lock (&svm->mutex);
740  oldheap = svm_push_data_heap (svm);
741 
742  for (i = 0; i < vec_len (dead_indices); i++)
743  {
744  regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
745  if (regpp)
746  {
747  /* Is this a pairwise SVM segment? */
748  if ((*regpp)->vlib_rp != svm)
749  {
750  int i;
751  svm_region_t *dead_rp = (*regpp)->vlib_rp;
752  /* Note: account for the memfd header page */
753  u64 virtual_base = dead_rp->virtual_base - MMAP_PAGESIZE;
754  u64 virtual_size = dead_rp->virtual_size + MMAP_PAGESIZE;
755 
756  /* For horizontal scaling, add a hash table... */
757  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
758  if (am->vlib_private_rps[i] == dead_rp)
759  {
760  vec_delete (am->vlib_private_rps, 1, i);
761  goto found;
762  }
763  clib_warning ("private rp %llx AWOL", dead_rp);
764 
765  found:
766  /* Kill it, accounting for the memfd header page */
767  if (munmap ((void *) virtual_base, virtual_size) < 0)
768  clib_unix_warning ("munmap");
769  /* Reset the queue-length-address cache */
771  }
772  else
773  {
774  /* Poison the old registration */
775  memset (*regpp, 0xF3, sizeof (**regpp));
776  clib_mem_free (*regpp);
777  }
778  /* no dangling references, please */
779  *regpp = 0;
780  }
781  else
782  {
783  svm_pop_heap (oldheap);
784  clib_warning ("Duplicate free, client index %d",
785  regpp - am->vl_clients);
786  oldheap = svm_push_data_heap (svm);
787  }
788  }
789 
791 
792  pthread_mutex_unlock (&svm->mutex);
793  svm_pop_heap (oldheap);
794  for (i = 0; i < vec_len (dead_indices); i++)
795  pool_put_index (am->vl_clients, dead_indices[i]);
796  }
797 }
798 
799 
800 static uword
802  vlib_node_runtime_t * node, vlib_frame_t * f)
803 {
804  uword mp;
805  vl_shmem_hdr_t *shm;
807  clib_error_t *e;
808  int rv;
809  api_main_t *am = &api_main;
810  f64 dead_client_scan_time;
811  f64 sleep_time, start_time;
812  f64 vector_rate;
814  clib_error_t *error;
815  int i;
817  uword event_type;
818  uword *event_data = 0;
819  int private_segment_rotor = 0;
820  svm_region_t *vlib_rp;
821  f64 now;
822 
824 
825  if ((rv = memory_api_init (am->region_name)) < 0)
826  {
827  clib_warning ("memory_api_init returned %d, quitting...", rv);
828  return 0;
829  }
830 
831  if ((error = socksvr_api_init (vm)))
832  {
833  clib_error_report (error);
834  clib_warning ("socksvr_api_init failed, quitting...");
835  return 0;
836  }
837 
838  shm = am->shmem_hdr;
839  ASSERT (shm);
840  q = shm->vl_input_queue;
841  ASSERT (q);
842  /* Make a note so we can always find the primary region easily */
843  am->vlib_primary_rp = am->vlib_rp;
844 
846  (vm, vm->api_init_function_registrations, 1 /* call_once */ );
847  if (e)
848  clib_error_report (e);
849 
850  sleep_time = 10.0;
851  dead_client_scan_time = vlib_time_now (vm) + 10.0;
852 
853  /*
854  * Send plugin message range messages for each plugin we loaded
855  */
856  for (i = 0; i < vec_len (am->msg_ranges); i++)
857  {
858  vl_api_msg_range_t *rp = am->msg_ranges + i;
860  rp->last_msg_id);
861  }
862 
863  /*
864  * Save the api message table snapshot, if configured
865  */
866  if (am->save_msg_table_filename)
867  {
868  int fd, rv;
869  u8 *chroot_file;
870  u8 *serialized_message_table;
871 
872  /*
873  * Snapshoot the api message table.
874  */
875  if (strstr ((char *) am->save_msg_table_filename, "..")
876  || index ((char *) am->save_msg_table_filename, '/'))
877  {
878  clib_warning ("illegal save-message-table filename '%s'",
880  goto skip_save;
881  }
882 
883  chroot_file = format (0, "/tmp/%s%c", am->save_msg_table_filename, 0);
884 
885  fd = creat ((char *) chroot_file, 0644);
886 
887  if (fd < 0)
888  {
889  clib_unix_warning ("creat");
890  goto skip_save;
891  }
892 
893  serialized_message_table = vl_api_serialize_message_table (am, 0);
894 
895  rv = write (fd, serialized_message_table,
896  vec_len (serialized_message_table));
897 
898  if (rv != vec_len (serialized_message_table))
899  clib_unix_warning ("write");
900 
901  rv = close (fd);
902  if (rv < 0)
903  clib_unix_warning ("close");
904 
905  vec_free (chroot_file);
906  vec_free (serialized_message_table);
907  }
908 
909 skip_save:
910 
911  /* $$$ pay attention to frame size, control CPU usage */
912  while (1)
913  {
914  i8 *headp;
915  int need_broadcast;
916 
917  /*
918  * There's a reason for checking the queue before
919  * sleeping. If the vlib application crashes, it's entirely
920  * possible for a client to enqueue a connect request
921  * during the process restart interval.
922  *
923  * Unless some force of physics causes the new incarnation
924  * of the application to process the request, the client will
925  * sit and wait for Godot...
926  */
927  vector_rate = vlib_last_vector_length_per_node (vm);
928  start_time = vlib_time_now (vm);
929  while (1)
930  {
931  pthread_mutex_lock (&q->mutex);
932  if (q->cursize == 0)
933  {
934  vm->api_queue_nonempty = 0;
935  pthread_mutex_unlock (&q->mutex);
936 
938  {
939  /* *INDENT-OFF* */
940  ELOG_TYPE_DECLARE (e) =
941  {
942  .format = "q-underflow: len %d",
943  .format_args = "i4",
944  };
945  /* *INDENT-ON* */
946  struct
947  {
948  u32 len;
949  } *ed;
950  ed = ELOG_DATA (&vm->elog_main, e);
951  ed->len = 0;
952  }
953  sleep_time = 20.0;
954  break;
955  }
956 
957  headp = (i8 *) (q->data + sizeof (uword) * q->head);
958  clib_memcpy (&mp, headp, sizeof (uword));
959 
960  q->head++;
961  need_broadcast = (q->cursize == q->maxsize / 2);
962  q->cursize--;
963 
964  if (PREDICT_FALSE (q->head == q->maxsize))
965  q->head = 0;
966  pthread_mutex_unlock (&q->mutex);
967  if (need_broadcast)
968  (void) pthread_cond_broadcast (&q->condvar);
969 
970  vl_msg_api_handler_with_vm_node (am, (void *) mp, vm, node);
971 
972  /* Allow no more than 10us without a pause */
973  if (vlib_time_now (vm) > start_time + 10e-6)
974  {
975  int index = SLEEP_400_US;
976  if (vector_rate > 40.0)
977  sleep_time = 400e-6;
978  else if (vector_rate > 20.0)
979  {
980  index = SLEEP_200_US;
981  sleep_time = 200e-6;
982  }
983  else if (vector_rate >= 1.0)
984  {
985  index = SLEEP_100_US;
986  sleep_time = 100e-6;
987  }
988  else
989  {
990  index = SLEEP_10_US;
991  sleep_time = 10e-6;
992  }
993  vector_rate_histogram[index] += 1;
994  break;
995  }
996  }
997 
998  /*
999  * see if we have any private api shared-memory segments
1000  * If so, push required context variables, and process
1001  * a message.
1002  */
1003  if (PREDICT_FALSE (vec_len (am->vlib_private_rps)))
1004  {
1005  unix_shared_memory_queue_t *save_vlib_input_queue = q;
1006  vl_shmem_hdr_t *save_shmem_hdr = am->shmem_hdr;
1007  svm_region_t *save_vlib_rp = am->vlib_rp;
1008 
1009  vlib_rp = am->vlib_rp = am->vlib_private_rps[private_segment_rotor];
1010 
1011  am->shmem_hdr = (void *) vlib_rp->user_ctx;
1012  q = am->shmem_hdr->vl_input_queue;
1013 
1014  pthread_mutex_lock (&q->mutex);
1015  if (q->cursize > 0)
1016  {
1017  headp = (i8 *) (q->data + sizeof (uword) * q->head);
1018  clib_memcpy (&mp, headp, sizeof (uword));
1019 
1020  q->head++;
1021  need_broadcast = (q->cursize == q->maxsize / 2);
1022  q->cursize--;
1023 
1024  if (PREDICT_FALSE (q->head == q->maxsize))
1025  q->head = 0;
1026  pthread_mutex_unlock (&q->mutex);
1027 
1028  if (need_broadcast)
1029  (void) pthread_cond_broadcast (&q->condvar);
1030 
1031  vl_msg_api_handler_with_vm_node (am, (void *) mp, vm, node);
1032  }
1033  else
1034  pthread_mutex_unlock (&q->mutex);
1035 
1036  q = save_vlib_input_queue;
1037  am->shmem_hdr = save_shmem_hdr;
1038  am->vlib_rp = save_vlib_rp;
1039 
1040  private_segment_rotor++;
1041  if (private_segment_rotor >= vec_len (am->vlib_private_rps))
1042  private_segment_rotor = 0;
1043  }
1044 
1045  vlib_process_wait_for_event_or_clock (vm, sleep_time);
1046  vec_reset_length (event_data);
1047  event_type = vlib_process_get_events (vm, &event_data);
1048  now = vlib_time_now (vm);
1049 
1050  switch (event_type)
1051  {
1052  case QUEUE_SIGNAL_EVENT:
1053  vm->queue_signal_pending = 0;
1054  break;
1055 
1056  case SOCKET_READ_EVENT:
1057  for (i = 0; i < vec_len (event_data); i++)
1058  {
1059  a = pool_elt_at_index (socket_main.process_args, event_data[i]);
1061  (i8 *) a->data);
1062  vec_free (a->data);
1064  }
1065  break;
1066 
1067  /* Timeout... */
1068  case -1:
1069  break;
1070 
1071  default:
1072  clib_warning ("unknown event type %d", event_type);
1073  break;
1074  }
1075 
1076  if (now > dead_client_scan_time)
1077  {
1078  dead_client_scan (am, shm, now);
1079  dead_client_scan_time = vlib_time_now (vm) + 10.0;
1080  }
1081 
1083  {
1084  /* *INDENT-OFF* */
1085  ELOG_TYPE_DECLARE (e) = {
1086  .format = "q-awake: len %d",
1087  .format_args = "i4",
1088  };
1089  /* *INDENT-ON* */
1090  struct
1091  {
1092  u32 len;
1093  } *ed;
1094  ed = ELOG_DATA (&vm->elog_main, e);
1095  ed->len = q->cursize;
1096  }
1097  }
1098 
1099  return 0;
1100 }
1101 /* *INDENT-OFF* */
1103 {
1104  .function = memclnt_process,
1105  .type = VLIB_NODE_TYPE_PROCESS,
1106  .name = "api-rx-from-ring",
1107  .state = VLIB_NODE_STATE_DISABLED,
1108 };
1109 /* *INDENT-ON* */
1110 
1111 
1112 static clib_error_t *
1114  unformat_input_t * input,
1115  vlib_cli_command_t * cli_cmd)
1116 {
1117  u64 total_counts = 0;
1118  int i;
1119 
1120  for (i = 0; i < SLEEP_N_BUCKETS; i++)
1121  {
1122  total_counts += vector_rate_histogram[i];
1123  }
1124 
1125  if (total_counts == 0)
1126  {
1127  vlib_cli_output (vm, "No control-plane activity.");
1128  return 0;
1129  }
1130 
1131 #define _(n) \
1132  do { \
1133  f64 percent; \
1134  percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
1135  / (f64) total_counts; \
1136  percent *= 100.0; \
1137  vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
1138  vector_rate_histogram[SLEEP_##n##_US], \
1139  percent); \
1140  } while (0);
1142 #undef _
1143 
1144  return 0;
1145 }
1146 
1147 /*?
1148  * Display the binary api sleep-time histogram
1149 ?*/
1150 /* *INDENT-OFF* */
1152 {
1153  .path = "show api histogram",
1154  .short_help = "show api histogram",
1155  .function = vl_api_show_histogram_command,
1156 };
1157 /* *INDENT-ON* */
1158 
1159 static clib_error_t *
1161  unformat_input_t * input,
1162  vlib_cli_command_t * cli_cmd)
1163 {
1164  int i;
1165 
1166  for (i = 0; i < SLEEP_N_BUCKETS; i++)
1167  vector_rate_histogram[i] = 0;
1168  return 0;
1169 }
1170 
1171 /*?
1172  * Clear the binary api sleep-time histogram
1173 ?*/
1174 /* *INDENT-OFF* */
1176 {
1177  .path = "clear api histogram",
1178  .short_help = "clear api histogram",
1179  .function = vl_api_clear_histogram_command,
1180 };
1181 /* *INDENT-ON* */
1182 
1183 volatile int **vl_api_queue_cursizes;
1184 
1185 static void
1187 {
1188  int i;
1189  api_main_t *am = &api_main;
1190 
1191  if (PREDICT_FALSE (vec_len (vl_api_queue_cursizes) !=
1192  1 + vec_len (am->vlib_private_rps)))
1193  {
1196 
1197  if (shmem_hdr == 0)
1198  return;
1199 
1200  q = shmem_hdr->vl_input_queue;
1201  if (q == 0)
1202  return;
1203 
1204  vec_add1 (vl_api_queue_cursizes, &q->cursize);
1205 
1206  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
1207  {
1208  svm_region_t *vlib_rp = am->vlib_private_rps[i];
1209 
1210  shmem_hdr = (void *) vlib_rp->user_ctx;
1211  q = shmem_hdr->vl_input_queue;
1212  vec_add1 (vl_api_queue_cursizes, &q->cursize);
1213  }
1214  }
1215 
1216  for (i = 0; i < vec_len (vl_api_queue_cursizes); i++)
1217  {
1218  if (*vl_api_queue_cursizes[i])
1219  {
1220  vm->queue_signal_pending = 1;
1221  vm->api_queue_nonempty = 1;
1223  /* event_type */ QUEUE_SIGNAL_EVENT,
1224  /* event_data */ 0);
1225  break;
1226  }
1227  }
1228 }
1229 
1230 void
1232 {
1233  vlib_node_set_state (vm, memclnt_node.index,
1234  (enable
1235  ? VLIB_NODE_STATE_POLLING
1236  : VLIB_NODE_STATE_DISABLED));
1237 }
1238 
1239 static uword
1241  vlib_node_runtime_t * node, vlib_frame_t * frame)
1242 {
1243  uword n_packets = frame->n_vectors;
1244  uword n_left_from;
1245  u32 *from;
1246  static u8 *long_msg;
1247 
1248  vec_validate (long_msg, 4095);
1249  n_left_from = frame->n_vectors;
1250  from = vlib_frame_args (frame);
1251 
1252  while (n_left_from > 0)
1253  {
1254  u32 bi0;
1255  vlib_buffer_t *b0;
1256  void *msg;
1257  uword msg_len;
1258 
1259  bi0 = from[0];
1260  b0 = vlib_get_buffer (vm, bi0);
1261  from += 1;
1262  n_left_from -= 1;
1263 
1264  msg = b0->data + b0->current_data;
1265  msg_len = b0->current_length;
1266  if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1267  {
1268  ASSERT (long_msg != 0);
1269  _vec_len (long_msg) = 0;
1270  vec_add (long_msg, msg, msg_len);
1271  while (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1272  {
1273  b0 = vlib_get_buffer (vm, b0->next_buffer);
1274  msg = b0->data + b0->current_data;
1275  msg_len = b0->current_length;
1276  vec_add (long_msg, msg, msg_len);
1277  }
1278  msg = long_msg;
1279  }
1281  }
1282 
1283  /* Free what we've been given. */
1284  vlib_buffer_free (vm, vlib_frame_args (frame), n_packets);
1285 
1286  return n_packets;
1287 }
1288 
1289 /* *INDENT-OFF* */
1291  .function = api_rx_from_node,
1292  .type = VLIB_NODE_TYPE_INTERNAL,
1293  .vector_size = 4,
1294  .name = "api-rx-from-node",
1295 };
1296 /* *INDENT-ON* */
1297 
1298 static clib_error_t *
1300 {
1301  atexit (vl_unmap_shmem);
1302  return 0;
1303 }
1304 
1306 
1307 u8 *
1308 format_api_message_rings (u8 * s, va_list * args)
1309 {
1310  api_main_t *am = va_arg (*args, api_main_t *);
1311  vl_shmem_hdr_t *shmem_hdr = va_arg (*args, vl_shmem_hdr_t *);
1312  int main_segment = va_arg (*args, int);
1313  ring_alloc_t *ap;
1314  int i;
1315 
1316  if (shmem_hdr == 0)
1317  return format (s, "%8s %8s %8s %8s %8s\n",
1318  "Owner", "Size", "Nitems", "Hits", "Misses");
1319 
1320  ap = shmem_hdr->vl_rings;
1321 
1322  for (i = 0; i < vec_len (shmem_hdr->vl_rings); i++)
1323  {
1324  s = format (s, "%8s %8d %8d %8d %8d\n",
1325  "vlib", ap->size, ap->nitems, ap->hits, ap->misses);
1326  ap++;
1327  }
1328 
1329  ap = shmem_hdr->client_rings;
1330 
1331  for (i = 0; i < vec_len (shmem_hdr->client_rings); i++)
1332  {
1333  s = format (s, "%8s %8d %8d %8d %8d\n",
1334  "clnt", ap->size, ap->nitems, ap->hits, ap->misses);
1335  ap++;
1336  }
1337 
1338  if (main_segment)
1339  {
1340  s = format (s, "%d ring miss fallback allocations\n", am->ring_misses);
1341  s = format
1342  (s,
1343  "%d application restarts, %d reclaimed msgs, %d garbage collects\n",
1344  shmem_hdr->application_restarts, shmem_hdr->restart_reclaims,
1345  shmem_hdr->garbage_collects);
1346  }
1347  return s;
1348 }
1349 
1350 
1351 static clib_error_t *
1353  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1354 {
1355  int i;
1357  api_main_t *am = &api_main;
1358 
1359  /* First, dump the primary region rings.. */
1360 
1361  if (am->vlib_primary_rp == 0 || am->vlib_primary_rp->user_ctx == 0)
1362  {
1363  vlib_cli_output (vm, "Shared memory segment not initialized...\n");
1364  return 0;
1365  }
1366 
1367  shmem_hdr = (void *) am->vlib_primary_rp->user_ctx;
1368 
1369  vlib_cli_output (vm, "Main API segment rings:");
1370 
1372  0 /* print header */ , 0 /* notused */ );
1373 
1375  shmem_hdr, 1 /* main segment */ );
1376 
1377  for (i = 0; i < vec_len (am->vlib_private_rps); i++)
1378  {
1379  svm_region_t *vlib_rp = am->vlib_private_rps[i];
1380  shmem_hdr = (void *) vlib_rp->user_ctx;
1381  vl_api_registration_t **regpp;
1382  vl_api_registration_t *regp = 0;
1383 
1384  /* For horizontal scaling, add a hash table... */
1385  /* *INDENT-OFF* */
1386  pool_foreach (regpp, am->vl_clients,
1387  ({
1388  regp = *regpp;
1389  if (regp && regp->vlib_rp == vlib_rp)
1390  {
1391  vlib_cli_output (vm, "%s segment rings:", regp->name);
1392  goto found;
1393  }
1394  }));
1395  vlib_cli_output (vm, "regp %llx not found?", regp);
1396  continue;
1397  /* *INDENT-ON* */
1398  found:
1400  0 /* print header */ , 0 /* notused */ );
1402  shmem_hdr, 0 /* main segment */ );
1403  }
1404 
1405  return 0;
1406 }
1407 
1409  __attribute__ ((weak));
1410 
1411 void
1413 {
1414 }
1415 
1416 static clib_error_t *
1418  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1419 {
1420  vl_api_registration_t **regpp, *regp;
1422  char *health;
1423  api_main_t *am = &api_main;
1424  u32 *confused_indices = 0;
1425 
1426  if (!pool_elts (am->vl_clients))
1427  goto socket_clients;
1428  vlib_cli_output (vm, "Shared memory clients");
1429  vlib_cli_output (vm, "%16s %8s %14s %18s %s",
1430  "Name", "PID", "Queue Length", "Queue VA", "Health");
1431 
1432  /* *INDENT-OFF* */
1433  pool_foreach (regpp, am->vl_clients,
1434  ({
1435  regp = *regpp;
1436 
1437  if (regp)
1438  {
1439  if (regp->unanswered_pings > 0)
1440  health = "questionable";
1441  else
1442  health = "OK";
1443 
1444  q = regp->vl_input_queue;
1445 
1446  vlib_cli_output (vm, "%16s %8d %14d 0x%016llx %s\n",
1447  regp->name, q->consumer_pid, q->cursize,
1448  q, health);
1449  }
1450  else
1451  {
1452  clib_warning ("NULL client registration index %d",
1453  regpp - am->vl_clients);
1454  vec_add1 (confused_indices, regpp - am->vl_clients);
1455  }
1456  }));
1457  /* *INDENT-ON* */
1458 
1459  /* This should "never happen," but if it does, fix it... */
1460  if (PREDICT_FALSE (vec_len (confused_indices) > 0))
1461  {
1462  int i;
1463  for (i = 0; i < vec_len (confused_indices); i++)
1464  {
1465  pool_put_index (am->vl_clients, confused_indices[i]);
1466  }
1467  }
1468  vec_free (confused_indices);
1469 
1470  if (am->missing_clients)
1471  vlib_cli_output (vm, "%u messages with missing clients",
1472  am->missing_clients);
1473 socket_clients:
1474  dump_socket_clients (vm, am);
1475 
1476  return 0;
1477 }
1478 
1479 static clib_error_t *
1481  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1482 {
1483  api_main_t *am = &api_main;
1484 
1485  // check if rx_trace and tx_trace are not null pointers
1486 
1487  if (am->rx_trace == 0)
1488  {
1489  vlib_cli_output (vm, "RX Trace disabled\n");
1490  }
1491  else
1492  {
1493  if (am->rx_trace->enabled == 0)
1494  vlib_cli_output (vm, "RX Trace disabled\n");
1495  else
1496  vlib_cli_output (vm, "RX Trace enabled\n");
1497  }
1498 
1499  if (am->tx_trace == 0)
1500  {
1501  vlib_cli_output (vm, "TX Trace disabled\n");
1502  }
1503  else
1504  {
1505  if (am->tx_trace->enabled == 0)
1506  vlib_cli_output (vm, "TX Trace disabled\n");
1507  else
1508  vlib_cli_output (vm, "TX Trace enabled\n");
1509  }
1510 
1511  return 0;
1512 }
1513 
1514 /* *INDENT-OFF* */
1515 VLIB_CLI_COMMAND (cli_show_api_command, static) =
1516 {
1517  .path = "show api",
1518  .short_help = "Show API information",
1519 };
1520 /* *INDENT-ON* */
1521 
1522 /*?
1523  * Display binary api message allocation ring statistics
1524 ?*/
1525 /* *INDENT-OFF* */
1526 VLIB_CLI_COMMAND (cli_show_api_ring_command, static) =
1527 {
1528  .path = "show api ring-stats",
1529  .short_help = "Message ring statistics",
1530  .function = vl_api_ring_command,
1531 };
1532 /* *INDENT-ON* */
1533 
1534 /*?
1535  * Display current api client connections
1536 ?*/
1537 /* *INDENT-OFF* */
1538 VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
1539 {
1540  .path = "show api clients",
1541  .short_help = "Client information",
1542  .function = vl_api_client_command,
1543 };
1544 /* *INDENT-ON* */
1545 
1546 /*?
1547  * Display the current api message tracing status
1548 ?*/
1549 /* *INDENT-OFF* */
1550 VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
1551 {
1552  .path = "show api trace-status",
1553  .short_help = "Display API trace status",
1554  .function = vl_api_status_command,
1555 };
1556 /* *INDENT-ON* */
1557 
1558 static clib_error_t *
1560  unformat_input_t * input,
1561  vlib_cli_command_t * cli_cmd)
1562 {
1563  api_main_t *am = &api_main;
1564  int i;
1565  int verbose = 0;
1566 
1567  if (unformat (input, "verbose"))
1568  verbose = 1;
1569 
1570 
1571  if (verbose == 0)
1572  vlib_cli_output (vm, "%-4s %s", "ID", "Name");
1573  else
1574  vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
1575  "MP-safe");
1576 
1577  for (i = 1; i < vec_len (am->msg_names); i++)
1578  {
1579  if (verbose == 0)
1580  {
1581  vlib_cli_output (vm, "%-4d %s", i,
1582  am->msg_names[i] ? am->msg_names[i] :
1583  " [no handler]");
1584  }
1585  else
1586  {
1587  vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
1588  am->msg_names[i] ? am->msg_names[i] :
1589  " [no handler]", am->message_bounce[i],
1590  am->is_mp_safe[i]);
1591  }
1592  }
1593 
1594  return 0;
1595 }
1596 
1597 /*?
1598  * Display the current api message decode tables
1599 ?*/
1600 /* *INDENT-OFF* */
1601 VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
1602 {
1603  .path = "show api message-table",
1604  .short_help = "Message Table",
1605  .function = vl_api_message_table_command,
1606 };
1607 /* *INDENT-ON* */
1608 
1609 static clib_error_t *
1611  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1612 {
1613  u32 nitems = 1024;
1615  api_main_t *am = &api_main;
1616 
1617  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1618  {
1619  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
1620  goto configure;
1621  else if (unformat (input, "tx nitems %u", &nitems)
1622  || unformat (input, "tx"))
1623  {
1624  which = VL_API_TRACE_RX;
1625  goto configure;
1626  }
1627  else if (unformat (input, "on rx"))
1628  {
1630  }
1631  else if (unformat (input, "on tx"))
1632  {
1634  }
1635  else if (unformat (input, "on"))
1636  {
1638  }
1639  else if (unformat (input, "off"))
1640  {
1643  }
1644  else if (unformat (input, "free"))
1645  {
1650  }
1651  else if (unformat (input, "debug on"))
1652  {
1653  am->msg_print_flag = 1;
1654  }
1655  else if (unformat (input, "debug off"))
1656  {
1657  am->msg_print_flag = 0;
1658  }
1659  else
1660  return clib_error_return (0, "unknown input `%U'",
1661  format_unformat_error, input);
1662  }
1663  return 0;
1664 
1665 configure:
1666  if (vl_msg_api_trace_configure (am, which, nitems))
1667  {
1668  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
1669  which, nitems);
1670  }
1671 
1672  return 0;
1673 }
1674 
1675 /*?
1676  * Control the binary API trace mechanism
1677 ?*/
1678 /* *INDENT-OFF* */
1679 VLIB_CLI_COMMAND (trace, static) =
1680 {
1681  .path = "set api-trace [on][on tx][on rx][off][free][debug on][debug off]",
1682  .short_help = "API trace",
1683  .function = vl_api_trace_command,
1684 };
1685 /* *INDENT-ON* */
1686 
1687 clib_error_t *
1689 {
1690  api_main_t *am = &api_main;
1691  svm_map_region_args_t _a, *a = &_a;
1692  clib_error_t *error;
1693 
1694  memset (a, 0, sizeof (*a));
1695  a->root_path = am->root_path;
1697  a->baseva = (am->global_baseva != 0) ?
1699  a->size = (am->global_size != 0) ? am->global_size : SVM_GLOBAL_REGION_SIZE;
1700  a->flags = SVM_FLAGS_NODATA;
1701  a->uid = am->api_uid;
1702  a->gid = am->api_gid;
1703  a->pvt_heap_size =
1704  (am->global_pvt_heap_size !=
1706 
1708 
1710 
1711  return error;
1712 }
1713 
1715 
1716 void
1717 vl_set_memory_region_name (const char *name)
1718 {
1719  api_main_t *am = &api_main;
1720 
1721  am->region_name = name;
1722 }
1723 
1724 static int
1726 {
1727  int len0, len1, clen;
1728 
1729  len0 = vec_len (a0->name);
1730  len1 = vec_len (a1->name);
1731  clen = len0 < len1 ? len0 : len1;
1732  return (strncmp ((char *) a0->name, (char *) a1->name, clen));
1733 }
1734 
1735 static u8 *
1736 format_api_msg_range (u8 * s, va_list * args)
1737 {
1738  vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
1739 
1740  if (rp == 0)
1741  s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
1742  else
1743  s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
1744  rp->last_msg_id);
1745 
1746  return s;
1747 }
1748 
1749 static clib_error_t *
1751  unformat_input_t * input,
1752  vlib_cli_command_t * cli_cmd)
1753 {
1754  api_main_t *am = &api_main;
1755  vl_api_msg_range_t *rp = 0;
1756  int i;
1757 
1758  if (vec_len (am->msg_ranges) == 0)
1759  {
1760  vlib_cli_output (vm, "No plugin API message ranges configured...");
1761  return 0;
1762  }
1763 
1764  rp = vec_dup (am->msg_ranges);
1765 
1767 
1768  vlib_cli_output (vm, "Plugin API message ID ranges...\n");
1769  vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
1770 
1771  for (i = 0; i < vec_len (rp); i++)
1772  vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
1773 
1774  vec_free (rp);
1775 
1776  return 0;
1777 }
1778 
1779 /*?
1780  * Display the plugin binary API message range table
1781 ?*/
1782 /* *INDENT-OFF* */
1783 VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
1784 {
1785  .path = "show api plugin",
1786  .short_help = "show api plugin",
1787  .function = vl_api_show_plugin_command,
1788 };
1789 /* *INDENT-ON* */
1790 
1791 static void
1793 {
1794  vl_api_rpc_call_reply_t *rmp;
1795  int (*fp) (void *);
1796  i32 rv = 0;
1798 
1799  if (mp->function == 0)
1800  {
1801  rv = -1;
1802  clib_warning ("rpc NULL function pointer");
1803  }
1804 
1805  else
1806  {
1807  if (mp->need_barrier_sync)
1809 
1810  fp = uword_to_pointer (mp->function, int (*)(void *));
1811  rv = fp (mp->data);
1812 
1813  if (mp->need_barrier_sync)
1815  }
1816 
1817  if (mp->send_reply)
1818  {
1821  if (q)
1822  {
1823  rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
1824  rmp->_vl_msg_id = ntohs (VL_API_RPC_CALL_REPLY);
1825  rmp->context = mp->context;
1826  rmp->retval = rv;
1827  vl_msg_api_send_shmem (q, (u8 *) & rmp);
1828  }
1829  }
1830  if (mp->multicast)
1831  {
1832  clib_warning ("multicast not yet implemented...");
1833  }
1834 }
1835 
1836 static void
1837 vl_api_rpc_call_reply_t_handler (vl_api_rpc_call_reply_t * mp)
1838 {
1839  clib_warning ("unimplemented");
1840 }
1841 
1842 void
1844 {
1845  api_main_t *am = &api_main;
1848  int i;
1849 
1850  /*
1851  * Use the "normal" control-plane mechanism for the main thread.
1852  * Well, almost. if the main input queue is full, we cannot
1853  * block. Otherwise, we can expect a barrier sync timeout.
1854  */
1855  q = shmem_hdr->vl_input_queue;
1856 
1857  for (i = 0; i < vec_len (vm->pending_rpc_requests); i++)
1858  {
1859  while (pthread_mutex_trylock (&q->mutex))
1861 
1863  {
1864  pthread_mutex_unlock (&q->mutex);
1866  while (pthread_mutex_trylock (&q->mutex))
1868  }
1869 
1871 
1872  pthread_mutex_unlock (&q->mutex);
1873  }
1874  _vec_len (vm->pending_rpc_requests) = 0;
1875 }
1876 
1877 always_inline void
1878 vl_api_rpc_call_main_thread_inline (void *fp, u8 * data, u32 data_length,
1879  u8 force_rpc)
1880 {
1881  vl_api_rpc_call_t *mp;
1883 
1884  /* Main thread and not a forced RPC: call the function directly */
1885  if ((force_rpc == 0) && (vlib_get_thread_index () == 0))
1886  {
1887  void (*call_fp) (void *);
1888 
1890 
1891  call_fp = fp;
1892  call_fp (data);
1893 
1895  return;
1896  }
1897 
1898  /* Otherwise, actually do an RPC */
1899  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + data_length);
1900 
1901  memset (mp, 0, sizeof (*mp));
1902  clib_memcpy (mp->data, data, data_length);
1903  mp->_vl_msg_id = ntohs (VL_API_RPC_CALL);
1904  mp->function = pointer_to_uword (fp);
1905  mp->need_barrier_sync = 1;
1906 
1907  vec_add1 (vm->pending_rpc_requests, (uword) mp);
1908 }
1909 
1910 /*
1911  * Check if called from worker threads.
1912  * If so, make rpc call of fp through shmem.
1913  * Otherwise, call fp directly
1914  */
1915 void
1916 vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
1917 {
1918  vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */
1919  0);
1920 }
1921 
1922 /*
1923  * Always make rpc call of fp through shmem, useful for calling from threads
1924  * not setup as worker threads, such as DPDK callback thread
1925  */
1926 void
1927 vl_api_force_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
1928 {
1929  vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */
1930  1);
1931 }
1932 
1933 static void
1935 {
1936  api_main_t *am = &api_main;
1937  vl_api_msg_range_t *rp;
1938  uword *p;
1939 
1940  /* Noop (except for tracing) during normal operation */
1941  if (am->replay_in_progress == 0)
1942  return;
1943 
1945  if (p == 0)
1946  {
1947  clib_warning ("WARNING: traced plugin '%s' not in current image",
1948  mp->plugin_name);
1949  return;
1950  }
1951 
1952  rp = vec_elt_at_index (am->msg_ranges, p[0]);
1953  if (rp->first_msg_id != clib_net_to_host_u16 (mp->first_msg_id))
1954  {
1955  clib_warning ("WARNING: traced plugin '%s' first message id %d not %d",
1956  mp->plugin_name, clib_net_to_host_u16 (mp->first_msg_id),
1957  rp->first_msg_id);
1958  }
1959 
1960  if (rp->last_msg_id != clib_net_to_host_u16 (mp->last_msg_id))
1961  {
1962  clib_warning ("WARNING: traced plugin '%s' last message id %d not %d",
1963  mp->plugin_name, clib_net_to_host_u16 (mp->last_msg_id),
1964  rp->last_msg_id);
1965  }
1966 }
1967 
1968 #define foreach_rpc_api_msg \
1969 _(RPC_CALL,rpc_call) \
1970 _(RPC_CALL_REPLY,rpc_call_reply)
1971 
1972 #define foreach_plugin_trace_msg \
1973 _(TRACE_PLUGIN_MSG_IDS,trace_plugin_msg_ids)
1974 
1975 /*
1976  * Set the rpc callback at our earliest possible convenience.
1977  * This avoids ordering issues between thread_init() -> start_workers and
1978  * an init function which we could define here. If we ever intend to use
1979  * vlib all by itself, we can't create a link-time dependency on
1980  * an init function here and a typical "call foo_init first"
1981  * guitar lick.
1982  */
1983 
1984 extern void *rpc_call_main_thread_cb_fn;
1985 
1986 static clib_error_t *
1988 {
1989  api_main_t *am = &api_main;
1990 #define _(N,n) \
1991  vl_msg_api_set_handlers(VL_API_##N, #n, \
1992  vl_api_##n##_t_handler, \
1993  vl_noop_handler, \
1994  vl_noop_handler, \
1995  vl_api_##n##_t_print, \
1996  sizeof(vl_api_##n##_t), 0 /* do not trace */);
1998 #undef _
1999 
2000 #define _(N,n) \
2001  vl_msg_api_set_handlers(VL_API_##N, #n, \
2002  vl_api_##n##_t_handler, \
2003  vl_noop_handler, \
2004  vl_noop_handler, \
2005  vl_api_##n##_t_print, \
2006  sizeof(vl_api_##n##_t), 1 /* do trace */);
2008 #undef _
2009 
2010  /* No reason to halt the parade to create a trace record... */
2011  am->is_mp_safe[VL_API_TRACE_PLUGIN_MSG_IDS] = 1;
2012  rpc_call_main_thread_cb_fn = vl_api_rpc_call_main_thread;
2013  return 0;
2014 }
2015 
2017 
2018 typedef enum
2019 {
2024 } vl_api_replay_t;
2025 
2026 u8 *
2027 format_vl_msg_api_trace_status (u8 * s, va_list * args)
2028 {
2029  api_main_t *am = va_arg (*args, api_main_t *);
2030  vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
2031  vl_api_trace_t *tp;
2032  char *trace_name;
2033 
2034  switch (which)
2035  {
2036  case VL_API_TRACE_TX:
2037  tp = am->tx_trace;
2038  trace_name = "TX trace";
2039  break;
2040 
2041  case VL_API_TRACE_RX:
2042  tp = am->rx_trace;
2043  trace_name = "RX trace";
2044  break;
2045 
2046  default:
2047  abort ();
2048  }
2049 
2050  if (tp == 0)
2051  {
2052  s = format (s, "%s: not yet configured.\n", trace_name);
2053  return s;
2054  }
2055 
2056  s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
2057  trace_name, vec_len (tp->traces), tp->nitems,
2058  tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
2059  return s;
2060 }
2061 
2063  __attribute__ ((weak));
2064 void
2066 {
2067 }
2068 
2069 static void
2071  u32 first_index, u32 last_index,
2072  vl_api_replay_t which)
2073 {
2074  vl_api_trace_file_header_t *hp;
2075  int i, fd;
2076  struct stat statb;
2077  size_t file_size;
2078  u8 *msg;
2079  u8 endian_swap_needed = 0;
2080  api_main_t *am = &api_main;
2081  u8 *tmpbuf = 0;
2082  u32 nitems;
2083  void **saved_print_handlers = 0;
2084 
2085  fd = open ((char *) filename, O_RDONLY);
2086 
2087  if (fd < 0)
2088  {
2089  vlib_cli_output (vm, "Couldn't open %s\n", filename);
2090  return;
2091  }
2092 
2093  if (fstat (fd, &statb) < 0)
2094  {
2095  vlib_cli_output (vm, "Couldn't stat %s\n", filename);
2096  close (fd);
2097  return;
2098  }
2099 
2100  if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
2101  {
2102  vlib_cli_output (vm, "File not plausible: %s\n", filename);
2103  close (fd);
2104  return;
2105  }
2106 
2107  file_size = statb.st_size;
2108  file_size = (file_size + 4095) & ~(4096);
2109 
2110  hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
2111 
2112  if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
2113  {
2114  vlib_cli_output (vm, "mmap failed: %s\n", filename);
2115  close (fd);
2116  return;
2117  }
2118  close (fd);
2119 
2120  if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
2121  || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
2122  endian_swap_needed = 1;
2123 
2124  if (endian_swap_needed)
2125  nitems = ntohl (hp->nitems);
2126  else
2127  nitems = hp->nitems;
2128 
2129  if (last_index == (u32) ~ 0)
2130  {
2131  last_index = nitems - 1;
2132  }
2133 
2134  if (first_index >= nitems || last_index >= nitems)
2135  {
2136  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
2137  first_index, last_index, nitems - 1);
2138  munmap (hp, file_size);
2139  return;
2140  }
2141  if (hp->wrapped)
2142  vlib_cli_output (vm,
2143  "Note: wrapped/incomplete trace, results may vary\n");
2144 
2145  if (which == CUSTOM_DUMP)
2146  {
2147  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
2149  }
2150 
2151 
2152  msg = (u8 *) (hp + 1);
2153 
2154  for (i = 0; i < first_index; i++)
2155  {
2156  trace_cfg_t *cfgp;
2157  int size;
2158  u16 msg_id;
2159 
2160  size = clib_host_to_net_u32 (*(u32 *) msg);
2161  msg += sizeof (u32);
2162 
2164  msg_id = ntohs (*((u16 *) msg));
2165  else
2166  msg_id = *((u16 *) msg);
2167 
2168  cfgp = am->api_trace_cfg + msg_id;
2169  if (!cfgp)
2170  {
2171  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
2172  munmap (hp, file_size);
2173  return;
2174  }
2175  msg += size;
2176  }
2177 
2178  if (which == REPLAY)
2179  am->replay_in_progress = 1;
2180 
2181  for (; i <= last_index; i++)
2182  {
2183  trace_cfg_t *cfgp;
2184  u16 *msg_idp;
2185  u16 msg_id;
2186  int size;
2187 
2188  if (which == DUMP)
2189  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
2190 
2191  size = clib_host_to_net_u32 (*(u32 *) msg);
2192  msg += sizeof (u32);
2193 
2195  msg_id = ntohs (*((u16 *) msg));
2196  else
2197  msg_id = *((u16 *) msg);
2198 
2199  cfgp = am->api_trace_cfg + msg_id;
2200  if (!cfgp)
2201  {
2202  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
2203  munmap (hp, file_size);
2204  vec_free (tmpbuf);
2205  am->replay_in_progress = 0;
2206  return;
2207  }
2208 
2209  /* Copy the buffer (from the read-only mmap'ed file) */
2210  vec_validate (tmpbuf, size - 1 + sizeof (uword));
2211  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
2212  memset (tmpbuf, 0xf, sizeof (uword));
2213 
2214  /*
2215  * Endian swap if needed. All msg data is supposed to be
2216  * in network byte order. All msg handlers are supposed to
2217  * know that. The generic message dumpers don't know that.
2218  * One could fix apigen, I suppose.
2219  */
2220  if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
2221  {
2222  void (*endian_fp) (void *);
2223  if (msg_id >= vec_len (am->msg_endian_handlers)
2224  || (am->msg_endian_handlers[msg_id] == 0))
2225  {
2226  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
2227  munmap (hp, file_size);
2228  vec_free (tmpbuf);
2229  am->replay_in_progress = 0;
2230  return;
2231  }
2232  endian_fp = am->msg_endian_handlers[msg_id];
2233  (*endian_fp) (tmpbuf + sizeof (uword));
2234  }
2235 
2236  /* msg_id always in network byte order */
2238  {
2239  msg_idp = (u16 *) (tmpbuf + sizeof (uword));
2240  *msg_idp = msg_id;
2241  }
2242 
2243  switch (which)
2244  {
2245  case CUSTOM_DUMP:
2246  case DUMP:
2247  if (msg_id < vec_len (am->msg_print_handlers) &&
2248  am->msg_print_handlers[msg_id])
2249  {
2250  u8 *(*print_fp) (void *, void *);
2251 
2252  print_fp = (void *) am->msg_print_handlers[msg_id];
2253  (*print_fp) (tmpbuf + sizeof (uword), vm);
2254  }
2255  else
2256  {
2257  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
2258  msg_id);
2259  break;
2260  }
2261  break;
2262 
2263  case INITIALIZERS:
2264  if (msg_id < vec_len (am->msg_print_handlers) &&
2265  am->msg_print_handlers[msg_id])
2266  {
2267  u8 *s;
2268  int j;
2269  u8 *(*print_fp) (void *, void *);
2270 
2271  print_fp = (void *) am->msg_print_handlers[msg_id];
2272 
2273  vlib_cli_output (vm, "/*");
2274 
2275  (*print_fp) (tmpbuf + sizeof (uword), vm);
2276  vlib_cli_output (vm, "*/\n");
2277 
2278  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
2279  am->msg_names[msg_id], i,
2280  am->api_trace_cfg[msg_id].size);
2281 
2282  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
2283  {
2284  if ((j & 7) == 0)
2285  s = format (s, "\n ");
2286  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
2287  }
2288  s = format (s, "\n};\n%c", 0);
2289  vlib_cli_output (vm, (char *) s);
2290  vec_free (s);
2291  }
2292  break;
2293 
2294  case REPLAY:
2295  if (msg_id < vec_len (am->msg_print_handlers) &&
2296  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
2297  {
2298  void (*handler) (void *);
2299 
2300  handler = (void *) am->msg_handlers[msg_id];
2301 
2302  if (!am->is_mp_safe[msg_id])
2304  (*handler) (tmpbuf + sizeof (uword));
2305  if (!am->is_mp_safe[msg_id])
2307  }
2308  else
2309  {
2310  if (cfgp->replay_enable)
2311  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
2312  msg_id);
2313  break;
2314  }
2315  break;
2316  }
2317 
2318  _vec_len (tmpbuf) = 0;
2319  msg += size;
2320  }
2321 
2322  if (saved_print_handlers)
2323  {
2324  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
2325  vec_len (am->msg_print_handlers) * sizeof (void *));
2326  vec_free (saved_print_handlers);
2327  }
2328 
2329  munmap (hp, file_size);
2330  vec_free (tmpbuf);
2331  am->replay_in_progress = 0;
2332 }
2333 
2334 static clib_error_t *
2336  unformat_input_t * input, vlib_cli_command_t * cmd)
2337 {
2338  u32 nitems = 256 << 10;
2339  api_main_t *am = &api_main;
2341  u8 *filename;
2342  u32 first = 0;
2343  u32 last = (u32) ~ 0;
2344  FILE *fp;
2345  int rv;
2346 
2347  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2348  {
2349  if (unformat (input, "on") || unformat (input, "enable"))
2350  {
2351  if (unformat (input, "nitems %d", &nitems))
2352  ;
2353  vl_msg_api_trace_configure (am, which, nitems);
2354  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
2355  }
2356  else if (unformat (input, "off"))
2357  {
2358  vl_msg_api_trace_onoff (am, which, 0);
2359  }
2360  else if (unformat (input, "save %s", &filename))
2361  {
2362  u8 *chroot_filename;
2363  if (strstr ((char *) filename, "..")
2364  || index ((char *) filename, '/'))
2365  {
2366  vlib_cli_output (vm, "illegal characters in filename '%s'",
2367  filename);
2368  return 0;
2369  }
2370 
2371  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
2372 
2373  vec_free (filename);
2374 
2375  fp = fopen ((char *) chroot_filename, "w");
2376  if (fp == NULL)
2377  {
2378  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
2379  return 0;
2380  }
2381  rv = vl_msg_api_trace_save (am, which, fp);
2382  fclose (fp);
2383  if (rv == -1)
2384  vlib_cli_output (vm, "API Trace data not present\n");
2385  else if (rv == -2)
2386  vlib_cli_output (vm, "File for writing is closed\n");
2387  else if (rv == -10)
2388  vlib_cli_output (vm, "Error while writing header to file\n");
2389  else if (rv == -11)
2390  vlib_cli_output (vm, "Error while writing trace to file\n");
2391  else if (rv == -12)
2392  vlib_cli_output (vm,
2393  "Error while writing end of buffer trace to file\n");
2394  else if (rv == -13)
2395  vlib_cli_output (vm,
2396  "Error while writing start of buffer trace to file\n");
2397  else if (rv < 0)
2398  vlib_cli_output (vm, "Unkown error while saving: %d", rv);
2399  else
2400  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
2401  vec_free (chroot_filename);
2402  }
2403  else if (unformat (input, "dump %s", &filename))
2404  {
2405  vl_msg_api_process_file (vm, filename, first, last, DUMP);
2406  }
2407  else if (unformat (input, "custom-dump %s", &filename))
2408  {
2409  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
2410  }
2411  else if (unformat (input, "replay %s", &filename))
2412  {
2413  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
2414  }
2415  else if (unformat (input, "initializers %s", &filename))
2416  {
2417  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
2418  }
2419  else if (unformat (input, "tx"))
2420  {
2421  which = VL_API_TRACE_TX;
2422  }
2423  else if (unformat (input, "first %d", &first))
2424  {
2425  ;
2426  }
2427  else if (unformat (input, "last %d", &last))
2428  {
2429  ;
2430  }
2431  else if (unformat (input, "status"))
2432  {
2434  am, which);
2435  }
2436  else if (unformat (input, "free"))
2437  {
2438  vl_msg_api_trace_onoff (am, which, 0);
2439  vl_msg_api_trace_free (am, which);
2440  }
2441  else if (unformat (input, "post-mortem-on"))
2443  else if (unformat (input, "post-mortem-off"))
2445  else
2446  return clib_error_return (0, "unknown input `%U'",
2447  format_unformat_error, input);
2448  }
2449  return 0;
2450 }
2451 
2452 /*?
2453  * Display, replay, or save a binary API trace
2454 ?*/
2455 
2456 /* *INDENT-OFF* */
2457 VLIB_CLI_COMMAND (api_trace_command, static) =
2458 {
2459  .path = "api trace",
2460  .short_help =
2461  "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
2462  .function = api_trace_command_fn,
2463 };
2464 /* *INDENT-ON* */
2465 
2466 static clib_error_t *
2468 {
2469  u32 nitems = 256 << 10;
2471  api_main_t *am = &api_main;
2472 
2473  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2474  {
2475  if (unformat (input, "on") || unformat (input, "enable"))
2476  {
2477  if (unformat (input, "nitems %d", &nitems))
2478  ;
2479  vl_msg_api_trace_configure (am, which, nitems);
2480  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
2482  }
2483  else if (unformat (input, "save-api-table %s",
2485  ;
2486  else
2487  return clib_error_return (0, "unknown input `%U'",
2488  format_unformat_error, input);
2489  }
2490  return 0;
2491 }
2492 
2493 /*?
2494  * This module has three configuration parameters:
2495  * "on" or "enable" - enables binary api tracing
2496  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
2497  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
2498 ?*/
2499 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
2500 
2501 static clib_error_t *
2503 {
2504  api_main_t *am = &api_main;
2505  u32 nitems;
2506 
2507  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2508  {
2509  if (unformat (input, "length %d", &nitems) ||
2510  (unformat (input, "len %d", &nitems)))
2511  {
2512  if (nitems >= 1024)
2513  am->vlib_input_queue_length = nitems;
2514  else
2515  clib_warning ("vlib input queue length %d too small, ignored",
2516  nitems);
2517  }
2518  else
2519  return clib_error_return (0, "unknown input `%U'",
2520  format_unformat_error, input);
2521  }
2522  return 0;
2523 }
2524 
2526 
2527 static u8 *
2529 {
2530  u8 *rv;
2531 
2532  rv = vec_dup (s);
2533 
2534  while (vec_len (rv) && rv[vec_len (rv)] != '_')
2535  _vec_len (rv)--;
2536 
2537  rv[vec_len (rv)] = 0;
2538 
2539  return rv;
2540 }
2541 
2542 static u8 *
2544 {
2545  int i;
2546  u8 *rv;
2547 
2548  rv = vec_dup (s);
2549 
2550  for (i = vec_len (rv) - 1; i >= 0; i--)
2551  {
2552  if (rv[i] == '_')
2553  {
2554  vec_delete (rv, i + 1, 0);
2555  break;
2556  }
2557  }
2558  return rv;
2559 }
2560 
2561 typedef struct
2562 {
2567  int which;
2569 
2570 static int
2571 table_id_cmp (void *a1, void *a2)
2572 {
2573  msg_table_unserialize_t *n1 = a1;
2574  msg_table_unserialize_t *n2 = a2;
2575 
2576  return (n1->msg_index - n2->msg_index);
2577 }
2578 
2579 static int
2580 table_name_and_crc_cmp (void *a1, void *a2)
2581 {
2582  msg_table_unserialize_t *n1 = a1;
2583  msg_table_unserialize_t *n2 = a2;
2584 
2585  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
2586 }
2587 
2588 static clib_error_t *
2590  unformat_input_t * input,
2591  vlib_cli_command_t * cmd)
2592 {
2593  u8 *filename = 0;
2594  api_main_t *am = &api_main;
2595  serialize_main_t _sm, *sm = &_sm;
2596  clib_error_t *error;
2597  u32 nmsgs;
2598  u32 msg_index;
2599  u8 *name_and_crc;
2600  int compare_current = 0;
2601  int numeric_sort = 0;
2602  msg_table_unserialize_t *table = 0, *item;
2603  u32 i;
2604  u32 ndifferences = 0;
2605 
2606  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2607  {
2608  if (unformat (input, "file %s", &filename))
2609  ;
2610  else if (unformat (input, "compare-current")
2611  || unformat (input, "compare"))
2612  compare_current = 1;
2613  else if (unformat (input, "numeric"))
2614  numeric_sort = 1;
2615  else
2616  return clib_error_return (0, "unknown input `%U'",
2617  format_unformat_error, input);
2618  }
2619 
2620  if (numeric_sort && compare_current)
2621  return clib_error_return
2622  (0, "Comparison and numeric sorting are incompatible");
2623 
2624  if (filename == 0)
2625  return clib_error_return (0, "File not specified");
2626 
2627  /* Load the serialized message table from the table dump */
2628 
2629  error = unserialize_open_clib_file (sm, (char *) filename);
2630 
2631  if (error)
2632  return error;
2633 
2634  unserialize_integer (sm, &nmsgs, sizeof (u32));
2635 
2636  for (i = 0; i < nmsgs; i++)
2637  {
2639  unserialize_cstring (sm, (char **) &name_and_crc);
2640  vec_add2 (table, item, 1);
2641  item->msg_index = msg_index;
2642  item->name_and_crc = name_and_crc;
2643  item->name = extract_name (name_and_crc);
2644  item->crc = extract_crc (name_and_crc);
2645  item->which = 0; /* file */
2646  }
2647  serialize_close (sm);
2648 
2649  /* Compare with the current image? */
2650  if (compare_current)
2651  {
2652  /* Append the current message table */
2653  u8 *tblv = vl_api_serialize_message_table (am, 0);
2654 
2655  serialize_open_vector (sm, tblv);
2656  unserialize_integer (sm, &nmsgs, sizeof (u32));
2657 
2658  for (i = 0; i < nmsgs; i++)
2659  {
2661  unserialize_cstring (sm, (char **) &name_and_crc);
2662 
2663  vec_add2 (table, item, 1);
2664  item->msg_index = msg_index;
2665  item->name_and_crc = name_and_crc;
2666  item->name = extract_name (name_and_crc);
2667  item->crc = extract_crc (name_and_crc);
2668  item->which = 1; /* current_image */
2669  }
2670  vec_free (tblv);
2671  }
2672 
2673  /* Sort the table. */
2674  if (numeric_sort)
2676  else
2678 
2679  if (compare_current)
2680  {
2681  ndifferences = 0;
2682 
2683  /*
2684  * In this case, the recovered table will have two entries per
2685  * API message. So, if entries i and i+1 match, the message definitions
2686  * are identical. Otherwise, the crc is different, or a message is
2687  * present in only one of the tables.
2688  */
2689  vlib_cli_output (vm, "%=60s %s", "Message Name", "Result");
2690 
2691  for (i = 0; i < vec_len (table);)
2692  {
2693  /* Last message lonely? */
2694  if (i == vec_len (table) - 1)
2695  {
2696  ndifferences++;
2697  goto last_unique;
2698  }
2699 
2700  /* Identical pair? */
2701  if (!strncmp
2702  ((char *) table[i].name_and_crc,
2703  (char *) table[i + 1].name_and_crc,
2704  vec_len (table[i].name_and_crc)))
2705  {
2706  i += 2;
2707  continue;
2708  }
2709 
2710  ndifferences++;
2711 
2712  /* Only in one of two tables? */
2713  if (strncmp ((char *) table[i].name, (char *) table[i + 1].name,
2714  vec_len (table[i].name)))
2715  {
2716  last_unique:
2717  vlib_cli_output (vm, "%-60s only in %s",
2718  table[i].name, table[i].which ?
2719  "image" : "file");
2720  i++;
2721  continue;
2722  }
2723  /* In both tables, but with different signatures */
2724  vlib_cli_output (vm, "%-60s definition changed", table[i].name);
2725  i += 2;
2726  }
2727  if (ndifferences == 0)
2728  vlib_cli_output (vm, "No api message signature differences found.");
2729  else
2730  vlib_cli_output (vm, "Found %u api message signature differences",
2731  ndifferences);
2732  goto cleanup;
2733  }
2734 
2735  /* Dump the table, sorted as shown above */
2736  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
2737 
2738  for (i = 0; i < vec_len (table); i++)
2739  {
2740  item = table + i;
2741  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
2742  item->msg_index, item->crc);
2743  }
2744 
2745 cleanup:
2746  for (i = 0; i < vec_len (table); i++)
2747  {
2748  vec_free (table[i].name_and_crc);
2749  vec_free (table[i].name);
2750  vec_free (table[i].crc);
2751  }
2752 
2753  vec_free (table);
2754 
2755  return 0;
2756 }
2757 
2758 /*?
2759  * Displays a serialized API message decode table, sorted by message name
2760  *
2761  * @cliexpar
2762  * @cliexstart{show api dump file <filename>}
2763  * Message name MsgID CRC
2764  * accept_session 407 8e2a127e
2765  * accept_session_reply 408 67d8c22a
2766  * add_node_next 549 e4202993
2767  * add_node_next_reply 550 e89d6eed
2768  * etc.
2769  * @cliexend
2770 ?*/
2771 
2772 /*?
2773  * Compares a serialized API message decode table with the current image
2774  *
2775  * @cliexpar
2776  * @cliexstart{show api dump file <filename> compare}
2777  * ip_add_del_route definition changed
2778  * ip_table_add_del definition changed
2779  * l2_macs_event only in image
2780  * vnet_ip4_fib_counters only in file
2781  * vnet_ip4_nbr_counters only in file
2782  * @cliexend
2783 ?*/
2784 
2785 /*?
2786  * Display a serialized API message decode table, compare a saved
2787  * decode table with the current image, to establish API differences.
2788  *
2789 ?*/
2790 /* *INDENT-OFF* */
2791 VLIB_CLI_COMMAND (dump_api_table_file, static) =
2792 {
2793  .path = "show api dump",
2794  .short_help = "show api dump file <filename> [numeric | compare-current]",
2795  .function = dump_api_table_file_command_fn,
2796 };
2797 /* *INDENT-ON* */
2798 
2799 /*
2800  * fd.io coding-style-patch-verification: ON
2801  *
2802  * Local Variables:
2803  * eval: (c-set-style "gnu")
2804  * End:
2805  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
Message range (belonging to a plugin)
Definition: api_common.h:109
vl_api_registration_t * regp
Definition: api_common.h:151
void vl_set_memory_region_name(const char *name)
Definition: memory_vlib.c:1717
u8 * format_api_message_rings(u8 *s, va_list *args)
Definition: memory_vlib.c:1308
u32 vl(void *p)
Definition: threads.c:30
static int table_id_cmp(void *a1, void *a2)
Definition: memory_vlib.c:2571
void * vl_msg_api_alloc_as_if_client(int nbytes)
#define TRACE_VLIB_MEMORY_QUEUE
Definition: memory_vlib.c:49
uword * pending_rpc_requests
Definition: main.h:214
#define vl_print(handle,...)
Definition: memory_vlib.c:58
u8 * name
Client name.
Definition: api_common.h:51
static int memory_api_init(const char *region_name)
Definition: memory_vlib.c:522
#define SVM_GLOBAL_REGION_NAME
Definition: svm_common.h:87
const char * root_path
Definition: svm_common.h:67
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
void vl_api_memclnt_delete_t_handler(vl_api_memclnt_delete_t *mp)
Definition: memory_vlib.c:281
u8 * name
name of the plugin
Definition: api_common.h:111
static void svm_pop_heap(void *oldheap)
Definition: svm.h:94
static u64 unserialize_likely_small_unsigned_integer(serialize_main_t *m)
Definition: serialize.h:254
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:699
a
Definition: bitmap.h:516
#define SVM_FLAGS_NODATA
Definition: svm_common.h:29
int unix_shared_memory_queue_is_full(unix_shared_memory_queue_t *q)
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:356
static clib_error_t * api_queue_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: memory_vlib.c:2502
static clib_error_t * setup_memclnt_exit(vlib_main_t *vm)
Definition: memory_vlib.c:1299
u8 wrapped
trace has wrapped
Definition: api_common.h:91
u32 application_restarts
Definition: api_common.h:79
int size
for sanity checking
Definition: api_common.h:79
Fixed length block allocator.
unix_shared_memory_queue_t * vl_input_queue
Definition: api_common.h:68
static vlib_node_registration_t api_rx_from_node_node
(constructor) VLIB_REGISTER_NODE (api_rx_from_node_node)
Definition: memory_vlib.c:1290
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:224
static clib_error_t * vl_api_client_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1417
u8 * message_bounce
Don&#39;t automatically free message buffer vetor.
Definition: api_common.h:218
vl_socket_args_for_process_t * process_args
Definition: api_common.h:179
Message configuration definition.
Definition: api_common.h:117
svm_region_t * vlib_primary_rp
Primary api segment descriptor.
Definition: api_common.h:254
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
static void vl_api_trace_plugin_msg_ids_t_handler(vl_api_trace_plugin_msg_ids_t *mp)
Definition: memory_vlib.c:1934
static clib_error_t * vl_api_message_table_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1559
static clib_error_t * vl_api_show_plugin_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1750
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
uword virtual_base
Definition: svm_common.h:42
#define SVM_PVT_MHEAP_SIZE
Definition: svm_common.h:32
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:557
api_version_t * api_version_list
api version list
Definition: api_common.h:324
int api_uid
uid for the api shared memory region
Definition: api_common.h:279
static clib_error_t * api_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: memory_vlib.c:2467
ring_alloc_t * client_rings
Definition: api_common.h:76
static clib_error_t * vl_api_clear_histogram_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1160
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
void vl_msg_api_send(vl_api_registration_t *rp, u8 *elem)
Definition: memory_vlib.c:102
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
Definition: pool.h:260
static void vl_api_rpc_call_reply_t_handler(vl_api_rpc_call_reply_t *mp)
Definition: memory_vlib.c:1837
void vl_api_get_first_msg_id_t_handler(vl_api_get_first_msg_id_t *mp)
Definition: memory_vlib.c:394
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
int api_gid
gid for the api shared memory region
Definition: api_common.h:282
static clib_error_t * dump_api_table_file_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: memory_vlib.c:2589
void vl_enable_disable_memory_api(vlib_main_t *vm, int enable)
Definition: memory_vlib.c:1231
#define VL_API_EPOCH_MASK
Definition: api_common.h:90
trace_cfg_t * api_trace_cfg
Current trace configuration.
Definition: api_common.h:245
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define MMAP_PAGESIZE
Definition: memfd.h:44
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:212
_vl_msg_api_function_list_elt_t * reaper_function_registrations
List of API client reaper functions.
Definition: api_common.h:339
void vl_msg_api_custom_dump_configure(api_main_t *am)
Definition: memory_vlib.c:2065
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:595
static f64 vlib_last_vector_length_per_node(vlib_main_t *vm)
Definition: main.h:315
static void vlib_worker_thread_barrier_check(void)
Definition: threads.h:392
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:95
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:68
_vlib_init_function_list_elt_t * api_init_function_registrations
Definition: main.h:182
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:438
static int range_compare(vl_api_msg_range_t *a0, vl_api_msg_range_t *a1)
Definition: memory_vlib.c:1725
vl_api_trace_t * rx_trace
Received message trace configuration.
Definition: api_common.h:236
void vl_api_api_versions_t_handler(vl_api_api_versions_t *mp)
Definition: memory_vlib.c:476
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:542
void vl_msg_api_handler_no_trace_no_free(void *the_msg)
Definition: api_shared.c:568
u32 ring_misses
Number of times that the ring allocator failed.
Definition: api_common.h:227
static void * svm_push_data_heap(svm_region_t *rp)
Definition: svm.h:86
#define always_inline
Definition: clib.h:92
void vl_api_socket_process_msg(clib_file_t *uf, vl_api_registration_t *rp, i8 *input_v)
Definition: socksvr_vlib.c:143
vl_api_registration_t ** vl_clients
vlib/vpp only: vector of client registrations
Definition: api_common.h:264
volatile void * user_ctx
Definition: svm_common.h:47
int i32
Definition: types.h:81
#define clib_arch_is_little_endian
Definition: byte_order.h:54
char i8
Definition: types.h:45
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
int replay_in_progress
Replay in progress?
Definition: api_common.h:333
static void send_one_plugin_msg_ids_msg(u8 *name, u16 first_msg_id, u16 last_msg_id)
Definition: memory_vlib.c:582
const char * root_path
Chroot path to the shared memory API files.
Definition: api_common.h:330
#define clib_error_return(e, args...)
Definition: error.h:99
svm_region_t * vlib_rp
Current binary api segment descriptor.
Definition: api_common.h:251
clib_error_t * vlib_call_init_exit_functions(vlib_main_t *vm, _vlib_init_function_list_elt_t *head, int call_once)
Definition: init.c:43
static clib_error_t * api_trace_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: memory_vlib.c:2335
#define SVM_GLOBAL_REGION_BASEVA
Definition: svm_common.h:93
unsigned long u64
Definition: types.h:89
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:261
static void * vl_api_memclnt_create_t_print(vl_api_memclnt_create_t *a, void *handle)
Definition: memory_vlib.c:64
void vl_socket_api_send(vl_api_registration_t *rp, u8 *elem)
Definition: socksvr_vlib.c:79
char name[64]
Definition: api_common.h:194
#define foreach_plugin_trace_msg
Definition: memory_vlib.c:1972
#define vlib_call_init_function(vm, x)
Definition: init.h:162
#define SOCKET_READ_EVENT
Definition: api_common.h:144
static uword pointer_to_uword(const void *p)
Definition: types.h:131
void * vl_msg_api_alloc(int nbytes)
static void memclnt_queue_callback(vlib_main_t *vm)
Definition: memory_vlib.c:1186
static void vlib_set_queue_signal_callback(vlib_main_t *vm, void(*fp)(vlib_main_t *))
Definition: main.h:354
static vlib_cli_command_t cli_show_api_histogram_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_histogram_command)
Definition: memory_vlib.c:1151
vl_shmem_hdr_t * shmem_hdr
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
void * rpc_call_main_thread_cb_fn
Definition: threads.c:1795
int vl_msg_api_trace_free(api_main_t *am, vl_api_trace_which_t which)
Definition: api_shared.c:154
vl_registration_type_t registration_type
type
Definition: api_common.h:46
int unix_shared_memory_queue_add(unix_shared_memory_queue_t *q, u8 *elem, int nowait)
u16 last_msg_id
last assigned message ID
Definition: api_common.h:113
static void * vl_api_trace_plugin_msg_ids_t_print(vl_api_trace_plugin_msg_ids_t *a, void *handle)
Definition: memory_vlib.c:84
char * name
Definition: main.h:100
static void dead_client_scan(api_main_t *am, vl_shmem_hdr_t *shm, f64 now)
Definition: memory_vlib.c:656
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
#define foreach_rpc_api_msg
Definition: memory_vlib.c:1968
vlib_node_registration_t memclnt_node
(constructor) VLIB_REGISTER_NODE (memclnt_node)
Definition: memory_vlib.c:1102
static clib_error_t * vl_api_ring_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1352
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:72
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:950
static int call_reaper_functions(u32 client_index)
Definition: memory_vlib.c:261
void(** msg_print_handlers)(void *, void *)
Message print function vector.
Definition: api_common.h:212
void vl_api_memclnt_keepalive_reply_t_handler(vl_api_memclnt_keepalive_reply_t *mp)
client answered a ping, stave off the grim reaper...
Definition: memory_vlib.c:439
int replay_enable
This message can be replayed.
Definition: api_common.h:81
struct _unformat_input_t unformat_input_t
volatile int ** vl_api_queue_cursizes
Definition: memory_vlib.c:1183
void vl_msg_api_free(void *)
static void vl_api_memclnt_keepalive_t_handler(vl_api_memclnt_keepalive_t *mp)
We can send ourselves these messages if someone uses the builtin binary api test tool...
Definition: memory_vlib.c:459
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:271
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:370
static void cleanup(void)
Definition: client.c:90
#define ELOG_DATA(em, f)
Definition: elog.h:481
svm_region_t ** vlib_private_rps
Vector of all mapped shared-VM segments.
Definition: api_common.h:257
#define PREDICT_FALSE(x)
Definition: clib.h:105
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:119
uword virtual_size
Definition: svm_common.h:43
void svm_region_init_args(svm_map_region_args_t *a)
Definition: svm.c:851
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:383
static void vl_api_rpc_call_t_handler(vl_api_rpc_call_t *mp)
Definition: memory_vlib.c:1792
#define SVM_GLOBAL_REGION_SIZE
Definition: svm_common.h:86
static u32 vl_msg_api_handle_get_index(u32 index)
Definition: api.h:37
vl_api_replay_t
Definition: memory_vlib.c:2018
#define foreach_vlib_api_msg
Definition: memory_vlib.c:510
void vl_msg_api_handler_with_vm_node(api_main_t *am, void *the_msg, vlib_main_t *vm, vlib_node_runtime_t *node)
Definition: api_shared.c:468
volatile u32 queue_signal_pending
Definition: main.h:187
#define QUEUE_SIGNAL_EVENT
Definition: api_common.h:143
void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:178
vl_api_module_version_t api_versions[count]
Definition: memclnt.api:121
#define uword_to_pointer(u, type)
Definition: types.h:136
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:198
socket_main_t socket_main
Definition: memory_shared.c:42
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:191
u64 global_size
size of the global VM region
Definition: api_common.h:288
void vl_api_force_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1927
u8 enabled
trace is enabled
Definition: api_common.h:90
An API client registration, only in vpp/vlib.
Definition: api_common.h:44
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
#define clib_arch_is_big_endian
Definition: byte_order.h:53
int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, int onoff)
Definition: api_shared.c:112
static void vl_api_rpc_call_main_thread_inline(void *fp, u8 *data, u32 data_length, u8 force_rpc)
Definition: memory_vlib.c:1878
api_main_t api_main
Definition: api_shared.c:35
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
ring_alloc_t * vl_rings
Definition: api_common.h:73
svmdb_client_t * c
u16 n_vectors
Definition: node.h:344
API trace state.
Definition: api_common.h:87
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1916
vlib_main_t * vm
Definition: buffer.c:283
void serialize_open_vector(serialize_main_t *m, u8 *vector)
Definition: serialize.c:908
void vl_unmap_shmem(void)
u64 global_baseva
base virtual address for global VM region
Definition: api_common.h:285
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
unix_shared_memory_queue_t * vl_input_queue
shared memory only: pointer to client input queue
Definition: api_common.h:59
vl_api_msg_range_t * msg_ranges
vector of message ranges
Definition: api_common.h:276
clib_error_t * unserialize_open_clib_file(serialize_main_t *m, char *file)
Definition: serialize.c:1241
#define clib_warning(format, args...)
Definition: error.h:59
clib_error_t * vlibsocket_init(vlib_main_t *vm)
Definition: socksvr_vlib.c:706
#define clib_memcpy(a, b, c)
Definition: string.h:75
#define foreach_histogram_bucket
Definition: memory_vlib.c:560
unix_shared_memory_queue_t * vl_api_client_index_to_input_queue(u32 index)
u32 garbage_collects
Definition: api_common.h:85
elog_main_t elog_main
Definition: main.h:155
u8 ** traces
Trace ring.
Definition: api_common.h:95
static void unserialize_integer(serialize_main_t *m, void *x, u32 n_bytes)
Definition: serialize.h:201
static void serialize_integer(serialize_main_t *m, u64 x, u32 n_bytes)
Definition: serialize.h:185
#define ARRAY_LEN(x)
Definition: clib.h:59
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:439
const char ** msg_names
Message name vector.
Definition: api_common.h:215
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:388
static clib_error_t * vl_api_trace_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1610
static void vl_msg_api_process_file(vlib_main_t *vm, u8 *filename, u32 first_index, u32 last_index, vl_api_replay_t which)
Definition: memory_vlib.c:2070
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
u8 * save_msg_table_filename
Dump (msg-name, crc) snapshot here at startup.
Definition: api_common.h:336
#define VL_API_BIG_ENDIAN
Definition: api_common.h:106
histogram_index_t
Definition: memory_vlib.c:566
void vl_msg_api_send_shmem(unix_shared_memory_queue_t *q, u8 *elem)
vl_api_trace_t * tx_trace
Sent message trace configuration.
Definition: api_common.h:239
static uword api_rx_from_node(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: memory_vlib.c:1240
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:294
#define ASSERT(truth)
static uword hash_elts(void *v)
Definition: hash.h:117
unsigned int u32
Definition: types.h:88
clib_error_t * vlibmemory_init(vlib_main_t *vm)
Definition: memory_vlib.c:1688
#define VL_API_LITTLE_ENDIAN
Definition: api_common.h:105
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:781
static u64 vector_rate_histogram[SLEEP_N_BUCKETS]
Definition: memory_vlib.c:574
static uword memclnt_process(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *f)
Definition: memory_vlib.c:801
void serialize_close(serialize_main_t *m)
Definition: serialize.c:869
VLIB_API_INIT_FUNCTION(rpc_api_hookup)
u64 size
Definition: vhost-user.h:76
u8 * vl_api_serialize_message_table(api_main_t *am, u8 *vector)
Definition: memory_vlib.c:115
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:109
static void clib_mem_free(void *p)
Definition: mem.h:179
static u8 * extract_name(u8 *s)
Definition: memory_vlib.c:2528
static vlib_cli_command_t cli_clear_api_histogram_command
(constructor) VLIB_CLI_COMMAND (cli_clear_api_histogram_command)
Definition: memory_vlib.c:1175
u8 * serialized_message_table_in_shmem
vlib/vpp only: serialized (message, name, crc) table
Definition: api_common.h:267
#define clib_error_report(e)
Definition: error.h:113
static void * vlib_frame_args(vlib_frame_t *f)
Get pointer to frame scalar data.
Definition: node_funcs.h:284
void dump_socket_clients(vlib_main_t *vm, api_main_t *am)
Definition: memory_vlib.c:1412
u64 global_pvt_heap_size
size of the global VM private mheap
Definition: api_common.h:294
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:147
static void * clib_mem_alloc(uword size)
Definition: mem.h:112
u32 restart_reclaims
Definition: api_common.h:82
static u8 * format_api_msg_range(u8 *s, va_list *args)
Definition: memory_vlib.c:1736
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u64 uword
Definition: types.h:112
static clib_error_t * rpc_api_hookup(vlib_main_t *vm)
Definition: memory_vlib.c:1987
static clib_error_t * vl_api_status_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1480
u32 missing_clients
Number of missing clients / failed message sends.
Definition: api_common.h:233
void vl_msg_api_post_mortem_dump_enable_disable(int enable)
Definition: api_shared.c:788
unsigned short u16
Definition: types.h:57
static void send_memclnt_keepalive(vl_api_registration_t *regp, f64 now)
Definition: memory_vlib.c:604
u16 first_msg_id
first assigned message ID
Definition: api_common.h:112
void vl_msg_api_send_shmem_nolock(unix_shared_memory_queue_t *q, u8 *elem)
void vl_api_memclnt_create_t_handler(vl_api_memclnt_create_t *mp)
Definition: memory_vlib.c:181
void(** msg_endian_handlers)(void *)
Message endian handler vector.
Definition: api_common.h:209
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
#define hash_foreach_pair(p, v, body)
Iterate over hash pairs.
Definition: hash.h:372
static u8 * extract_crc(u8 *s)
Definition: memory_vlib.c:2543
const char * name
Definition: svm_common.h:68
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:956
#define clib_unix_warning(format, args...)
Definition: error.h:68
void vl_api_send_pending_rpc_requests(vlib_main_t *vm)
Definition: memory_vlib.c:1843
u8 * format_vl_msg_api_trace_status(u8 *s, va_list *args)
Definition: memory_vlib.c:2027
u32 vl_api_registration_pool_index
Index in VLIB&#39;s brain (not shared memory).
Definition: api_common.h:49
void svm_client_scan_this_region_nolock(svm_region_t *rp)
Definition: svm.c:1168
static clib_error_t * vl_api_show_histogram_command(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cli_cmd)
Definition: memory_vlib.c:1113
volatile u32 api_queue_nonempty
Definition: main.h:188
#define hash_get_mem(h, key)
Definition: hash.h:268
void(** msg_handlers)(void *)
Message handler vector.
Definition: api_common.h:201
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
clib_error_t * socksvr_api_init(vlib_main_t *vm)
Definition: socksvr_vlib.c:586
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1491
u8 * is_mp_safe
Message is mp safe vector.
Definition: api_common.h:221
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static int table_name_and_crc_cmp(void *a1, void *a2)
Definition: memory_vlib.c:2580
u8 data[0]
Packet data.
Definition: buffer.h:159
int msg_print_flag
Print every received message.
Definition: api_common.h:242
vl_api_registration_t * vl_api_client_index_to_registration(u32 index)
void * serialize_close_vector(serialize_main_t *m)
Definition: serialize.c:918
static void * vl_api_memclnt_delete_t_print(vl_api_memclnt_delete_t *a, void *handle)
Definition: memory_vlib.c:75
vl_api_trace_which_t
Trace RX / TX enum.
Definition: api_common.h:99
const char * region_name
Shared VM binary API region name.
Definition: api_common.h:327
Trace configuration for a single message.
Definition: api_common.h:77
static u32 vl_msg_api_handle_get_epoch(u32 index)
Definition: api.h:31
int vl_map_shmem(const char *region_name, int is_vlib)
u32 vl_api_memclnt_create_internal(char *name, unix_shared_memory_queue_t *q)
Definition: memory_vlib.c:142
uword * msg_index_by_name_and_crc
client message index hash table
Definition: api_common.h:321
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:322
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
uword * msg_range_by_name
Message range by name hash.
Definition: api_common.h:273
Shared memory connection.
Definition: api_common.h:36
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
u32 nitems
Number of trace records.
Definition: api_common.h:93
svm_region_t * vlib_rp
Definition: api_common.h:60
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u32 vlib_input_queue_length
vpp/vlib input queue length
Definition: api_common.h:318
pthread_mutex_t mutex
Definition: svm_common.h:37
static u32 vl_msg_api_handle_from_index_and_epoch(u32 index, u32 epoch)
Definition: api.h:43
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
struct _unix_shared_memory_queue unix_shared_memory_queue_t
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128