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