FD.io VPP  v17.01.1-3-gc6833f8
Vector Packet Processing
api_shared.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * api_shared.c - API message handling, common code for both clients
4  * and the vlib process itself.
5  *
6  *
7  * Copyright (c) 2009 Cisco and/or its affiliates.
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at:
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *------------------------------------------------------------------
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/mman.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <vppinfra/format.h>
32 #include <vppinfra/byte_order.h>
33 #include <vppinfra/error.h>
34 #include <vlib/vlib.h>
35 #include <vlib/unix/unix.h>
36 #include <vlibapi/api.h>
37 #include <vppinfra/elog.h>
38 
40 
41 void vl_msg_api_barrier_sync (void) __attribute__ ((weak));
42 void
44 {
45 }
46 
47 void vl_msg_api_barrier_release (void) __attribute__ ((weak));
48 void
50 {
51 }
52 
53 void
55 {
56  api_main_t *am = &api_main;
57  am->missing_clients++;
58 }
59 
60 typedef enum
61 {
67 
68 int
70 {
71  return (am->rx_trace && am->rx_trace->enabled);
72 }
73 
74 int
76 {
77  return (am->tx_trace && am->tx_trace->enabled);
78 }
79 
80 /*
81  * vl_msg_api_trace
82  */
83 void
85 {
86  u8 **this_trace;
87  u8 **old_trace;
88  u8 *msg_copy;
89  u32 length;
90  trace_cfg_t *cfgp;
91  u16 msg_id = ntohs (*((u16 *) msg));
92  msgbuf_t *header = (msgbuf_t *) (((u8 *) msg) - offsetof (msgbuf_t, data));
93 
94  cfgp = am->api_trace_cfg + msg_id;
95 
96  if (!cfgp || !cfgp->trace_enable)
97  return;
98 
99  msg_copy = 0;
100 
101  if (tp->nitems == 0)
102  {
103  clib_warning ("tp->nitems is 0");
104  return;
105  }
106 
107  if (vec_len (tp->traces) < tp->nitems)
108  {
109  vec_add1 (tp->traces, 0);
110  this_trace = tp->traces + vec_len (tp->traces) - 1;
111  }
112  else
113  {
114  tp->wrapped = 1;
115  old_trace = tp->traces + tp->curindex++;
116  if (tp->curindex == tp->nitems)
117  tp->curindex = 0;
118  vec_free (*old_trace);
119  this_trace = old_trace;
120  }
121 
122  length = clib_net_to_host_u32 (header->data_len);
123 
124  vec_validate (msg_copy, length - 1);
125  clib_memcpy (msg_copy, msg, length);
126  *this_trace = msg_copy;
127 }
128 
129 int
131  int onoff)
132 {
133  vl_api_trace_t *tp;
134  int rv;
135 
136  switch (which)
137  {
138  case VL_API_TRACE_TX:
139  tp = am->tx_trace;
140  if (tp == 0)
141  {
142  vl_msg_api_trace_configure (am, which, 1024);
143  tp = am->tx_trace;
144  }
145  break;
146 
147  case VL_API_TRACE_RX:
148  tp = am->rx_trace;
149  if (tp == 0)
150  {
151  vl_msg_api_trace_configure (am, which, 1024);
152  tp = am->rx_trace;
153  }
154  break;
155 
156  default:
157  /* duh? */
158  return -1;
159  }
160 
161  /* Configured? */
162  if (tp == 0 || tp->nitems == 0)
163  return -1;
164 
165  rv = tp->enabled;
166  tp->enabled = onoff;
167 
168  return rv;
169 }
170 
171 int
173 {
174  vl_api_trace_t *tp;
175  int i;
176 
177  switch (which)
178  {
179  case VL_API_TRACE_TX:
180  tp = am->tx_trace;
181  break;
182 
183  case VL_API_TRACE_RX:
184  tp = am->rx_trace;
185  break;
186 
187  default:
188  /* duh? */
189  return -1;
190  }
191 
192  /* Configured? */
193  if (!tp || tp->nitems == 0)
194  return -1;
195 
196  tp->curindex = 0;
197  tp->wrapped = 0;
198 
199  for (i = 0; i < vec_len (tp->traces); i++)
200  {
201  vec_free (tp->traces[i]);
202  }
203  vec_free (tp->traces);
204 
205  return 0;
206 }
207 
208 int
210 {
211  vl_api_trace_t *tp;
212  vl_api_trace_file_header_t fh;
213  int i;
214  u8 *msg;
215 
216  switch (which)
217  {
218  case VL_API_TRACE_TX:
219  tp = am->tx_trace;
220  break;
221 
222  case VL_API_TRACE_RX:
223  tp = am->rx_trace;
224  break;
225 
226  default:
227  /* duh? */
228  return -1;
229  }
230 
231  /* Configured, data present? */
232  if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
233  return -1;
234 
235  /* "Dare to be stupid" check */
236  if (fp == 0)
237  {
238  return -2;
239  }
240 
241  /* Write the file header */
242  fh.nitems = vec_len (tp->traces);
243  fh.endian = tp->endian;
244  fh.wrapped = tp->wrapped;
245 
246  if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
247  {
248  return (-10);
249  }
250 
251  /* No-wrap case */
252  if (tp->wrapped == 0)
253  {
254  /*
255  * Note: vec_len return 0 when fed a NULL pointer.
256  * Unfortunately, the static analysis tool doesn't
257  * figure it out, hence the suppressed warnings.
258  * What a great use of my time.
259  */
260  for (i = 0; i < vec_len (tp->traces); i++)
261  {
262  u32 msg_length;
263  /*sa_ignore NO_NULL_CHK */
264  msg = tp->traces[i];
265  /*
266  * This retarded check required to pass
267  * [sic] SA-checking.
268  */
269  if (!msg)
270  continue;
271 
272  msg_length = clib_host_to_net_u32 (vec_len (msg));
273  if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
274  != sizeof (msg_length))
275  {
276  return (-14);
277  }
278  if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
279  {
280  return (-11);
281  }
282  }
283  }
284  else
285  {
286  /* Wrap case: write oldest -> end of buffer */
287  for (i = tp->curindex; i < vec_len (tp->traces); i++)
288  {
289  u32 msg_length;
290  msg = tp->traces[i];
291  /*
292  * This retarded check required to pass
293  * [sic] SA-checking
294  */
295  if (!msg)
296  continue;
297 
298  msg_length = clib_host_to_net_u32 (vec_len (msg));
299  if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
300  != sizeof (msg_length))
301  {
302  return (-14);
303  }
304 
305  if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
306  {
307  return (-12);
308  }
309  }
310  /* write beginning of buffer -> oldest-1 */
311  for (i = 0; i < tp->curindex; i++)
312  {
313  u32 msg_length;
314  /*sa_ignore NO_NULL_CHK */
315  msg = tp->traces[i];
316  /*
317  * This retarded check required to pass
318  * [sic] SA-checking
319  */
320  if (!msg)
321  continue;
322 
323  msg_length = clib_host_to_net_u32 (vec_len (msg));
324  if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
325  != sizeof (msg_length))
326  {
327  return (-14);
328  }
329 
330  if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
331  {
332  return (-13);
333  }
334  }
335  }
336  return 0;
337 }
338 
339 int
341  u32 nitems)
342 {
343  vl_api_trace_t *tp;
344  int was_on = 0;
345 
346  switch (which)
347  {
348  case VL_API_TRACE_TX:
349  tp = am->tx_trace;
350  if (tp == 0)
351  {
352  vec_validate (am->tx_trace, 0);
353  tp = am->tx_trace;
354  }
355  break;
356 
357  case VL_API_TRACE_RX:
358  tp = am->rx_trace;
359  if (tp == 0)
360  {
361  vec_validate (am->rx_trace, 0);
362  tp = am->rx_trace;
363  }
364 
365  break;
366 
367  default:
368  return -1;
369 
370  }
371 
372  if (tp->enabled)
373  {
374  was_on = vl_msg_api_trace_onoff (am, which, 0);
375  }
376  if (tp->traces)
377  {
378  vl_msg_api_trace_free (am, which);
379  }
380 
381  memset (tp, 0, sizeof (*tp));
382 
384  {
386  }
387  else
388  {
390  }
391 
392  tp->nitems = nitems;
393  if (was_on)
394  {
395  (void) vl_msg_api_trace_onoff (am, which, was_on);
396  }
397  return 0;
398 }
399 
400 always_inline void
402  void *the_msg, int trace_it, int do_it, int free_it)
403 {
404  u16 id = ntohs (*((u16 *) the_msg));
405  u8 *(*print_fp) (void *, void *);
406 
407  if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
408  {
409  if (trace_it)
410  vl_msg_api_trace (am, am->rx_trace, the_msg);
411 
412  if (am->msg_print_flag)
413  {
414  fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
415  print_fp = (void *) am->msg_print_handlers[id];
416  if (print_fp == 0)
417  {
418  fformat (stdout, " [no registered print fn]\n");
419  }
420  else
421  {
422  (*print_fp) (the_msg, stdout);
423  }
424  }
425 
426  if (do_it)
427  {
428  if (!am->is_mp_safe[id])
430  (*am->msg_handlers[id]) (the_msg);
431  if (!am->is_mp_safe[id])
433  }
434  }
435  else
436  {
437  clib_warning ("no handler for msg id %d", id);
438  }
439 
440  if (free_it)
441  vl_msg_api_free (the_msg);
442 }
443 
444 /* set to 1 if you want before/after message handler event logging */
445 #define ELOG_API_MESSAGE_HANDLERS 0
446 
447 #if ELOG_API_MESSAGE_HANDLERS > 0
448 static u32
449 elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
450 {
451  uword *p, r;
452  static uword *h;
453  u8 *name_copy;
454 
455  if (!h)
456  h = hash_create_string (0, sizeof (uword));
457 
458  p = hash_get_mem (h, msg_name);
459  if (p)
460  return p[0];
461  r = elog_string (&vm->elog_main, "%s", msg_name);
462 
463  name_copy = format (0, "%s%c", msg_name, 0);
464 
465  hash_set_mem (h, name_copy, r);
466 
467  return r;
468 }
469 #endif
470 
471 /* This is only to be called from a vlib/vnet app */
472 void
474  void *the_msg, vlib_main_t * vm,
475  vlib_node_runtime_t * node)
476 {
477  u16 id = ntohs (*((u16 *) the_msg));
478  u8 *(*handler) (void *, void *, void *);
479 
480 #if ELOG_API_MESSAGE_HANDLERS > 0
481  {
482  /* *INDENT-OFF* */
483  ELOG_TYPE_DECLARE (e) =
484  {
485  .format = "api-msg: %s",
486  .format_args = "T4",
487  };
488  /* *INDENT-ON* */
489  struct
490  {
491  u32 c;
492  } *ed;
493  ed = ELOG_DATA (&vm->elog_main, e);
494  if (id < vec_len (am->msg_names))
495  ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
496  else
497  ed->c = elog_id_for_msg_name (vm, "BOGUS");
498  }
499 #endif
500 
501  if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
502  {
503  handler = (void *) am->msg_handlers[id];
504 
505  if (am->rx_trace && am->rx_trace->enabled)
506  vl_msg_api_trace (am, am->rx_trace, the_msg);
507 
508  if (!am->is_mp_safe[id])
510  (*handler) (the_msg, vm, node);
511  if (!am->is_mp_safe[id])
513  }
514  else
515  {
516  clib_warning ("no hander for msg id %d", id);
517  }
518 
519  /*
520  * Special-case, so we can e.g. bounce messages off the vnet
521  * main thread without copying them...
522  */
523  if (!(am->message_bounce[id]))
524  vl_msg_api_free (the_msg);
525 
526 #if ELOG_API_MESSAGE_HANDLERS > 0
527  {
528  /* *INDENT-OFF* */
529  ELOG_TYPE_DECLARE (e) = {
530  .format = "api-msg-done: %s",
531  .format_args = "T4",
532  };
533  /* *INDENT-ON* */
534 
535  struct
536  {
537  u32 c;
538  } *ed;
539  ed = ELOG_DATA (&vm->elog_main, e);
540  if (id < vec_len (am->msg_names))
541  ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
542  else
543  ed->c = elog_id_for_msg_name (vm, "BOGUS");
544  }
545 #endif
546 }
547 
548 void
549 vl_msg_api_handler (void *the_msg)
550 {
551  api_main_t *am = &api_main;
552 
553  msg_handler_internal (am, the_msg,
554  (am->rx_trace
555  && am->rx_trace->enabled) /* trace_it */ ,
556  1 /* do_it */ , 1 /* free_it */ );
557 }
558 
559 void
561 {
562  api_main_t *am = &api_main;
563  msg_handler_internal (am, the_msg,
564  (am->rx_trace
565  && am->rx_trace->enabled) /* trace_it */ ,
566  1 /* do_it */ , 0 /* free_it */ );
567 }
568 
569 void
571 {
572  api_main_t *am = &api_main;
573  msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
574  0 /* free_it */ );
575 }
576 
577 /*
578  * Add a trace record to the API message trace buffer, if
579  * API message tracing is enabled. Handy for adding sufficient
580  * data to the trace to reproduce autonomous state, as opposed to
581  * state downloaded via control-plane API messages. Example: the NAT
582  * application creates database entries based on packet traffic, not
583  * control-plane messages.
584  *
585  */
586 void
587 vl_msg_api_trace_only (void *the_msg)
588 {
589  api_main_t *am = &api_main;
590 
591  msg_handler_internal (am, the_msg,
592  (am->rx_trace
593  && am->rx_trace->enabled) /* trace_it */ ,
594  0 /* do_it */ , 0 /* free_it */ );
595 }
596 
597 void
599 {
600  api_main_t *am = &api_main;
601  u16 id = ntohs (*((u16 *) the_msg));
602 
603  if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
604  {
605  clib_warning ("_vl_msg_id too large: %d\n", id);
606  return;
607  }
608  if (am->msg_cleanup_handlers[id])
609  (*am->msg_cleanup_handlers[id]) (the_msg);
610 
611  vl_msg_api_free (the_msg);
612 }
613 
614 /*
615  * vl_msg_api_replay_handler
616  */
617 void
619 {
620  api_main_t *am = &api_main;
621 
622  u16 id = ntohs (*((u16 *) the_msg));
623 
624  if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
625  {
626  clib_warning ("_vl_msg_id too large: %d\n", id);
627  return;
628  }
629  /* do NOT trace the message... */
630  if (am->msg_handlers[id])
631  (*am->msg_handlers[id]) (the_msg);
632  /* do NOT free the message buffer... */
633 }
634 
635 /*
636  * vl_msg_api_socket_handler
637  */
638 void
640 {
641  api_main_t *am = &api_main;
642 
643  msg_handler_internal (am, the_msg,
644  (am->rx_trace
645  && am->rx_trace->enabled) /* trace_it */ ,
646  1 /* do_it */ , 0 /* free_it */ );
647 }
648 
649 #define foreach_msg_api_vector \
650 _(msg_names) \
651 _(msg_handlers) \
652 _(msg_cleanup_handlers) \
653 _(msg_endian_handlers) \
654 _(msg_print_handlers) \
655 _(api_trace_cfg) \
656 _(message_bounce) \
657 _(is_mp_safe)
658 
659 void
661 {
662  api_main_t *am = &api_main;
663 
664  ASSERT (c->id > 0);
665 
666 #define _(a) vec_validate (am->a, c->id);
668 #undef _
669 
670  am->msg_names[c->id] = c->name;
671  am->msg_handlers[c->id] = c->handler;
672  am->msg_cleanup_handlers[c->id] = c->cleanup;
673  am->msg_endian_handlers[c->id] = c->endian;
674  am->msg_print_handlers[c->id] = c->print;
675  am->message_bounce[c->id] = c->message_bounce;
676  am->is_mp_safe[c->id] = c->is_mp_safe;
677 
678  am->api_trace_cfg[c->id].size = c->size;
679  am->api_trace_cfg[c->id].trace_enable = c->traced;
680  am->api_trace_cfg[c->id].replay_enable = c->replay;
681 }
682 
683 /*
684  * vl_msg_api_set_handlers
685  * preserve the old API for a while
686  */
687 void
688 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
689  void *endian, void *print, int size, int traced)
690 {
692  vl_msg_api_msg_config_t *c = &cfg;
693 
694  memset (c, 0, sizeof (*c));
695 
696  c->id = id;
697  c->name = name;
698  c->handler = handler;
699  c->cleanup = cleanup;
700  c->endian = endian;
701  c->print = print;
702  c->traced = traced;
703  c->replay = 1;
704  c->message_bounce = 0;
705  c->is_mp_safe = 0;
706  vl_msg_api_config (c);
707 }
708 
709 void
710 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
711 {
712  api_main_t *am = &api_main;
713  ASSERT (msg_id > 0);
714 
715  vec_validate (am->msg_cleanup_handlers, msg_id);
716  am->msg_cleanup_handlers[msg_id] = fp;
717 }
718 
719 void
721 {
722  uword msg;
723 
724  while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
725  vl_msg_api_handler ((void *) msg);
726 }
727 
730 {
731  switch (which)
732  {
733  case VL_API_TRACE_RX:
734  return am->rx_trace;
735  case VL_API_TRACE_TX:
736  return am->tx_trace;
737  default:
738  return 0;
739  }
740 }
741 
742 void
743 vl_noop_handler (void *mp)
744 {
745 }
746 
747 clib_error_t *
749 {
750  static u8 once;
751  api_main_t *am = &api_main;
752 
753  if (once)
754  return 0;
755 
756  once = 1;
757 
758  am->region_name = "/unset";
759  /*
760  * Eventually passed to fchown, -1 => "current user"
761  * instead of 0 => "root". A very fine disctinction at best.
762  */
763  if (am->api_uid == 0)
764  am->api_uid = -1;
765  if (am->api_gid == 0)
766  am->api_gid = -1;
767 
768  return (0);
769 }
770 
772  __attribute__ ((weak));
773 void
775 {
776 }
777 
779 
780 static void
782  u32 first_index, u32 last_index,
783  vl_api_replay_t which)
784 {
785  vl_api_trace_file_header_t *hp;
786  int i, fd;
787  struct stat statb;
788  size_t file_size;
789  u8 *msg;
790  u8 endian_swap_needed = 0;
791  api_main_t *am = &api_main;
792  u8 *tmpbuf = 0;
793  u32 nitems;
794  void **saved_print_handlers = 0;
795 
796  fd = open ((char *) filename, O_RDONLY);
797 
798  if (fd < 0)
799  {
800  vlib_cli_output (vm, "Couldn't open %s\n", filename);
801  return;
802  }
803 
804  if (fstat (fd, &statb) < 0)
805  {
806  vlib_cli_output (vm, "Couldn't stat %s\n", filename);
807  close (fd);
808  return;
809  }
810 
811  if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
812  {
813  vlib_cli_output (vm, "File not plausible: %s\n", filename);
814  close (fd);
815  return;
816  }
817 
818  file_size = statb.st_size;
819  file_size = (file_size + 4095) & ~(4096);
820 
821  hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
822 
823  if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
824  {
825  vlib_cli_output (vm, "mmap failed: %s\n", filename);
826  close (fd);
827  return;
828  }
829  close (fd);
830 
831  if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
832  || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
833  endian_swap_needed = 1;
834 
835  if (endian_swap_needed)
836  nitems = ntohl (hp->nitems);
837  else
838  nitems = hp->nitems;
839 
840  if (last_index == (u32) ~ 0)
841  {
842  last_index = nitems - 1;
843  }
844 
845  if (first_index >= nitems || last_index >= nitems)
846  {
847  vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
848  first_index, last_index, nitems - 1);
849  munmap (hp, file_size);
850  return;
851  }
852  if (hp->wrapped)
853  vlib_cli_output (vm,
854  "Note: wrapped/incomplete trace, results may vary\n");
855 
856  if (which == CUSTOM_DUMP)
857  {
858  saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
860  }
861 
862 
863  msg = (u8 *) (hp + 1);
864 
865  for (i = 0; i < first_index; i++)
866  {
867  trace_cfg_t *cfgp;
868  int size;
869  u16 msg_id;
870 
871  size = clib_host_to_net_u32 (*(u32 *) msg);
872  msg += sizeof (u32);
873 
875  msg_id = ntohs (*((u16 *) msg));
876  else
877  msg_id = *((u16 *) msg);
878 
879  cfgp = am->api_trace_cfg + msg_id;
880  if (!cfgp)
881  {
882  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
883  munmap (hp, file_size);
884  return;
885  }
886  msg += size;
887  }
888 
889  for (; i <= last_index; i++)
890  {
891  trace_cfg_t *cfgp;
892  u16 *msg_idp;
893  u16 msg_id;
894  int size;
895 
896  if (which == DUMP)
897  vlib_cli_output (vm, "---------- trace %d -----------\n", i);
898 
899  size = clib_host_to_net_u32 (*(u32 *) msg);
900  msg += sizeof (u32);
901 
903  msg_id = ntohs (*((u16 *) msg));
904  else
905  msg_id = *((u16 *) msg);
906 
907  cfgp = am->api_trace_cfg + msg_id;
908  if (!cfgp)
909  {
910  vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
911  munmap (hp, file_size);
912  vec_free (tmpbuf);
913  return;
914  }
915 
916  /* Copy the buffer (from the read-only mmap'ed file) */
917  vec_validate (tmpbuf, size - 1 + sizeof (uword));
918  clib_memcpy (tmpbuf + sizeof (uword), msg, size);
919  memset (tmpbuf, 0xf, sizeof (uword));
920 
921  /*
922  * Endian swap if needed. All msg data is supposed to be
923  * in network byte order. All msg handlers are supposed to
924  * know that. The generic message dumpers don't know that.
925  * One could fix apigen, I suppose.
926  */
927  if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
928  {
929  void (*endian_fp) (void *);
930  if (msg_id >= vec_len (am->msg_endian_handlers)
931  || (am->msg_endian_handlers[msg_id] == 0))
932  {
933  vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
934  munmap (hp, file_size);
935  vec_free (tmpbuf);
936  return;
937  }
938  endian_fp = am->msg_endian_handlers[msg_id];
939  (*endian_fp) (tmpbuf + sizeof (uword));
940  }
941 
942  /* msg_id always in network byte order */
944  {
945  msg_idp = (u16 *) (tmpbuf + sizeof (uword));
946  *msg_idp = msg_id;
947  }
948 
949  switch (which)
950  {
951  case CUSTOM_DUMP:
952  case DUMP:
953  if (msg_id < vec_len (am->msg_print_handlers) &&
954  am->msg_print_handlers[msg_id])
955  {
956  u8 *(*print_fp) (void *, void *);
957 
958  print_fp = (void *) am->msg_print_handlers[msg_id];
959  (*print_fp) (tmpbuf + sizeof (uword), vm);
960  }
961  else
962  {
963  vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
964  msg_id);
965  break;
966  }
967  break;
968 
969  case INITIALIZERS:
970  if (msg_id < vec_len (am->msg_print_handlers) &&
971  am->msg_print_handlers[msg_id])
972  {
973  u8 *s;
974  int j;
975  u8 *(*print_fp) (void *, void *);
976 
977  print_fp = (void *) am->msg_print_handlers[msg_id];
978 
979  vlib_cli_output (vm, "/*");
980 
981  (*print_fp) (tmpbuf + sizeof (uword), vm);
982  vlib_cli_output (vm, "*/\n");
983 
984  s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
985  am->msg_names[msg_id], i,
986  am->api_trace_cfg[msg_id].size);
987 
988  for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
989  {
990  if ((j & 7) == 0)
991  s = format (s, "\n ");
992  s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
993  }
994  s = format (s, "\n};\n%c", 0);
995  vlib_cli_output (vm, (char *) s);
996  vec_free (s);
997  }
998  break;
999 
1000  case REPLAY:
1001  if (msg_id < vec_len (am->msg_print_handlers) &&
1002  am->msg_print_handlers[msg_id] && cfgp->replay_enable)
1003  {
1004  void (*handler) (void *);
1005 
1006  handler = (void *) am->msg_handlers[msg_id];
1007 
1008  if (!am->is_mp_safe[msg_id])
1010  (*handler) (tmpbuf + sizeof (uword));
1011  if (!am->is_mp_safe[msg_id])
1013  }
1014  else
1015  {
1016  if (cfgp->replay_enable)
1017  vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
1018  msg_id);
1019  break;
1020  }
1021  break;
1022  }
1023 
1024  _vec_len (tmpbuf) = 0;
1025  msg += size;
1026  }
1027 
1028  if (saved_print_handlers)
1029  {
1030  clib_memcpy (am->msg_print_handlers, saved_print_handlers,
1031  vec_len (am->msg_print_handlers) * sizeof (void *));
1032  vec_free (saved_print_handlers);
1033  }
1034 
1035  munmap (hp, file_size);
1036  vec_free (tmpbuf);
1037 }
1038 
1039 u8 *
1040 format_vl_msg_api_trace_status (u8 * s, va_list * args)
1041 {
1042  api_main_t *am = va_arg (*args, api_main_t *);
1043  vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1044  vl_api_trace_t *tp;
1045  char *trace_name;
1046 
1047  switch (which)
1048  {
1049  case VL_API_TRACE_TX:
1050  tp = am->tx_trace;
1051  trace_name = "TX trace";
1052  break;
1053 
1054  case VL_API_TRACE_RX:
1055  tp = am->rx_trace;
1056  trace_name = "RX trace";
1057  break;
1058 
1059  default:
1060  abort ();
1061  }
1062 
1063  if (tp == 0)
1064  {
1065  s = format (s, "%s: not yet configured.\n", trace_name);
1066  return s;
1067  }
1068 
1069  s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1070  trace_name, vec_len (tp->traces), tp->nitems,
1071  tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1072  return s;
1073 }
1074 
1076 
1077 static clib_error_t *
1079  unformat_input_t * input, vlib_cli_command_t * cmd)
1080 {
1081  u32 nitems = 256 << 10;
1082  api_main_t *am = &api_main;
1084  u8 *filename;
1085  u32 first = 0;
1086  u32 last = (u32) ~ 0;
1087  FILE *fp;
1088  int rv;
1089 
1090  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1091  {
1092  if (unformat (input, "on") || unformat (input, "enable"))
1093  {
1094  if (unformat (input, "nitems %d", &nitems))
1095  ;
1096  vl_msg_api_trace_configure (am, which, nitems);
1097  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1098  }
1099  else if (unformat (input, "off"))
1100  {
1101  vl_msg_api_trace_onoff (am, which, 0);
1102  }
1103  else if (unformat (input, "save %s", &filename))
1104  {
1105  u8 *chroot_filename;
1106  if (strstr ((char *) filename, "..")
1107  || index ((char *) filename, '/'))
1108  {
1109  vlib_cli_output (vm, "illegal characters in filename '%s'",
1110  filename);
1111  return 0;
1112  }
1113 
1114  chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1115 
1116  vec_free (filename);
1117 
1118  fp = fopen ((char *) chroot_filename, "w");
1119  if (fp == NULL)
1120  {
1121  vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1122  return 0;
1123  }
1124  rv = vl_msg_api_trace_save (am, which, fp);
1125  fclose (fp);
1126  if (rv == -1)
1127  vlib_cli_output (vm, "API Trace data not present\n");
1128  else if (rv == -2)
1129  vlib_cli_output (vm, "File for writing is closed\n");
1130  else if (rv == -10)
1131  vlib_cli_output (vm, "Error while writing header to file\n");
1132  else if (rv == -11)
1133  vlib_cli_output (vm, "Error while writing trace to file\n");
1134  else if (rv == -12)
1135  vlib_cli_output (vm,
1136  "Error while writing end of buffer trace to file\n");
1137  else if (rv == -13)
1138  vlib_cli_output (vm,
1139  "Error while writing start of buffer trace to file\n");
1140  else if (rv < 0)
1141  vlib_cli_output (vm, "Unkown error while saving: %d", rv);
1142  else
1143  vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1144  vec_free (chroot_filename);
1145  }
1146  else if (unformat (input, "dump %s", &filename))
1147  {
1148  vl_msg_api_process_file (vm, filename, first, last, DUMP);
1149  }
1150  else if (unformat (input, "custom-dump %s", &filename))
1151  {
1152  vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1153  }
1154  else if (unformat (input, "replay %s", &filename))
1155  {
1156  vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1157  }
1158  else if (unformat (input, "initializers %s", &filename))
1159  {
1160  vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1161  }
1162  else if (unformat (input, "tx"))
1163  {
1164  which = VL_API_TRACE_TX;
1165  }
1166  else if (unformat (input, "first %d", &first))
1167  {
1168  ;
1169  }
1170  else if (unformat (input, "last %d", &last))
1171  {
1172  ;
1173  }
1174  else if (unformat (input, "status"))
1175  {
1177  am, which);
1178  }
1179  else if (unformat (input, "free"))
1180  {
1181  vl_msg_api_trace_onoff (am, which, 0);
1182  vl_msg_api_trace_free (am, which);
1183  }
1184  else if (unformat (input, "post-mortem-on"))
1186  else if (unformat (input, "post-mortem-off"))
1188  else
1189  return clib_error_return (0, "unknown input `%U'",
1190  format_unformat_error, input);
1191  }
1192  return 0;
1193 }
1194 
1195 /* *INDENT-OFF* */
1196 VLIB_CLI_COMMAND (api_trace_command, static) = {
1197  .path = "api trace",
1198  .short_help =
1199  "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1200  .function = api_trace_command_fn,
1201 };
1202 /* *INDENT-ON* */
1203 
1204 static clib_error_t *
1206 {
1207  u32 nitems = 256 << 10;
1209  api_main_t *am = &api_main;
1210 
1211  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1212  {
1213  if (unformat (input, "on") || unformat (input, "enable"))
1214  {
1215  if (unformat (input, "nitems %d", &nitems))
1216  ;
1217  vl_msg_api_trace_configure (am, which, nitems);
1218  vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1220  }
1221  else
1222  return clib_error_return (0, "unknown input `%U'",
1223  format_unformat_error, input);
1224  }
1225  return 0;
1226 }
1227 
1228 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1229 
1230 void
1232 {
1233  api_main_t *am = &api_main;
1234  FILE *fp;
1235  char filename[64];
1236  int rv;
1237 
1238  if (post_mortem_dump_enabled == 0)
1239  return;
1240 
1241  snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1242  getpid ());
1243 
1244  fp = fopen (filename, "w");
1245  if (fp == NULL)
1246  {
1247  rv = write (2, "Couldn't create ", 16);
1248  rv = write (2, filename, strlen (filename));
1249  rv = write (2, "\n", 1);
1250  return;
1251  }
1252  rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1253  fclose (fp);
1254  if (rv < 0)
1255  {
1256  rv = write (2, "Failed to save post-mortem API trace to ", 40);
1257  rv = write (2, filename, strlen (filename));
1258  rv = write (2, "\n", 1);
1259  }
1260 
1261 }
1262 
1263 /* Layered message handling support */
1264 
1265 void
1266 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1267 {
1268  api_main_t *am = &api_main;
1269 
1270  /* Mild idiot proofing */
1271  if (msg_id_host_byte_order > 10000)
1272  clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1273  msg_id_host_byte_order,
1274  clib_net_to_host_u16 (msg_id_host_byte_order));
1275  vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1276  am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1277 }
1278 
1279 int
1280 vl_msg_api_pd_handler (void *mp, int rv)
1281 {
1282  api_main_t *am = &api_main;
1283  int (*fp) (void *, int);
1284  u16 msg_id;
1285 
1287  msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1288  else
1289  msg_id = *((u16 *) mp);
1290 
1291  if (msg_id >= vec_len (am->pd_msg_handlers)
1292  || am->pd_msg_handlers[msg_id] == 0)
1293  return rv;
1294 
1295  fp = am->pd_msg_handlers[msg_id];
1296  rv = (*fp) (mp, rv);
1297  return rv;
1298 }
1299 
1300 void
1302 {
1303  api_main_t *am = &api_main;
1304 
1305  am->first_available_msg_id = first_avail;
1306 }
1307 
1308 u16
1309 vl_msg_api_get_msg_ids (char *name, int n)
1310 {
1311  api_main_t *am = &api_main;
1312  u8 *name_copy;
1313  vl_api_msg_range_t *rp;
1314  uword *p;
1315  u16 rv;
1316 
1317  if (am->msg_range_by_name == 0)
1318  am->msg_range_by_name = hash_create_string (0, sizeof (uword));
1319 
1320  name_copy = format (0, "%s%c", name, 0);
1321 
1322  p = hash_get_mem (am->msg_range_by_name, name_copy);
1323  if (p)
1324  {
1325  clib_warning ("WARNING: duplicate message range registration for '%s'",
1326  name_copy);
1327  vec_free (name_copy);
1328  return ((u16) ~ 0);
1329  }
1330 
1331  if (n < 0 || n > 1024)
1332  {
1333  clib_warning
1334  ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1335  n, name_copy);
1336  vec_free (name_copy);
1337  return ((u16) ~ 0);
1338  }
1339 
1340  vec_add2 (am->msg_ranges, rp, 1);
1341 
1342  rv = rp->first_msg_id = am->first_available_msg_id;
1343  am->first_available_msg_id += n;
1344  rp->last_msg_id = am->first_available_msg_id - 1;
1345  rp->name = name_copy;
1346 
1347  hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1348 
1349  return rv;
1350 }
1351 
1352 void
1354 {
1355  uword *p;
1356 
1357  if (am->msg_index_by_name_and_crc == 0)
1359 
1360  p = hash_get_mem (am->msg_index_by_name_and_crc, string);
1361  if (p)
1362  {
1363  clib_warning ("attempt to redefine '%s' ignored...", string);
1364  return;
1365  }
1366 
1367  hash_set_mem (am->msg_index_by_name_and_crc, string, id);
1368 }
1369 
1370 
1371 /*
1372  * fd.io coding-style-patch-verification: ON
1373  *
1374  * Local Variables:
1375  * eval: (c-set-style "gnu")
1376  * End:
1377  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
void vl_msg_api_set_first_available_msg_id(u16 first_avail)
Definition: api_shared.c:1301
int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, int onoff)
Definition: api_shared.c:130
int vl_msg_api_trace_save(api_main_t *am, vl_api_trace_which_t which, FILE *fp)
Definition: api_shared.c:209
void vl_msg_api_set_handlers(int id, char *name, void *handler, void *cleanup, void *endian, void *print, int size, int traced)
Definition: api_shared.c:688
int vl_msg_api_trace_free(api_main_t *am, vl_api_trace_which_t which)
Definition: api_shared.c:172
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
char * region_name
Definition: api.h:189
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
void vl_msg_api_set_cleanup_handler(int msg_id, void *fp)
Definition: api_shared.c:710
int vl_msg_api_pd_handler(void *mp, int rv)
Definition: api_shared.c:1280
void vl_msg_api_handler(void *the_msg)
Definition: api_shared.c:549
static u64 do_it(pg_main_t *pg, pg_stream_t *s, u32 *buffers, u32 n_buffers, u32 lo_bit, u32 hi_bit, u64 v_min, u64 v_max, u64 v, pg_edit_type_t edit_type)
Definition: input.c:744
u8 wrapped
Definition: api.h:83
int size
Definition: api.h:71
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define NULL
Definition: clib.h:55
static void msg_handler_internal(api_main_t *am, void *the_msg, int trace_it, int do_it, int free_it)
Definition: api_shared.c:401
u8 * message_bounce
Definition: api.h:123
static u8 post_mortem_dump_enabled
Definition: api_shared.c:1075
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
vl_api_trace_t * vl_msg_api_trace_get(api_main_t *am, vl_api_trace_which_t which)
Definition: api_shared.c:729
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: api_shared.c:781
static heap_elt_t * last(heap_header_t *h)
Definition: heap.c:53
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
static clib_error_t * api_config_fn(vlib_main_t *vm, unformat_input_t *input)
Definition: api_shared.c:1205
int api_uid
Definition: api.h:150
#define hash_set_mem(h, key, value)
Definition: hash.h:274
int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, u32 nitems)
Definition: api_shared.c:340
void(** msg_cleanup_handlers)(void *)
Definition: api.h:119
int api_gid
Definition: api.h:152
void vl_noop_handler(void *mp)
Definition: api_shared.c:743
trace_cfg_t * api_trace_cfg
Definition: api.h:131
void vl_msg_api_handler_no_trace_no_free(void *the_msg)
Definition: api_shared.c:570
void vl_msg_api_add_msg_name_crc(api_main_t *am, char *string, u32 id)
Definition: api_shared.c:1353
clib_error_t * vl_api_init(vlib_main_t *vm)
Definition: api_shared.c:748
void vl_msg_api_cleanup_handler(void *the_msg)
Definition: api_shared.c:598
vl_api_trace_t * rx_trace
Definition: api.h:128
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
#define always_inline
Definition: clib.h:84
void vl_msg_api_config(vl_msg_api_msg_config_t *c)
Definition: api_shared.c:660
void vl_msg_api_free(void *)
#define clib_arch_is_little_endian
Definition: byte_order.h:54
static clib_error_t * api_trace_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: api_shared.c:1078
#define clib_warning(format, args...)
Definition: error.h:59
int vl_msg_api_tx_trace_enabled(api_main_t *am)
Definition: api_shared.c:75
void vl_msg_api_trace_only(void *the_msg)
Definition: api_shared.c:587
#define hash_create_string(elts, value_bytes)
Definition: hash.h:652
void vl_msg_api_queue_handler(unix_shared_memory_queue_t *q)
Definition: api_shared.c:720
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:473
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
u16 last_msg_id
Definition: api.h:112
int vl_msg_api_rx_trace_enabled(api_main_t *am)
Definition: api_shared.c:69
void(** msg_print_handlers)(void *, void *)
Definition: api.h:121
int replay_enable
Definition: api.h:73
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:334
u32 curindex
Definition: api.h:86
#define ELOG_DATA(em, f)
Definition: elog.h:392
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:118
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
u8 * format_vl_msg_api_trace_status(u8 *s, va_list *args)
Definition: api_shared.c:1040
u8 enabled
Definition: api.h:82
#define clib_arch_is_big_endian
Definition: byte_order.h:53
int unix_shared_memory_queue_sub(unix_shared_memory_queue_t *q, u8 *elem, int nowait)
svmdb_client_t * c
#define VL_API_LITTLE_ENDIAN
Definition: api.h:105
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:49
vl_api_msg_range_t * msg_ranges
Definition: api.h:147
void vl_msg_api_post_mortem_dump(void)
Definition: api_shared.c:1231
#define clib_memcpy(a, b, c)
Definition: string.h:69
elog_main_t elog_main
Definition: main.h:141
u8 ** traces
Definition: api.h:87
vl_api_replay_t
Definition: api_shared.c:60
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:350
vl_api_trace_which_t
Definition: api.h:99
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
void vl_msg_api_socket_handler(void *the_msg)
Definition: api_shared.c:639
api_main_t api_main
Definition: api_shared.c:39
vl_api_trace_t * tx_trace
Definition: api.h:129
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static u32 elog_id_for_msg_name(mc_main_t *m, char *msg_name)
Definition: mc.c:46
u32 data_len
Definition: api.h:214
Definition: api.h:211
u64 size
Definition: vhost-user.h:74
#define VL_API_BIG_ENDIAN
Definition: api.h:106
void vl_msg_api_replay_handler(void *the_msg)
Definition: api_shared.c:618
char ** msg_names
Definition: api.h:122
void vl_msg_api_handler_no_free(void *the_msg)
Definition: api_shared.c:560
u64 uword
Definition: types.h:112
u32 missing_clients
Definition: api.h:127
void vl_msg_api_increment_missing_client_counter(void)
Definition: api_shared.c:54
unsigned short u16
Definition: types.h:57
u16 first_msg_id
Definition: api.h:111
void vl_msg_api_register_pd_handler(void *fp, u16 msg_id_host_byte_order)
Definition: api_shared.c:1266
void(** msg_endian_handlers)(void *)
Definition: api.h:120
u32 elog_string(elog_main_t *em, char *fmt,...)
Definition: elog.c:525
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
int(** pd_msg_handlers)(void *, int)
Definition: api.h:118
word fformat(FILE *f, char *fmt,...)
Definition: format.c:452
#define foreach_msg_api_vector
Definition: api_shared.c:649
#define hash_get_mem(h, key)
Definition: hash.h:268
u16 first_available_msg_id
Definition: api.h:141
u8 endian
Definition: api.h:81
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
void(** msg_handlers)(void *)
Definition: api.h:117
u8 * is_mp_safe
Definition: api.h:124
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
void vl_msg_api_trace(api_main_t *am, vl_api_trace_t *tp, void *msg)
Definition: api_shared.c:84
int trace_enable
Definition: api.h:72
int msg_print_flag
Definition: api.h:130
u16 vl_msg_api_get_msg_ids(char *name, int n)
Definition: api_shared.c:1309
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
uword * msg_index_by_name_and_crc
Definition: api.h:187
uword * msg_range_by_name
Definition: api.h:144
u32 nitems
Definition: api.h:85
struct _unix_shared_memory_queue unix_shared_memory_queue_t
void vl_msg_api_custom_dump_configure(api_main_t *am)
Definition: api_shared.c:774
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:43