FD.io VPP  v17.10-9-gd594711
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 
100  __attribute__ ((weak));
101 
102 void
104 {
105  static int count;
106 
107  if (count++ < 5)
108  clib_warning ("need to link against -lvlibsocket, msg not sent!");
109 }
110 
111 void
113 {
115  {
116  vl_socket_api_send (rp, elem);
117  }
118  else
119  {
121  }
122 }
123 
124 u8 *
126 {
127  serialize_main_t _sm, *sm = &_sm;
128  hash_pair_t *hp;
130 
131  serialize_open_vector (sm, vector);
132 
133  /* serialize the count */
134  serialize_integer (sm, nmsg, sizeof (u32));
135 
136  /* *INDENT-OFF* */
138  ({
139  serialize_likely_small_unsigned_integer (sm, hp->value[0]);
140  serialize_cstring (sm, (char *) hp->key);
141  }));
142  /* *INDENT-ON* */
143 
144  return serialize_close_vector (sm);
145 }
146 
147 /*
148  * vl_api_memclnt_create_internal
149  */
150 
151 u32
153 {
154  vl_api_registration_t **regpp;
155  vl_api_registration_t *regp;
156  svm_region_t *svm;
157  void *oldheap;
158  api_main_t *am = &api_main;
159 
160  ASSERT (vlib_get_thread_index () == 0);
161  pool_get (am->vl_clients, regpp);
162 
163  svm = am->vlib_rp;
164 
165  pthread_mutex_lock (&svm->mutex);
166  oldheap = svm_push_data_heap (svm);
167  *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
168 
169  regp = *regpp;
170  memset (regp, 0, sizeof (*regp));
172  regp->vl_api_registration_pool_index = regpp - am->vl_clients;
173 
174  regp->vl_input_queue = q;
175  regp->name = format (0, "%s%c", name, 0);
176 
177  pthread_mutex_unlock (&svm->mutex);
178  svm_pop_heap (oldheap);
182 }
183 
184 
185 /*
186  * vl_api_memclnt_create_t_handler
187  */
188 void
190 {
191  vl_api_registration_t **regpp;
192  vl_api_registration_t *regp;
194  svm_region_t *svm;
196  int rv = 0;
197  void *oldheap;
198  api_main_t *am = &api_main;
199 
200  /*
201  * This is tortured. Maintain a vlib-address-space private
202  * pool of client registrations. We use the shared-memory virtual
203  * address of client structure as a handle, to allow direct
204  * manipulation of context quota vbls from the client library.
205  *
206  * This scheme causes trouble w/ API message trace replay, since
207  * some random VA from clib_mem_alloc() certainly won't
208  * occur in the Linux sim. The (very) few places
209  * that care need to use the pool index.
210  *
211  * Putting the registration object(s) into a pool in shared memory and
212  * using the pool index as a handle seems like a great idea.
213  * Unfortunately, each and every reference to that pool would need
214  * to be protected by a mutex:
215  *
216  * Client VLIB
217  * ------ ----
218  * convert pool index to
219  * pointer.
220  * <deschedule>
221  * expand pool
222  * <deschedule>
223  * kaboom!
224  */
225 
226  pool_get (am->vl_clients, regpp);
227 
228  svm = am->vlib_rp;
229 
230  pthread_mutex_lock (&svm->mutex);
231  oldheap = svm_push_data_heap (svm);
232  *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
233 
234  regp = *regpp;
235  memset (regp, 0, sizeof (*regp));
237  regp->vl_api_registration_pool_index = regpp - am->vl_clients;
238 
240  mp->input_queue;
241 
242  regp->name = format (0, "%s", mp->name);
243  vec_add1 (regp->name, 0);
244 
245  pthread_mutex_unlock (&svm->mutex);
246  svm_pop_heap (oldheap);
247 
249 
250  rp = vl_msg_api_alloc (sizeof (*rp));
251  rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_REPLY);
252  rp->handle = (uword) regp;
256  rp->context = mp->context;
257  rp->response = ntohl (rv);
258  rp->message_table =
260 
261  vl_msg_api_send_shmem (q, (u8 *) & rp);
262 }
263 
264 static int
266 {
267  clib_error_t *error = 0;
268  _vl_msg_api_function_list_elt_t *i;
269 
271  while (i)
272  {
273  error = i->f (client_index);
274  if (error)
275  clib_error_report (error);
276  i = i->next_init_function;
277  }
278  return 0;
279 }
280 
281 /*
282  * vl_api_memclnt_delete_t_handler
283  */
284 void
286 {
287  vl_api_registration_t **regpp;
288  vl_api_registration_t *regp;
290  svm_region_t *svm;
291  void *oldheap;
292  api_main_t *am = &api_main;
293  u32 handle, client_index, epoch;
294 
295  handle = mp->index;
296 
297  if (call_reaper_functions (handle))
298  return;
299 
300  epoch = vl_msg_api_handle_get_epoch (handle);
301  client_index = vl_msg_api_handle_get_index (handle);
302 
303  if (epoch != (am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK))
304  {
306  ("Stale clnt delete index %d old epoch %d cur epoch %d",
307  client_index, epoch,
309  return;
310  }
311 
312  regpp = am->vl_clients + client_index;
313 
314  if (!pool_is_free (am->vl_clients, regpp))
315  {
316  regp = *regpp;
317  svm = am->vlib_rp;
318 
319  /* $$$ check the input queue for e.g. punted sf's */
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  /* No dangling references, please */
337  *regpp = 0;
338 
340 
341  pthread_mutex_lock (&svm->mutex);
342  oldheap = svm_push_data_heap (svm);
343  /* Poison the old registration */
344  memset (regp, 0xF1, sizeof (*regp));
345  clib_mem_free (regp);
346  pthread_mutex_unlock (&svm->mutex);
347  svm_pop_heap (oldheap);
348  }
349  else
350  {
351  clib_warning ("unknown client ID %d", mp->index);
352  }
353 }
354 
355 void
357 {
360  uword *p;
361  api_main_t *am = &api_main;
362  vl_api_msg_range_t *rp;
363  u8 name[64];
364  u16 first_msg_id = ~0;
365  int rv = -7; /* VNET_API_ERROR_INVALID_VALUE */
366 
368  if (!q)
369  return;
370 
371  if (am->msg_range_by_name == 0)
372  goto out;
373 
374  strncpy ((char *) name, (char *) mp->name, ARRAY_LEN (name) - 1);
375 
376  p = hash_get_mem (am->msg_range_by_name, name);
377  if (p == 0)
378  goto out;
379 
380  rp = vec_elt_at_index (am->msg_ranges, p[0]);
381 
382  first_msg_id = rp->first_msg_id;
383  rv = 0;
384 
385 out:
386 
387  rmp = vl_msg_api_alloc (sizeof (*rmp));
388  rmp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID_REPLY);
389  rmp->context = mp->context;
390  rmp->retval = ntohl (rv);
391  rmp->first_msg_id = ntohs (first_msg_id);
392  vl_msg_api_send_shmem (q, (u8 *) & rmp);
393 }
394 
395 #define foreach_vlib_api_msg \
396 _(MEMCLNT_CREATE, memclnt_create) \
397 _(MEMCLNT_DELETE, memclnt_delete) \
398 _(GET_FIRST_MSG_ID, get_first_msg_id)
399 
400 /*
401  * vl_api_init
402  */
403 static int
404 memory_api_init (const char *region_name)
405 {
406  int rv;
408  vl_msg_api_msg_config_t *c = &cfg;
409 
410  memset (c, 0, sizeof (*c));
411 
412  if ((rv = vl_map_shmem (region_name, 1 /* is_vlib */ )) < 0)
413  return rv;
414 
415 #define _(N,n) do { \
416  c->id = VL_API_##N; \
417  c->name = #n; \
418  c->handler = vl_api_##n##_t_handler; \
419  c->cleanup = vl_noop_handler; \
420  c->endian = vl_api_##n##_t_endian; \
421  c->print = vl_api_##n##_t_print; \
422  c->size = sizeof(vl_api_##n##_t); \
423  c->traced = 1; /* trace, so these msgs print */ \
424  c->replay = 0; /* don't replay client create/delete msgs */ \
425  c->message_bounce = 0; /* don't bounce this message */ \
426  vl_msg_api_config(c);} while (0);
427 
429 #undef _
430 
431  return 0;
432 }
433 
434 #define foreach_histogram_bucket \
435 _(400) \
436 _(200) \
437 _(100) \
438 _(10)
439 
440 typedef enum
441 {
442 #define _(n) SLEEP_##n##_US,
444 #undef _
447 
449 
450 static void memclnt_queue_callback (vlib_main_t * vm);
451 
452 /*
453  * Callback to send ourselves a plugin numbering-space trace msg
454  */
455 static void
456 send_one_plugin_msg_ids_msg (u8 * name, u16 first_msg_id, u16 last_msg_id)
457 {
459  api_main_t *am = &api_main;
462 
463  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
464  memset (mp, 0, sizeof (*mp));
465 
466  mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_TRACE_PLUGIN_MSG_IDS);
467  strncpy ((char *) mp->plugin_name, (char *) name,
468  sizeof (mp->plugin_name) - 1);
469  mp->first_msg_id = clib_host_to_net_u16 (first_msg_id);
470  mp->last_msg_id = clib_host_to_net_u16 (last_msg_id);
471 
472  q = shmem_hdr->vl_input_queue;
473 
474  vl_msg_api_send_shmem (q, (u8 *) & mp);
475 }
476 
477 static uword
479  vlib_node_runtime_t * node, vlib_frame_t * f)
480 {
481  uword mp;
482  vl_shmem_hdr_t *shm;
484  clib_error_t *e;
485  int rv;
486  api_main_t *am = &api_main;
487  f64 dead_client_scan_time;
488  f64 sleep_time, start_time;
489  f64 vector_rate;
490  int i;
491  u8 *serialized_message_table = 0;
492  svm_region_t *svm;
493  void *oldheap;
494 
496 
497  if ((rv = memory_api_init (am->region_name)) < 0)
498  {
499  clib_warning ("memory_api_init returned %d, wait for godot...", rv);
500  vlib_process_suspend (vm, 1e70);
501  }
502 
503  shm = am->shmem_hdr;
504  ASSERT (shm);
505  q = shm->vl_input_queue;
506  ASSERT (q);
507 
509  (vm, vm->api_init_function_registrations, 1 /* call_once */ );
510  if (e)
511  clib_error_report (e);
512 
513  sleep_time = 20.0;
514  dead_client_scan_time = vlib_time_now (vm) + 20.0;
515 
516  /*
517  * Send plugin message range messages for each plugin we loaded
518  */
519  for (i = 0; i < vec_len (am->msg_ranges); i++)
520  {
521  vl_api_msg_range_t *rp = am->msg_ranges + i;
523  rp->last_msg_id);
524  }
525 
526  /*
527  * Snapshoot the api message table.
528  */
529  serialized_message_table = vl_api_serialize_message_table (am, 0);
530 
531  svm = am->vlib_rp;
532  pthread_mutex_lock (&svm->mutex);
533  oldheap = svm_push_data_heap (svm);
534 
535  am->serialized_message_table_in_shmem = vec_dup (serialized_message_table);
536 
537  pthread_mutex_unlock (&svm->mutex);
538  svm_pop_heap (oldheap);
539 
540  /*
541  * Save the api message table snapshot, if configured
542  */
543  if (am->save_msg_table_filename)
544  {
545  int fd, rv;
546  u8 *chroot_file;
547  if (strstr ((char *) am->save_msg_table_filename, "..")
548  || index ((char *) am->save_msg_table_filename, '/'))
549  {
550  clib_warning ("illegal save-message-table filename '%s'",
552  goto skip_save;
553  }
554 
555  chroot_file = format (0, "/tmp/%s%c", am->save_msg_table_filename, 0);
556 
557  fd = creat ((char *) chroot_file, 0644);
558 
559  if (fd < 0)
560  {
561  clib_unix_warning ("creat");
562  goto skip_save;
563  }
564  rv = write (fd, serialized_message_table,
565  vec_len (serialized_message_table));
566 
567  if (rv != vec_len (serialized_message_table))
568  clib_unix_warning ("write");
569 
570  rv = close (fd);
571  if (rv < 0)
572  clib_unix_warning ("close");
573 
574  vec_free (chroot_file);
575  }
576 
577 skip_save:
578  vec_free (serialized_message_table);
579 
580  /* $$$ pay attention to frame size, control CPU usage */
581  while (1)
582  {
583  uword event_type __attribute__ ((unused));
584  i8 *headp;
585  int need_broadcast;
586 
587  /*
588  * There's a reason for checking the queue before
589  * sleeping. If the vlib application crashes, it's entirely
590  * possible for a client to enqueue a connect request
591  * during the process restart interval.
592  *
593  * Unless some force of physics causes the new incarnation
594  * of the application to process the request, the client will
595  * sit and wait for Godot...
596  */
597  vector_rate = vlib_last_vector_length_per_node (vm);
598  start_time = vlib_time_now (vm);
599  while (1)
600  {
601  pthread_mutex_lock (&q->mutex);
602  if (q->cursize == 0)
603  {
604  vm->api_queue_nonempty = 0;
605  pthread_mutex_unlock (&q->mutex);
606 
608  {
609  /* *INDENT-OFF* */
610  ELOG_TYPE_DECLARE (e) =
611  {
612  .format = "q-underflow: len %d",
613  .format_args = "i4",
614  };
615  /* *INDENT-ON* */
616  struct
617  {
618  u32 len;
619  } *ed;
620  ed = ELOG_DATA (&vm->elog_main, e);
621  ed->len = 0;
622  }
623  sleep_time = 20.0;
624  break;
625  }
626 
627  headp = (i8 *) (q->data + sizeof (uword) * q->head);
628  clib_memcpy (&mp, headp, sizeof (uword));
629 
630  q->head++;
631  need_broadcast = (q->cursize == q->maxsize / 2);
632  q->cursize--;
633 
634  if (PREDICT_FALSE (q->head == q->maxsize))
635  q->head = 0;
636  pthread_mutex_unlock (&q->mutex);
637  if (need_broadcast)
638  (void) pthread_cond_broadcast (&q->condvar);
639 
640  vl_msg_api_handler_with_vm_node (am, (void *) mp, vm, node);
641 
642  /* Allow no more than 10us without a pause */
643  if (vlib_time_now (vm) > start_time + 10e-6)
644  {
645  int index = SLEEP_400_US;
646  if (vector_rate > 40.0)
647  sleep_time = 400e-6;
648  else if (vector_rate > 20.0)
649  {
650  index = SLEEP_200_US;
651  sleep_time = 200e-6;
652  }
653  else if (vector_rate >= 1.0)
654  {
655  index = SLEEP_100_US;
656  sleep_time = 100e-6;
657  }
658  else
659  {
660  index = SLEEP_10_US;
661  sleep_time = 10e-6;
662  }
663  vector_rate_histogram[index] += 1;
664  break;
665  }
666  }
667 
668  event_type = vlib_process_wait_for_event_or_clock (vm, sleep_time);
669  vm->queue_signal_pending = 0;
670  vlib_process_get_events (vm, 0 /* event_data */ );
671 
672  if (vlib_time_now (vm) > dead_client_scan_time)
673  {
674  vl_api_registration_t **regpp;
675  vl_api_registration_t *regp;
677  static u32 *dead_indices;
678  static u32 *confused_indices;
679 
680  vec_reset_length (dead_indices);
681  vec_reset_length (confused_indices);
682 
683  /* *INDENT-OFF* */
684  pool_foreach (regpp, am->vl_clients,
685  ({
686  regp = *regpp;
687  if (regp)
688  {
689  q = regp->vl_input_queue;
690  if (kill (q->consumer_pid, 0) < 0)
691  {
692  vec_add1(dead_indices, regpp - am->vl_clients);
693  }
694  }
695  else
696  {
697  clib_warning ("NULL client registration index %d",
698  regpp - am->vl_clients);
699  vec_add1 (confused_indices, regpp - am->vl_clients);
700  }
701  }));
702  /* *INDENT-ON* */
703  /* This should "never happen," but if it does, fix it... */
704  if (PREDICT_FALSE (vec_len (confused_indices) > 0))
705  {
706  int i;
707  for (i = 0; i < vec_len (confused_indices); i++)
708  {
709  pool_put_index (am->vl_clients, confused_indices[i]);
710  }
711  }
712 
713  if (PREDICT_FALSE (vec_len (dead_indices) > 0))
714  {
715  int i;
716  svm_region_t *svm;
717  void *oldheap;
718 
719  /* Allow the application to clean up its registrations */
720  for (i = 0; i < vec_len (dead_indices); i++)
721  {
722  regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
723  if (regpp)
724  {
725  u32 handle;
726 
728  (dead_indices[i], shm->application_restarts);
729  (void) call_reaper_functions (handle);
730  }
731  }
732 
733  svm = am->vlib_rp;
734  pthread_mutex_lock (&svm->mutex);
735  oldheap = svm_push_data_heap (svm);
736 
737  for (i = 0; i < vec_len (dead_indices); i++)
738  {
739  regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
740  if (regpp)
741  {
742  /* Poison the old registration */
743  memset (*regpp, 0xF3, sizeof (**regpp));
744  clib_mem_free (*regpp);
745  /* no dangling references, please */
746  *regpp = 0;
747  }
748  else
749  {
750  svm_pop_heap (oldheap);
751  clib_warning ("Duplicate free, client index %d",
752  regpp - am->vl_clients);
753  oldheap = svm_push_data_heap (svm);
754  }
755  }
756 
758 
759  pthread_mutex_unlock (&svm->mutex);
760  svm_pop_heap (oldheap);
761  for (i = 0; i < vec_len (dead_indices); i++)
762  pool_put_index (am->vl_clients, dead_indices[i]);
763  }
764 
765  dead_client_scan_time = vlib_time_now (vm) + 20.0;
766  }
767 
769  {
770  /* *INDENT-OFF* */
771  ELOG_TYPE_DECLARE (e) = {
772  .format = "q-awake: len %d",
773  .format_args = "i4",
774  };
775  /* *INDENT-ON* */
776  struct
777  {
778  u32 len;
779  } *ed;
780  ed = ELOG_DATA (&vm->elog_main, e);
781  ed->len = q->cursize;
782  }
783  }
784 
785  return 0;
786 }
787 /* *INDENT-OFF* */
789  .function = memclnt_process,
790  .type = VLIB_NODE_TYPE_PROCESS,
791  .name = "api-rx-from-ring",
792  .state = VLIB_NODE_STATE_DISABLED,
793 };
794 /* *INDENT-ON* */
795 
796 
797 static clib_error_t *
799  unformat_input_t * input,
800  vlib_cli_command_t * cli_cmd)
801 {
802  u64 total_counts = 0;
803  int i;
804 
805  for (i = 0; i < SLEEP_N_BUCKETS; i++)
806  {
807  total_counts += vector_rate_histogram[i];
808  }
809 
810  if (total_counts == 0)
811  {
812  vlib_cli_output (vm, "No control-plane activity.");
813  return 0;
814  }
815 
816 #define _(n) \
817  do { \
818  f64 percent; \
819  percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
820  / (f64) total_counts; \
821  percent *= 100.0; \
822  vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
823  vector_rate_histogram[SLEEP_##n##_US], \
824  percent); \
825  } while (0);
827 #undef _
828 
829  return 0;
830 }
831 
832 /*?
833  * Display the binary api sleep-time histogram
834 ?*/
835 /* *INDENT-OFF* */
836 VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
837 {
838  .path = "show api histogram",
839  .short_help = "show api histogram",
840  .function = vl_api_show_histogram_command,
841 };
842 /* *INDENT-ON* */
843 
844 static clib_error_t *
846  unformat_input_t * input,
847  vlib_cli_command_t * cli_cmd)
848 {
849  int i;
850 
851  for (i = 0; i < SLEEP_N_BUCKETS; i++)
852  vector_rate_histogram[i] = 0;
853  return 0;
854 }
855 
856 /*?
857  * Clear the binary api sleep-time histogram
858 ?*/
859 /* *INDENT-OFF* */
860 VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
861 {
862  .path = "clear api histogram",
863  .short_help = "clear api histogram",
864  .function = vl_api_clear_histogram_command,
865 };
866 /* *INDENT-ON* */
867 
868 static void
870 {
871  static volatile int *cursizep;
872 
873  if (PREDICT_FALSE (cursizep == 0))
874  {
875  api_main_t *am = &api_main;
878 
879  if (shmem_hdr == 0)
880  return;
881 
882  q = shmem_hdr->vl_input_queue;
883  if (q == 0)
884  return;
885  cursizep = &q->cursize;
886  }
887 
888  if (*cursizep >= 1)
889  {
890  vm->queue_signal_pending = 1;
891  vm->api_queue_nonempty = 1;
893  /* event_type */ 0, /* event_data */ 0);
894  }
895 }
896 
897 void
899 {
901  (enable
902  ? VLIB_NODE_STATE_POLLING
903  : VLIB_NODE_STATE_DISABLED));
904 }
905 
906 static uword
908  vlib_node_runtime_t * node, vlib_frame_t * frame)
909 {
910  uword n_packets = frame->n_vectors;
911  uword n_left_from;
912  u32 *from;
913  static u8 *long_msg;
914 
915  vec_validate (long_msg, 4095);
916  n_left_from = frame->n_vectors;
917  from = vlib_frame_args (frame);
918 
919  while (n_left_from > 0)
920  {
921  u32 bi0;
922  vlib_buffer_t *b0;
923  void *msg;
924  uword msg_len;
925 
926  bi0 = from[0];
927  b0 = vlib_get_buffer (vm, bi0);
928  from += 1;
929  n_left_from -= 1;
930 
931  msg = b0->data + b0->current_data;
932  msg_len = b0->current_length;
934  {
935  ASSERT (long_msg != 0);
936  _vec_len (long_msg) = 0;
937  vec_add (long_msg, msg, msg_len);
938  while (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
939  {
940  b0 = vlib_get_buffer (vm, b0->next_buffer);
941  msg = b0->data + b0->current_data;
942  msg_len = b0->current_length;
943  vec_add (long_msg, msg, msg_len);
944  }
945  msg = long_msg;
946  }
948  }
949 
950  /* Free what we've been given. */
951  vlib_buffer_free (vm, vlib_frame_args (frame), n_packets);
952 
953  return n_packets;
954 }
955 
956 /* *INDENT-OFF* */
958  .function = api_rx_from_node,
959  .type = VLIB_NODE_TYPE_INTERNAL,
960  .vector_size = 4,
961  .name = "api-rx-from-node",
962 };
963 /* *INDENT-ON* */
964 
965 static clib_error_t *
967 {
968  atexit (vl_unmap_shmem);
969  return 0;
970 }
971 
973 
974 
975 static clib_error_t *
977  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
978 {
979  int i;
980  ring_alloc_t *ap;
982  api_main_t *am = &api_main;
983 
984  shmem_hdr = am->shmem_hdr;
985 
986  if (shmem_hdr == 0)
987  {
988  vlib_cli_output (vm, "Shared memory segment not initialized...\n");
989  return 0;
990  }
991 
992  vlib_cli_output (vm, "%8s %8s %8s %8s %8s\n",
993  "Owner", "Size", "Nitems", "Hits", "Misses");
994 
995  ap = shmem_hdr->vl_rings;
996 
997  for (i = 0; i < vec_len (shmem_hdr->vl_rings); i++)
998  {
999  vlib_cli_output (vm, "%8s %8d %8d %8d %8d\n",
1000  "vlib", ap->size, ap->nitems, ap->hits, ap->misses);
1001  ap++;
1002  }
1003 
1004  ap = shmem_hdr->client_rings;
1005 
1006  for (i = 0; i < vec_len (shmem_hdr->client_rings); i++)
1007  {
1008  vlib_cli_output (vm, "%8s %8d %8d %8d %8d\n",
1009  "clnt", ap->size, ap->nitems, ap->hits, ap->misses);
1010  ap++;
1011  }
1012 
1013  vlib_cli_output (vm, "%d ring miss fallback allocations\n",
1014  am->ring_misses);
1015 
1017  (vm, "%d application restarts, %d reclaimed msgs, %d garbage collects\n",
1018  shmem_hdr->application_restarts,
1019  shmem_hdr->restart_reclaims, shmem_hdr->garbage_collects);
1020  return 0;
1021 }
1022 
1023 void dump_socket_clients (vlib_main_t * vm, api_main_t * am)
1024  __attribute__ ((weak));
1025 
1026 void
1028 {
1029 }
1030 
1031 static clib_error_t *
1033  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1034 {
1035  vl_api_registration_t **regpp, *regp;
1037  char *health;
1038  api_main_t *am = &api_main;
1039  u32 *confused_indices = 0;
1040 
1041  if (!pool_elts (am->vl_clients))
1042  goto socket_clients;
1043  vlib_cli_output (vm, "Shared memory clients");
1044  vlib_cli_output (vm, "%16s %8s %14s %18s %s",
1045  "Name", "PID", "Queue Length", "Queue VA", "Health");
1046 
1047  /* *INDENT-OFF* */
1048  pool_foreach (regpp, am->vl_clients,
1049  ({
1050  regp = *regpp;
1051 
1052  if (regp)
1053  {
1054  q = regp->vl_input_queue;
1055  if (kill (q->consumer_pid, 0) < 0)
1056  {
1057  health = "DEAD";
1058  }
1059  else
1060  {
1061  health = "alive";
1062  }
1063  vlib_cli_output (vm, "%16s %8d %14d 0x%016llx %s\n",
1064  regp->name, q->consumer_pid, q->cursize,
1065  q, health);
1066  }
1067  else
1068  {
1069  clib_warning ("NULL client registration index %d",
1070  regpp - am->vl_clients);
1071  vec_add1 (confused_indices, regpp - am->vl_clients);
1072  }
1073  }));
1074  /* *INDENT-ON* */
1075 
1076  /* This should "never happen," but if it does, fix it... */
1077  if (PREDICT_FALSE (vec_len (confused_indices) > 0))
1078  {
1079  int i;
1080  for (i = 0; i < vec_len (confused_indices); i++)
1081  {
1082  pool_put_index (am->vl_clients, confused_indices[i]);
1083  }
1084  }
1085  vec_free (confused_indices);
1086 
1087  if (am->missing_clients)
1088  vlib_cli_output (vm, "%u messages with missing clients",
1089  am->missing_clients);
1090 socket_clients:
1091  dump_socket_clients (vm, am);
1092 
1093  return 0;
1094 }
1095 
1096 static clib_error_t *
1098  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1099 {
1100  api_main_t *am = &api_main;
1101 
1102  // check if rx_trace and tx_trace are not null pointers
1103 
1104  if (am->rx_trace == 0)
1105  {
1106  vlib_cli_output (vm, "RX Trace disabled\n");
1107  }
1108  else
1109  {
1110  if (am->rx_trace->enabled == 0)
1111  vlib_cli_output (vm, "RX Trace disabled\n");
1112  else
1113  vlib_cli_output (vm, "RX Trace enabled\n");
1114  }
1115 
1116  if (am->tx_trace == 0)
1117  {
1118  vlib_cli_output (vm, "TX Trace disabled\n");
1119  }
1120  else
1121  {
1122  if (am->tx_trace->enabled == 0)
1123  vlib_cli_output (vm, "TX Trace disabled\n");
1124  else
1125  vlib_cli_output (vm, "TX Trace enabled\n");
1126  }
1127 
1128  return 0;
1129 }
1130 
1131 /* *INDENT-OFF* */
1133 {
1134  .path = "show api",
1135  .short_help = "Show API information",
1136 };
1137 /* *INDENT-ON* */
1138 
1139 /*?
1140  * Display binary api message allocation ring statistics
1141 ?*/
1142 /* *INDENT-OFF* */
1144 {
1145  .path = "show api ring-stats",
1146  .short_help = "Message ring statistics",
1147  .function = vl_api_ring_command,
1148 };
1149 /* *INDENT-ON* */
1150 
1151 /*?
1152  * Display current api client connections
1153 ?*/
1154 /* *INDENT-OFF* */
1156 {
1157  .path = "show api clients",
1158  .short_help = "Client information",
1159  .function = vl_api_client_command,
1160 };
1161 /* *INDENT-ON* */
1162 
1163 /*?
1164  * Display the current api message tracing status
1165 ?*/
1166 /* *INDENT-OFF* */
1168 {
1169  .path = "show api trace-status",
1170  .short_help = "Display API trace status",
1171  .function = vl_api_status_command,
1172 };
1173 /* *INDENT-ON* */
1174 
1175 static clib_error_t *
1177  unformat_input_t * input,
1178  vlib_cli_command_t * cli_cmd)
1179 {
1180  api_main_t *am = &api_main;
1181  int i;
1182  int verbose = 0;
1183 
1184  if (unformat (input, "verbose"))
1185  verbose = 1;
1186 
1187 
1188  if (verbose == 0)
1189  vlib_cli_output (vm, "%-4s %s", "ID", "Name");
1190  else
1191  vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
1192  "MP-safe");
1193 
1194  for (i = 1; i < vec_len (am->msg_names); i++)
1195  {
1196  if (verbose == 0)
1197  {
1198  vlib_cli_output (vm, "%-4d %s", i,
1199  am->msg_names[i] ? am->msg_names[i] :
1200  " [no handler]");
1201  }
1202  else
1203  {
1204  vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
1205  am->msg_names[i] ? am->msg_names[i] :
1206  " [no handler]", am->message_bounce[i],
1207  am->is_mp_safe[i]);
1208  }
1209  }
1210 
1211  return 0;
1212 }
1213 
1214 /*?
1215  * Display the current api message decode tables
1216 ?*/
1217 /* *INDENT-OFF* */
1219 {
1220  .path = "show api message-table",
1221  .short_help = "Message Table",
1222  .function = vl_api_message_table_command,
1223 };
1224 /* *INDENT-ON* */
1225 
1226 static clib_error_t *
1228  unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1229 {
1230  u32 nitems = 1024;
1232  api_main_t *am = &api_main;
1233 
1234  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1235  {
1236  if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
1237  goto configure;
1238  else if (unformat (input, "tx nitems %u", &nitems)
1239  || unformat (input, "tx"))
1240  {
1241  which = VL_API_TRACE_RX;
1242  goto configure;
1243  }
1244  else if (unformat (input, "on rx"))
1245  {
1247  }
1248  else if (unformat (input, "on tx"))
1249  {
1251  }
1252  else if (unformat (input, "on"))
1253  {
1255  }
1256  else if (unformat (input, "off"))
1257  {
1260  }
1261  else if (unformat (input, "free"))
1262  {
1267  }
1268  else if (unformat (input, "debug on"))
1269  {
1270  am->msg_print_flag = 1;
1271  }
1272  else if (unformat (input, "debug off"))
1273  {
1274  am->msg_print_flag = 0;
1275  }
1276  else
1277  return clib_error_return (0, "unknown input `%U'",
1278  format_unformat_error, input);
1279  }
1280  return 0;
1281 
1282 configure:
1283  if (vl_msg_api_trace_configure (am, which, nitems))
1284  {
1285  vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
1286  which, nitems);
1287  }
1288 
1289  return 0;
1290 }
1291 
1292 /*?
1293  * Control the binary API trace mechanism
1294 ?*/
1295 /* *INDENT-OFF* */
1297 {
1298  .path = "set api-trace [on][on tx][on rx][off][free][debug on][debug off]",
1299  .short_help = "API trace",
1300  .function = vl_api_trace_command,
1301 };
1302 /* *INDENT-ON* */
1303 
1304 clib_error_t *
1306 {
1307  api_main_t *am = &api_main;
1308  svm_map_region_args_t _a, *a = &_a;
1309 
1310  memset (a, 0, sizeof (*a));
1311  a->root_path = am->root_path;
1313  a->baseva = (am->global_baseva != 0) ?
1315  a->size = (am->global_size != 0) ? am->global_size : SVM_GLOBAL_REGION_SIZE;
1316  a->flags = SVM_FLAGS_NODATA;
1317  a->uid = am->api_uid;
1318  a->gid = am->api_gid;
1319  a->pvt_heap_size =
1320  (am->global_pvt_heap_size !=
1322 
1324  return 0;
1325 }
1326 
1328 
1329 void
1330 vl_set_memory_region_name (const char *name)
1331 {
1332  api_main_t *am = &api_main;
1333 
1334  am->region_name = name;
1335 }
1336 
1337 static int
1339 {
1340  int len0, len1, clen;
1341 
1342  len0 = vec_len (a0->name);
1343  len1 = vec_len (a1->name);
1344  clen = len0 < len1 ? len0 : len1;
1345  return (strncmp ((char *) a0->name, (char *) a1->name, clen));
1346 }
1347 
1348 static u8 *
1349 format_api_msg_range (u8 * s, va_list * args)
1350 {
1351  vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
1352 
1353  if (rp == 0)
1354  s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
1355  else
1356  s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
1357  rp->last_msg_id);
1358 
1359  return s;
1360 }
1361 
1362 static clib_error_t *
1364  unformat_input_t * input,
1365  vlib_cli_command_t * cli_cmd)
1366 {
1367  api_main_t *am = &api_main;
1368  vl_api_msg_range_t *rp = 0;
1369  int i;
1370 
1371  if (vec_len (am->msg_ranges) == 0)
1372  {
1373  vlib_cli_output (vm, "No plugin API message ranges configured...");
1374  return 0;
1375  }
1376 
1377  rp = vec_dup (am->msg_ranges);
1378 
1380 
1381  vlib_cli_output (vm, "Plugin API message ID ranges...\n");
1382  vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
1383 
1384  for (i = 0; i < vec_len (rp); i++)
1385  vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
1386 
1387  vec_free (rp);
1388 
1389  return 0;
1390 }
1391 
1392 /*?
1393  * Display the plugin binary API message range table
1394 ?*/
1395 /* *INDENT-OFF* */
1397 {
1398  .path = "show api plugin",
1399  .short_help = "show api plugin",
1400  .function = vl_api_show_plugin_command,
1401 };
1402 /* *INDENT-ON* */
1403 
1404 static void
1406 {
1407  vl_api_rpc_call_reply_t *rmp;
1408  int (*fp) (void *);
1409  i32 rv = 0;
1410  vlib_main_t *vm = vlib_get_main ();
1411 
1412  if (mp->function == 0)
1413  {
1414  rv = -1;
1415  clib_warning ("rpc NULL function pointer");
1416  }
1417 
1418  else
1419  {
1420  if (mp->need_barrier_sync)
1422 
1423  fp = uword_to_pointer (mp->function, int (*)(void *));
1424  rv = fp (mp->data);
1425 
1426  if (mp->need_barrier_sync)
1428  }
1429 
1430  if (mp->send_reply)
1431  {
1434  if (q)
1435  {
1436  rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
1437  rmp->_vl_msg_id = ntohs (VL_API_RPC_CALL_REPLY);
1438  rmp->context = mp->context;
1439  rmp->retval = rv;
1440  vl_msg_api_send_shmem (q, (u8 *) & rmp);
1441  }
1442  }
1443  if (mp->multicast)
1444  {
1445  clib_warning ("multicast not yet implemented...");
1446  }
1447 }
1448 
1449 static void
1450 vl_api_rpc_call_reply_t_handler (vl_api_rpc_call_reply_t * mp)
1451 {
1452  clib_warning ("unimplemented");
1453 }
1454 
1455 always_inline void
1456 vl_api_rpc_call_main_thread_inline (void *fp, u8 * data, u32 data_length,
1457  u8 force_rpc)
1458 {
1459  vl_api_rpc_call_t *mp;
1460  api_main_t *am = &api_main;
1463 
1464  /* Main thread: call the function directly */
1465  if ((force_rpc == 0) && (vlib_get_thread_index () == 0))
1466  {
1467  vlib_main_t *vm = vlib_get_main ();
1468  void (*call_fp) (void *);
1469 
1471 
1472  call_fp = fp;
1473  call_fp (data);
1474 
1476  return;
1477  }
1478 
1479  /* Any other thread, actually do an RPC call... */
1480  mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + data_length);
1481 
1482  memset (mp, 0, sizeof (*mp));
1483  clib_memcpy (mp->data, data, data_length);
1484  mp->_vl_msg_id = ntohs (VL_API_RPC_CALL);
1485  mp->function = pointer_to_uword (fp);
1486  mp->need_barrier_sync = 1;
1487 
1488  /*
1489  * Use the "normal" control-plane mechanism for the main thread.
1490  * Well, almost. if the main input queue is full, we cannot
1491  * block. Otherwise, we can expect a barrier sync timeout.
1492  */
1493  q = shmem_hdr->vl_input_queue;
1494 
1495  while (pthread_mutex_trylock (&q->mutex))
1497 
1499  {
1500  pthread_mutex_unlock (&q->mutex);
1502  while (pthread_mutex_trylock (&q->mutex))
1504  }
1505 
1506  vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1507 
1508  pthread_mutex_unlock (&q->mutex);
1509 }
1510 
1511 /*
1512  * Check if called from worker threads.
1513  * If so, make rpc call of fp through shmem.
1514  * Otherwise, call fp directly
1515  */
1516 void
1517 vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
1518 {
1519  vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */
1520  0);
1521 }
1522 
1523 /*
1524  * Always make rpc call of fp through shmem, useful for calling from threads
1525  * not setup as worker threads, such as DPDK callback thread
1526  */
1527 void
1528 vl_api_force_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
1529 {
1530  vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */
1531  1);
1532 }
1533 
1534 static void
1536 {
1537  api_main_t *am = &api_main;
1538  vl_api_msg_range_t *rp;
1539  uword *p;
1540 
1541  /* Noop (except for tracing) during normal operation */
1542  if (am->replay_in_progress == 0)
1543  return;
1544 
1546  if (p == 0)
1547  {
1548  clib_warning ("WARNING: traced plugin '%s' not in current image",
1549  mp->plugin_name);
1550  return;
1551  }
1552 
1553  rp = vec_elt_at_index (am->msg_ranges, p[0]);
1554  if (rp->first_msg_id != clib_net_to_host_u16 (mp->first_msg_id))
1555  {
1556  clib_warning ("WARNING: traced plugin '%s' first message id %d not %d",
1557  mp->plugin_name, clib_net_to_host_u16 (mp->first_msg_id),
1558  rp->first_msg_id);
1559  }
1560 
1561  if (rp->last_msg_id != clib_net_to_host_u16 (mp->last_msg_id))
1562  {
1563  clib_warning ("WARNING: traced plugin '%s' last message id %d not %d",
1564  mp->plugin_name, clib_net_to_host_u16 (mp->last_msg_id),
1565  rp->last_msg_id);
1566  }
1567 }
1568 
1569 #define foreach_rpc_api_msg \
1570 _(RPC_CALL,rpc_call) \
1571 _(RPC_CALL_REPLY,rpc_call_reply)
1572 
1573 #define foreach_plugin_trace_msg \
1574 _(TRACE_PLUGIN_MSG_IDS,trace_plugin_msg_ids)
1575 
1576 /*
1577  * Set the rpc callback at our earliest possible convenience.
1578  * This avoids ordering issues between thread_init() -> start_workers and
1579  * an init function which we could define here. If we ever intend to use
1580  * vlib all by itself, we can't create a link-time dependency on
1581  * an init function here and a typical "call foo_init first"
1582  * guitar lick.
1583  */
1584 
1585 extern void *rpc_call_main_thread_cb_fn;
1586 
1587 static clib_error_t *
1589 {
1590  api_main_t *am = &api_main;
1591 #define _(N,n) \
1592  vl_msg_api_set_handlers(VL_API_##N, #n, \
1593  vl_api_##n##_t_handler, \
1594  vl_noop_handler, \
1595  vl_noop_handler, \
1596  vl_api_##n##_t_print, \
1597  sizeof(vl_api_##n##_t), 0 /* do not trace */);
1599 #undef _
1600 
1601 #define _(N,n) \
1602  vl_msg_api_set_handlers(VL_API_##N, #n, \
1603  vl_api_##n##_t_handler, \
1604  vl_noop_handler, \
1605  vl_noop_handler, \
1606  vl_api_##n##_t_print, \
1607  sizeof(vl_api_##n##_t), 1 /* do trace */);
1609 #undef _
1610 
1611  /* No reason to halt the parade to create a trace record... */
1612  am->is_mp_safe[VL_API_TRACE_PLUGIN_MSG_IDS] = 1;
1613  rpc_call_main_thread_cb_fn = vl_api_rpc_call_main_thread;
1614  return 0;
1615 }
1616 
1618 
1619 typedef enum
1620 {
1625 } vl_api_replay_t;
1626 
1627 u8 *
1628 format_vl_msg_api_trace_status (u8 * s, va_list * args)
1629 {
1630  api_main_t *am = va_arg (*args, api_main_t *);
1631  vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1632  vl_api_trace_t *tp;
1633  char *trace_name;
1634 
1635  switch (which)
1636  {
1637  case VL_API_TRACE_TX:
1638  tp = am->tx_trace;
1639  trace_name = "TX trace";
1640  break;
1641 
1642  case VL_API_TRACE_RX:
1643  tp = am->rx_trace;
1644  trace_name = "RX trace";
1645  break;
1646 
1647  default:
1648  abort ();
1649  }
1650 
1651  if (tp == 0)
1652  {
1653  s = format (s, "%s: not yet configured.\n", trace_name);
1654  return s;
1655  }
1656 
1657  s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1658  trace_name, vec_len (tp->traces), tp->nitems,
1659  tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1660  return s;
1661 }
1662 
1664  __attribute__ ((weak));
1665 void
1667 {
1668 }
1669 
1670 static void
1672  u32 first_index, u32 last_index,
1673  vl_api_replay_t which)
1674 {
1675  vl_api_trace_file_header_t *hp;
1676  int i, fd;
1677  struct stat statb;
1678  size_t file_size;
1679  u8 *msg;
1680  u8 endian_swap_needed = 0;
1681  api_main_t *am = &api_main;
1682  u8 *tmpbuf = 0;
1683  u32 nitems;
1684  void **saved_print_handlers = 0;
1685 
1686  fd = open ((char *) filename, O_RDONLY);
1687 
1688  if (fd < 0)
1689  {
1690  vlib_cli_output (vm, "Couldn't open %s\n", filename);
1691  return;
1692  }
1693 
1694  if (fstat (fd, &statb) < 0)
1695  {
1696  vlib_cli_output (vm, "Couldn't stat %s\n", filename);
1697  close (fd);
1698  return;
1699  }
1700 
1701  if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
1702  {
1703  vlib_cli_output (vm, "File not plausible: %s\n", filename);
1704  close (fd);
1705  return;
1706  }
1707 
1708  file_size = statb.st_size;
1709  file_size = (file_size + 4095) & ~(4096);
1710 
1711  hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
1712 
1713  if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
1714  {
1715  vlib_cli_output (vm, "mmap failed: %s\n", filename);
1716  close (fd);
1717  return;
1718  }
1719  close (fd);
1720 
1721  if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
1722  || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
1723  endian_swap_needed = 1;
1724 
1725  if (endian_swap_needed)
1726  nitems = ntohl (hp->nitems);
1727  else
1728  nitems = hp->nitems;
1729 
1730  if (last_index == (u32) ~ 0)
1731  {
1732  last_index = nitems - 1;
1733  }
1734 
1735  if (first_index >= nitems || last_index >= nitems)
1736  {
1737  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
1738  first_index, last_index, nitems - 1);
1739  munmap (hp, file_size);
1740  return;
1741  }
1742  if (hp->wrapped)
1743  vlib_cli_output (vm,
1744  "Note: wrapped/incomplete trace, results may vary\n");
1745 
1746  if (which == CUSTOM_DUMP)
1747  {
1748  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
1750  }
1751 
1752 
1753  msg = (u8 *) (hp + 1);
1754 
1755  for (i = 0; i < first_index; i++)
1756  {
1757  trace_cfg_t *cfgp;
1758  int size;
1759  u16 msg_id;
1760 
1761  size = clib_host_to_net_u32 (*(u32 *) msg);
1762  msg += sizeof (u32);
1763 
1765  msg_id = ntohs (*((u16 *) msg));
1766  else
1767  msg_id = *((u16 *) msg);
1768 
1769  cfgp = am->api_trace_cfg + msg_id;
1770  if (!cfgp)
1771  {
1772  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
1773  munmap (hp, file_size);
1774  return;
1775  }
1776  msg += size;
1777  }
1778 
1779  if (which == REPLAY)
1780  am->replay_in_progress = 1;
1781 
1782  for (; i <= last_index; i++)
1783  {
1784  trace_cfg_t *cfgp;
1785  u16 *msg_idp;
1786  u16 msg_id;
1787  int size;
1788 
1789  if (which == DUMP)
1790  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
1791 
1792  size = clib_host_to_net_u32 (*(u32 *) msg);
1793  msg += sizeof (u32);
1794 
1796  msg_id = ntohs (*((u16 *) msg));
1797  else
1798  msg_id = *((u16 *) msg);
1799 
1800  cfgp = am->api_trace_cfg + msg_id;
1801  if (!cfgp)
1802  {
1803  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
1804  munmap (hp, file_size);
1805  vec_free (tmpbuf);
1806  am->replay_in_progress = 0;
1807  return;
1808  }
1809 
1810  /* Copy the buffer (from the read-only mmap'ed file) */
1811  vec_validate (tmpbuf, size - 1 + sizeof (uword));
1812  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
1813  memset (tmpbuf, 0xf, sizeof (uword));
1814 
1815  /*
1816  * Endian swap if needed. All msg data is supposed to be
1817  * in network byte order. All msg handlers are supposed to
1818  * know that. The generic message dumpers don't know that.
1819  * One could fix apigen, I suppose.
1820  */
1821  if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
1822  {
1823  void (*endian_fp) (void *);
1824  if (msg_id >= vec_len (am->msg_endian_handlers)
1825  || (am->msg_endian_handlers[msg_id] == 0))
1826  {
1827  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
1828  munmap (hp, file_size);
1829  vec_free (tmpbuf);
1830  am->replay_in_progress = 0;
1831  return;
1832  }
1833  endian_fp = am->msg_endian_handlers[msg_id];
1834  (*endian_fp) (tmpbuf + sizeof (uword));
1835  }
1836 
1837  /* msg_id always in network byte order */
1839  {
1840  msg_idp = (u16 *) (tmpbuf + sizeof (uword));
1841  *msg_idp = msg_id;
1842  }
1843 
1844  switch (which)
1845  {
1846  case CUSTOM_DUMP:
1847  case DUMP:
1848  if (msg_id < vec_len (am->msg_print_handlers) &&
1849  am->msg_print_handlers[msg_id])
1850  {
1851  u8 *(*print_fp) (void *, void *);
1852 
1853  print_fp = (void *) am->msg_print_handlers[msg_id];
1854  (*print_fp) (tmpbuf + sizeof (uword), vm);
1855  }
1856  else
1857  {
1858  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
1859  msg_id);
1860  break;
1861  }
1862  break;
1863 
1864  case INITIALIZERS:
1865  if (msg_id < vec_len (am->msg_print_handlers) &&
1866  am->msg_print_handlers[msg_id])
1867  {
1868  u8 *s;
1869  int j;
1870  u8 *(*print_fp) (void *, void *);
1871 
1872  print_fp = (void *) am->msg_print_handlers[msg_id];
1873 
1874  vlib_cli_output (vm, "/*");
1875 
1876  (*print_fp) (tmpbuf + sizeof (uword), vm);
1877  vlib_cli_output (vm, "*/\n");
1878 
1879  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
1880  am->msg_names[msg_id], i,
1881  am->api_trace_cfg[msg_id].size);
1882 
1883  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
1884  {
1885  if ((j & 7) == 0)
1886  s = format (s, "\n ");
1887  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
1888  }
1889  s = format (s, "\n};\n%c", 0);
1890  vlib_cli_output (vm, (char *) s);
1891  vec_free (s);
1892  }
1893  break;
1894 
1895  case REPLAY:
1896  if (msg_id < vec_len (am->msg_print_handlers) &&
1897  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
1898  {
1899  void (*handler) (void *);
1900 
1901  handler = (void *) am->msg_handlers[msg_id];
1902 
1903  if (!am->is_mp_safe[msg_id])
1905  (*handler) (tmpbuf + sizeof (uword));
1906  if (!am->is_mp_safe[msg_id])
1908  }
1909  else
1910  {
1911  if (cfgp->replay_enable)
1912  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
1913  msg_id);
1914  break;
1915  }
1916  break;
1917  }
1918 
1919  _vec_len (tmpbuf) = 0;
1920  msg += size;
1921  }
1922 
1923  if (saved_print_handlers)
1924  {
1925  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
1926  vec_len (am->msg_print_handlers) * sizeof (void *));
1927  vec_free (saved_print_handlers);
1928  }
1929 
1930  munmap (hp, file_size);
1931  vec_free (tmpbuf);
1932  am->replay_in_progress = 0;
1933 }
1934 
1935 static clib_error_t *
1937  unformat_input_t * input, vlib_cli_command_t * cmd)
1938 {
1939  u32 nitems = 256 << 10;
1940  api_main_t *am = &api_main;
1942  u8 *filename;
1943  u32 first = 0;
1944  u32 last = (u32) ~ 0;
1945  FILE *fp;
1946  int rv;
1947 
1948  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1949  {
1950  if (unformat (input, "on") || unformat (input, "enable"))
1951  {
1952  if (unformat (input, "nitems %d", &nitems))
1953  ;
1954  vl_msg_api_trace_configure (am, which, nitems);
1955  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1956  }
1957  else if (unformat (input, "off"))
1958  {
1959  vl_msg_api_trace_onoff (am, which, 0);
1960  }
1961  else if (unformat (input, "save %s", &filename))
1962  {
1963  u8 *chroot_filename;
1964  if (strstr ((char *) filename, "..")
1965  || index ((char *) filename, '/'))
1966  {
1967  vlib_cli_output (vm, "illegal characters in filename '%s'",
1968  filename);
1969  return 0;
1970  }
1971 
1972  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1973 
1974  vec_free (filename);
1975 
1976  fp = fopen ((char *) chroot_filename, "w");
1977  if (fp == NULL)
1978  {
1979  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1980  return 0;
1981  }
1982  rv = vl_msg_api_trace_save (am, which, fp);
1983  fclose (fp);
1984  if (rv == -1)
1985  vlib_cli_output (vm, "API Trace data not present\n");
1986  else if (rv == -2)
1987  vlib_cli_output (vm, "File for writing is closed\n");
1988  else if (rv == -10)
1989  vlib_cli_output (vm, "Error while writing header to file\n");
1990  else if (rv == -11)
1991  vlib_cli_output (vm, "Error while writing trace to file\n");
1992  else if (rv == -12)
1993  vlib_cli_output (vm,
1994  "Error while writing end of buffer trace to file\n");
1995  else if (rv == -13)
1996  vlib_cli_output (vm,
1997  "Error while writing start of buffer trace to file\n");
1998  else if (rv < 0)
1999  vlib_cli_output (vm, "Unkown error while saving: %d", rv);
2000  else
2001  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
2002  vec_free (chroot_filename);
2003  }
2004  else if (unformat (input, "dump %s", &filename))
2005  {
2006  vl_msg_api_process_file (vm, filename, first, last, DUMP);
2007  }
2008  else if (unformat (input, "custom-dump %s", &filename))
2009  {
2010  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
2011  }
2012  else if (unformat (input, "replay %s", &filename))
2013  {
2014  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
2015  }
2016  else if (unformat (input, "initializers %s", &filename))
2017  {
2018  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
2019  }
2020  else if (unformat (input, "tx"))
2021  {
2022  which = VL_API_TRACE_TX;
2023  }
2024  else if (unformat (input, "first %d", &first))
2025  {
2026  ;
2027  }
2028  else if (unformat (input, "last %d", &last))
2029  {
2030  ;
2031  }
2032  else if (unformat (input, "status"))
2033  {
2035  am, which);
2036  }
2037  else if (unformat (input, "free"))
2038  {
2039  vl_msg_api_trace_onoff (am, which, 0);
2040  vl_msg_api_trace_free (am, which);
2041  }
2042  else if (unformat (input, "post-mortem-on"))
2044  else if (unformat (input, "post-mortem-off"))
2046  else
2047  return clib_error_return (0, "unknown input `%U'",
2048  format_unformat_error, input);
2049  }
2050  return 0;
2051 }
2052 
2053 /*?
2054  * Display, replay, or save a binary API trace
2055 ?*/
2056 
2057 /* *INDENT-OFF* */
2059 {
2060  .path = "api trace",
2061  .short_help =
2062  "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
2063  .function = api_trace_command_fn,
2064 };
2065 /* *INDENT-ON* */
2066 
2067 static clib_error_t *
2069 {
2070  u32 nitems = 256 << 10;
2072  api_main_t *am = &api_main;
2073 
2074  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2075  {
2076  if (unformat (input, "on") || unformat (input, "enable"))
2077  {
2078  if (unformat (input, "nitems %d", &nitems))
2079  ;
2080  vl_msg_api_trace_configure (am, which, nitems);
2081  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
2083  }
2084  else if (unformat (input, "save-api-table %s",
2086  ;
2087  else
2088  return clib_error_return (0, "unknown input `%U'",
2089  format_unformat_error, input);
2090  }
2091  return 0;
2092 }
2093 
2094 /*?
2095  * This module has three configuration parameters:
2096  * "on" or "enable" - enables binary api tracing
2097  * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
2098  * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
2099 ?*/
2100 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
2101 
2102 static clib_error_t *
2104 {
2105  api_main_t *am = &api_main;
2106  u32 nitems;
2107 
2108  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2109  {
2110  if (unformat (input, "length %d", &nitems) ||
2111  (unformat (input, "len %d", &nitems)))
2112  {
2113  if (nitems >= 1024)
2114  am->vlib_input_queue_length = nitems;
2115  else
2116  clib_warning ("vlib input queue length %d too small, ignored",
2117  nitems);
2118  }
2119  else
2120  return clib_error_return (0, "unknown input `%U'",
2121  format_unformat_error, input);
2122  }
2123  return 0;
2124 }
2125 
2127 
2128 static u8 *
2130 {
2131  u8 *rv;
2132 
2133  rv = vec_dup (s);
2134 
2135  while (vec_len (rv) && rv[vec_len (rv)] != '_')
2136  _vec_len (rv)--;
2137 
2138  rv[vec_len (rv)] = 0;
2139 
2140  return rv;
2141 }
2142 
2143 static u8 *
2145 {
2146  int i;
2147  u8 *rv;
2148 
2149  rv = vec_dup (s);
2150 
2151  for (i = vec_len (rv) - 1; i >= 0; i--)
2152  {
2153  if (rv[i] == '_')
2154  {
2155  vec_delete (rv, i + 1, 0);
2156  break;
2157  }
2158  }
2159  return rv;
2160 }
2161 
2162 typedef struct
2163 {
2168  int which;
2170 
2171 static int
2172 table_id_cmp (void *a1, void *a2)
2173 {
2174  msg_table_unserialize_t *n1 = a1;
2175  msg_table_unserialize_t *n2 = a2;
2176 
2177  return (n1->msg_index - n2->msg_index);
2178 }
2179 
2180 static int
2181 table_name_and_crc_cmp (void *a1, void *a2)
2182 {
2183  msg_table_unserialize_t *n1 = a1;
2184  msg_table_unserialize_t *n2 = a2;
2185 
2186  return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
2187 }
2188 
2189 static clib_error_t *
2191  unformat_input_t * input,
2192  vlib_cli_command_t * cmd)
2193 {
2194  u8 *filename = 0;
2195  api_main_t *am = &api_main;
2196  serialize_main_t _sm, *sm = &_sm;
2197  clib_error_t *error;
2198  u32 nmsgs;
2199  u32 msg_index;
2200  u8 *name_and_crc;
2201  int compare_current = 0;
2202  int numeric_sort = 0;
2203  msg_table_unserialize_t *table = 0, *item;
2204  u32 i;
2205  u32 ndifferences = 0;
2206 
2207  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2208  {
2209  if (unformat (input, "file %s", &filename))
2210  ;
2211  else if (unformat (input, "compare-current")
2212  || unformat (input, "compare"))
2213  compare_current = 1;
2214  else if (unformat (input, "numeric"))
2215  numeric_sort = 1;
2216  else
2217  return clib_error_return (0, "unknown input `%U'",
2218  format_unformat_error, input);
2219  }
2220 
2221  if (numeric_sort && compare_current)
2222  return clib_error_return
2223  (0, "Comparison and numeric sorting are incompatible");
2224 
2225  if (filename == 0)
2226  return clib_error_return (0, "File not specified");
2227 
2228  /* Load the serialized message table from the table dump */
2229 
2230  error = unserialize_open_unix_file (sm, (char *) filename);
2231 
2232  if (error)
2233  return error;
2234 
2235  unserialize_integer (sm, &nmsgs, sizeof (u32));
2236 
2237  for (i = 0; i < nmsgs; i++)
2238  {
2240  unserialize_cstring (sm, (char **) &name_and_crc);
2241  vec_add2 (table, item, 1);
2242  item->msg_index = msg_index;
2243  item->name_and_crc = name_and_crc;
2244  item->name = extract_name (name_and_crc);
2245  item->crc = extract_crc (name_and_crc);
2246  item->which = 0; /* file */
2247  }
2248  serialize_close (sm);
2249 
2250  /* Compare with the current image? */
2251  if (compare_current)
2252  {
2253  /* Append the current message table */
2255 
2256  serialize_open_vector (sm, tblv);
2257  unserialize_integer (sm, &nmsgs, sizeof (u32));
2258 
2259  for (i = 0; i < nmsgs; i++)
2260  {
2262  unserialize_cstring (sm, (char **) &name_and_crc);
2263 
2264  vec_add2 (table, item, 1);
2265  item->msg_index = msg_index;
2266  item->name_and_crc = name_and_crc;
2267  item->name = extract_name (name_and_crc);
2268  item->crc = extract_crc (name_and_crc);
2269  item->which = 1; /* current_image */
2270  }
2271  }
2272 
2273  /* Sort the table. */
2274  if (numeric_sort)
2276  else
2278 
2279  if (compare_current)
2280  {
2281  ndifferences = 0;
2282 
2283  /*
2284  * In this case, the recovered table will have two entries per
2285  * API message. So, if entries i and i+1 match, the message definitions
2286  * are identical. Otherwise, the crc is different, or a message is
2287  * present in only one of the tables.
2288  */
2289  vlib_cli_output (vm, "%=60s %s", "Message Name", "Result");
2290 
2291  for (i = 0; i < vec_len (table);)
2292  {
2293  /* Last message lonely? */
2294  if (i == vec_len (table) - 1)
2295  {
2296  ndifferences++;
2297  goto last_unique;
2298  }
2299 
2300  /* Identical pair? */
2301  if (!strncmp
2302  ((char *) table[i].name_and_crc,
2303  (char *) table[i + 1].name_and_crc,
2304  vec_len (table[i].name_and_crc)))
2305  {
2306  i += 2;
2307  continue;
2308  }
2309 
2310  ndifferences++;
2311 
2312  /* Only in one of two tables? */
2313  if (strncmp ((char *) table[i].name, (char *) table[i + 1].name,
2314  vec_len (table[i].name)))
2315  {
2316  last_unique:
2317  vlib_cli_output (vm, "%-60s only in %s",
2318  table[i].name, table[i].which ?
2319  "image" : "file");
2320  i++;
2321  continue;
2322  }
2323  /* In both tables, but with different signatures */
2324  vlib_cli_output (vm, "%-60s definition changed", table[i].name);
2325  i += 2;
2326  }
2327  if (ndifferences == 0)
2328  vlib_cli_output (vm, "No api message signature differences found.");
2329  else
2330  vlib_cli_output (vm, "Found %u api message signature differences",
2331  ndifferences);
2332  goto cleanup;
2333  }
2334 
2335  /* Dump the table, sorted as shown above */
2336  vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
2337 
2338  for (i = 0; i < vec_len (table); i++)
2339  {
2340  item = table + i;
2341  vlib_cli_output (vm, "%-60s %8u %10s", item->name,
2342  item->msg_index, item->crc);
2343  }
2344 
2345 cleanup:
2346  for (i = 0; i < vec_len (table); i++)
2347  {
2348  vec_free (table[i].name_and_crc);
2349  vec_free (table[i].name);
2350  vec_free (table[i].crc);
2351  }
2352 
2353  vec_free (table);
2354 
2355  return 0;
2356 }
2357 
2358 /*?
2359  * Displays a serialized API message decode table, sorted by message name
2360  *
2361  * @cliexpar
2362  * @cliexstart{show api dump file <filename>}
2363  * Message name MsgID CRC
2364  * accept_session 407 8e2a127e
2365  * accept_session_reply 408 67d8c22a
2366  * add_node_next 549 e4202993
2367  * add_node_next_reply 550 e89d6eed
2368  * etc.
2369  * @cliexend
2370 ?*/
2371 
2372 /*?
2373  * Compares a serialized API message decode table with the current image
2374  *
2375  * @cliexpar
2376  * @cliexstart{show api dump file <filename> compare}
2377  * ip_add_del_route definition changed
2378  * ip_table_add_del definition changed
2379  * l2_macs_event only in image
2380  * vnet_ip4_fib_counters only in file
2381  * vnet_ip4_nbr_counters only in file
2382  * @cliexend
2383 ?*/
2384 
2385 /*?
2386  * Display a serialized API message decode table, compare a saved
2387  * decode table with the current image, to establish API differences.
2388  *
2389 ?*/
2390 /* *INDENT-OFF* */
2392 {
2393  .path = "show api dump",
2394  .short_help = "show api dump file <filename> [numeric | compare-current]",
2395  .function = dump_api_table_file_command_fn,
2396 };
2397 /* *INDENT-ON* */
2398 
2399 /*
2400  * fd.io coding-style-patch-verification: ON
2401  *
2402  * Local Variables:
2403  * eval: (c-set-style "gnu")
2404  * End:
2405  */
#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:101
void vl_set_memory_region_name(const char *name)
Definition: memory_vlib.c:1330
static int table_id_cmp(void *a1, void *a2)
Definition: memory_vlib.c:2172
void * vl_msg_api_alloc_as_if_client(int nbytes)
#define TRACE_VLIB_MEMORY_QUEUE
Definition: memory_vlib.c:49
#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:404
#define SVM_GLOBAL_REGION_NAME
Definition: svm_common.h:88
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:285
u8 * name
name of the plugin
Definition: api_common.h:103
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:317
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: memory_vlib.c:1296
static clib_error_t * api_queue_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: memory_vlib.c:2103
static clib_error_t * setup_memclnt_exit(vlib_main_t *vm)
Definition: memory_vlib.c:966
u8 wrapped
trace has wrapped
Definition: api_common.h:83
u32 application_restarts
Definition: api_common.h:79
int size
for sanity checking
Definition: api_common.h:71
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:957
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:221
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:1032
u8 * message_bounce
Don&#39;t automatically free message buffer vetor.
Definition: api_common.h:202
Message configuration definition.
Definition: api_common.h:109
#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:1535
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:1176
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:1363
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
#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
int api_uid
uid for the api shared memory region
Definition: api_common.h:259
static clib_error_t * api_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: memory_vlib.c:2068
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:845
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:112
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
Definition: pool.h:259
static void vl_api_rpc_call_reply_t_handler(vl_api_rpc_call_reply_t *mp)
Definition: memory_vlib.c:1450
void vl_api_get_first_msg_id_t_handler(vl_api_get_first_msg_id_t *mp)
Definition: memory_vlib.c:356
#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:262
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:2190
void vl_enable_disable_memory_api(vlib_main_t *vm, int enable)
Definition: memory_vlib.c:898
#define VL_API_EPOCH_MASK
Definition: api_common.h:91
trace_cfg_t * api_trace_cfg
Current trace configuration.
Definition: api_common.h:229
static vlib_cli_command_t cli_show_api_clients_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_clients_command)
Definition: memory_vlib.c:1155
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#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:316
void vl_msg_api_custom_dump_configure(api_main_t *am)
Definition: memory_vlib.c:1666
#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:312
static void vlib_worker_thread_barrier_check(void)
Definition: threads.h:392
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:448
#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
static vlib_cli_command_t cli_show_api_status_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_status_command)
Definition: memory_vlib.c:1167
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:437
static int range_compare(vl_api_msg_range_t *a0, vl_api_msg_range_t *a1)
Definition: memory_vlib.c:1338
vl_api_trace_t * rx_trace
Received message trace configuration.
Definition: api_common.h:220
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
clib_error_t * unserialize_open_unix_file(serialize_main_t *m, char *file)
Definition: serialize.c:1241
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:211
static void * svm_push_data_heap(svm_region_t *rp)
Definition: svm.h:86
#define always_inline
Definition: clib.h:84
vl_api_registration_t ** vl_clients
vlib/vpp only: vector of client registrations
Definition: api_common.h:244
static vlib_cli_command_t cli_show_api_message_table_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_message_table_command)
Definition: memory_vlib.c:1218
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:310
static void send_one_plugin_msg_ids_msg(u8 *name, u16 first_msg_id, u16 last_msg_id)
Definition: memory_vlib.c:456
const char * root_path
Chroot path to the shared memory API files.
Definition: api_common.h:307
#define clib_error_return(e, args...)
Definition: error.h:99
svm_region_t * vlib_rp
Binary api segment descriptor.
Definition: api_common.h:235
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:1936
#define SVM_GLOBAL_REGION_BASEVA
Definition: svm_common.h:86
unsigned long u64
Definition: types.h:89
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:241
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: memory_vlib.c:103
#define foreach_plugin_trace_msg
Definition: memory_vlib.c:1573
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:869
static void vlib_set_queue_signal_callback(vlib_main_t *vm, void(*fp)(vlib_main_t *))
Definition: main.h:351
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:1792
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
static vlib_cli_command_t api_trace_command
(constructor) VLIB_CLI_COMMAND (api_trace_command)
Definition: memory_vlib.c:2058
u16 last_msg_id
last assigned message ID
Definition: api_common.h:105
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
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:458
#define foreach_rpc_api_msg
Definition: memory_vlib.c:1569
static vlib_node_registration_t memclnt_node
(constructor) VLIB_REGISTER_NODE (memclnt_node)
Definition: memory_vlib.c:788
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:976
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:265
void(** msg_print_handlers)(void *, void *)
Message print function vector.
Definition: api_common.h:196
int replay_enable
This message can be replayed.
Definition: api_common.h:73
struct _unformat_input_t unformat_input_t
static vlib_cli_command_t cli_show_api_ring_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_ring_command)
Definition: memory_vlib.c:1143
void vl_msg_api_free(void *)
#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
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:119
void svm_region_init_args(svm_map_region_args_t *a)
Definition: svm.c:840
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:1405
#define SVM_GLOBAL_REGION_SIZE
Definition: svm_common.h:87
static u32 vl_msg_api_handle_get_index(u32 index)
Definition: api.h:37
vl_api_replay_t
Definition: memory_vlib.c:1619
#define foreach_vlib_api_msg
Definition: memory_vlib.c:395
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
void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:178
#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:182
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:268
void vl_api_force_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1528
u8 enabled
trace is enabled
Definition: api_common.h:82
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:1456
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:79
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:1517
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:265
#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:54
vl_api_msg_range_t * msg_ranges
vector of message ranges
Definition: api_common.h:256
#define clib_warning(format, args...)
Definition: error.h:59
#define clib_memcpy(a, b, c)
Definition: string.h:69
#define foreach_histogram_bucket
Definition: memory_vlib.c:434
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:87
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:199
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:388
static vlib_cli_command_t cli_show_api_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_command)
Definition: memory_vlib.c:1132
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:1227
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:1671
#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:313
#define VL_API_BIG_ENDIAN
Definition: api_common.h:98
histogram_index_t
Definition: memory_vlib.c:440
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:223
static uword api_rx_from_node(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: memory_vlib.c:907
static vlib_cli_command_t cli_show_api_plugin_command
(constructor) VLIB_CLI_COMMAND (cli_show_api_plugin_command)
Definition: memory_vlib.c:1396
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:293
#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:1305
#define VL_API_LITTLE_ENDIAN
Definition: api_common.h:97
#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:448
static uword memclnt_process(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *f)
Definition: memory_vlib.c:478
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:125
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:2129
u8 * serialized_message_table_in_shmem
vlib/vpp only: serialized (message, name, crc) table
Definition: api_common.h:247
#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:1027
u64 global_pvt_heap_size
size of the global VM private mheap
Definition: api_common.h:274
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
size_t count
Definition: vapi.c:40
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:1349
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:1588
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:1097
u32 missing_clients
Number of missing clients / failed message sends.
Definition: api_common.h:217
void vl_msg_api_post_mortem_dump_enable_disable(int enable)
Definition: api_shared.c:773
unsigned short u16
Definition: types.h:57
u16 first_msg_id
first assigned message ID
Definition: api_common.h:104
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:189
void(** msg_endian_handlers)(void *)
Message endian handler vector.
Definition: api_common.h:193
#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:349
static u8 * extract_crc(u8 *s)
Definition: memory_vlib.c:2144
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
u8 * format_vl_msg_api_trace_status(u8 *s, va_list *args)
Definition: memory_vlib.c:1628
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:1157
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:798
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:185
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1488
u8 * is_mp_safe
Message is mp safe vector.
Definition: api_common.h:205
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static int table_name_and_crc_cmp(void *a1, void *a2)
Definition: memory_vlib.c:2181
u8 data[0]
Packet data.
Definition: buffer.h:157
int msg_print_flag
Print every received message.
Definition: api_common.h:226
static vlib_cli_command_t dump_api_table_file
(constructor) VLIB_CLI_COMMAND (dump_api_table_file)
Definition: memory_vlib.c:2391
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:91
const char * region_name
Shared VM binary API region name.
Definition: api_common.h:304
Trace configuration for a single message.
Definition: api_common.h:69
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:152
uword * msg_index_by_name_and_crc
client message index hash table
Definition: api_common.h:301
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:253
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:85
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:298
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