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