2 *------------------------------------------------------------------
3 * api_shared.c - API message handling, common code for both clients
4 * and the vlib process itself.
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:
12 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
26 #include <sys/types.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>
41 void vl_msg_api_barrier_sync (void) __attribute__ ((weak));
43 vl_msg_api_barrier_sync (void)
47 void vl_msg_api_barrier_release (void) __attribute__ ((weak));
49 vl_msg_api_barrier_release (void)
54 vl_msg_api_increment_missing_client_counter (void)
56 api_main_t *am = &api_main;
57 am->missing_clients++;
69 vl_msg_api_rx_trace_enabled (api_main_t * am)
71 return (am->rx_trace && am->rx_trace->enabled);
75 vl_msg_api_tx_trace_enabled (api_main_t * am)
77 return (am->tx_trace && am->tx_trace->enabled);
84 vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg)
91 u16 msg_id = ntohs (*((u16 *) msg));
92 msgbuf_t *header = (msgbuf_t *) (((u8 *) msg) - offsetof (msgbuf_t, data));
94 cfgp = am->api_trace_cfg + msg_id;
96 if (!cfgp || !cfgp->trace_enable)
103 clib_warning ("tp->nitems is 0");
107 if (vec_len (tp->traces) < tp->nitems)
109 vec_add1 (tp->traces, 0);
110 this_trace = tp->traces + vec_len (tp->traces) - 1;
115 old_trace = tp->traces + tp->curindex++;
116 if (tp->curindex == tp->nitems)
118 vec_free (*old_trace);
119 this_trace = old_trace;
122 length = clib_net_to_host_u32 (header->data_len);
124 vec_validate (msg_copy, length - 1);
125 clib_memcpy (msg_copy, msg, length);
126 *this_trace = msg_copy;
130 vl_msg_api_trace_onoff (api_main_t * am, vl_api_trace_which_t which,
138 case VL_API_TRACE_TX:
142 vl_msg_api_trace_configure (am, which, 1024);
147 case VL_API_TRACE_RX:
151 vl_msg_api_trace_configure (am, which, 1024);
162 if (tp == 0 || tp->nitems == 0)
172 vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which)
179 case VL_API_TRACE_TX:
183 case VL_API_TRACE_RX:
193 if (!tp || tp->nitems == 0)
199 for (i = 0; i < vec_len (tp->traces); i++)
201 vec_free (tp->traces[i]);
203 vec_free (tp->traces);
209 vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp)
212 vl_api_trace_file_header_t fh;
218 case VL_API_TRACE_TX:
222 case VL_API_TRACE_RX:
231 /* Configured, data present? */
232 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
235 /* "Dare to be stupid" check */
241 /* Write the file header */
242 fh.nitems = vec_len (tp->traces);
243 fh.endian = tp->endian;
244 fh.wrapped = tp->wrapped;
246 if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
252 if (tp->wrapped == 0)
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.
260 for (i = 0; i < vec_len (tp->traces); i++)
263 /*sa_ignore NO_NULL_CHK */
266 * This retarded check required to pass
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))
278 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
286 /* Wrap case: write oldest -> end of buffer */
287 for (i = tp->curindex; i < vec_len (tp->traces); i++)
292 * This retarded check required to pass
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))
305 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
310 /* write beginning of buffer -> oldest-1 */
311 for (i = 0; i < tp->curindex; i++)
314 /*sa_ignore NO_NULL_CHK */
317 * This retarded check required to pass
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))
330 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
340 vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
348 case VL_API_TRACE_TX:
352 vec_validate (am->tx_trace, 0);
357 case VL_API_TRACE_RX:
361 vec_validate (am->rx_trace, 0);
374 was_on = vl_msg_api_trace_onoff (am, which, 0);
378 vl_msg_api_trace_free (am, which);
381 memset (tp, 0, sizeof (*tp));
383 if (clib_arch_is_big_endian)
385 tp->endian = VL_API_BIG_ENDIAN;
389 tp->endian = VL_API_LITTLE_ENDIAN;
395 (void) vl_msg_api_trace_onoff (am, which, was_on);
401 msg_handler_internal (api_main_t * am,
402 void *the_msg, int trace_it, int do_it, int free_it)
404 u16 id = ntohs (*((u16 *) the_msg));
405 u8 *(*print_fp) (void *, void *);
407 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
410 vl_msg_api_trace (am, am->rx_trace, the_msg);
412 if (am->msg_print_flag)
414 fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
415 print_fp = (void *) am->msg_print_handlers[id];
418 fformat (stdout, " [no registered print fn]\n");
422 (*print_fp) (the_msg, stdout);
428 if (!am->is_mp_safe[id])
429 vl_msg_api_barrier_sync ();
430 (*am->msg_handlers[id]) (the_msg);
431 if (!am->is_mp_safe[id])
432 vl_msg_api_barrier_release ();
437 clib_warning ("no handler for msg id %d", id);
441 vl_msg_api_free (the_msg);
444 /* set to 1 if you want before/after message handler event logging */
445 #define ELOG_API_MESSAGE_HANDLERS 0
447 #if ELOG_API_MESSAGE_HANDLERS > 0
449 elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
456 h = hash_create_string (0, sizeof (uword));
458 p = hash_get_mem (h, msg_name);
461 r = elog_string (&vm->elog_main, "%s", msg_name);
463 name_copy = format (0, "%s%c", msg_name, 0);
465 hash_set_mem (h, name_copy, r);
471 /* This is only to be called from a vlib/vnet app */
473 vl_msg_api_handler_with_vm_node (api_main_t * am,
474 void *the_msg, vlib_main_t * vm,
475 vlib_node_runtime_t * node)
477 u16 id = ntohs (*((u16 *) the_msg));
478 u8 *(*handler) (void *, void *, void *);
480 #if ELOG_API_MESSAGE_HANDLERS > 0
483 ELOG_TYPE_DECLARE (e) =
485 .format = "api-msg: %s",
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]);
497 ed->c = elog_id_for_msg_name (vm, "BOGUS");
501 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
503 handler = (void *) am->msg_handlers[id];
505 if (am->rx_trace && am->rx_trace->enabled)
506 vl_msg_api_trace (am, am->rx_trace, the_msg);
508 if (!am->is_mp_safe[id])
509 vl_msg_api_barrier_sync ();
510 (*handler) (the_msg, vm, node);
511 if (!am->is_mp_safe[id])
512 vl_msg_api_barrier_release ();
516 clib_warning ("no hander for msg id %d", id);
520 * Special-case, so we can e.g. bounce messages off the vnet
521 * main thread without copying them...
523 if (!(am->message_bounce[id]))
524 vl_msg_api_free (the_msg);
526 #if ELOG_API_MESSAGE_HANDLERS > 0
529 ELOG_TYPE_DECLARE (e) = {
530 .format = "api-msg-done: %s",
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]);
543 ed->c = elog_id_for_msg_name (vm, "BOGUS");
549 vl_msg_api_handler (void *the_msg)
551 api_main_t *am = &api_main;
553 msg_handler_internal (am, the_msg,
555 && am->rx_trace->enabled) /* trace_it */ ,
556 1 /* do_it */ , 1 /* free_it */ );
560 vl_msg_api_handler_no_free (void *the_msg)
562 api_main_t *am = &api_main;
563 msg_handler_internal (am, the_msg,
565 && am->rx_trace->enabled) /* trace_it */ ,
566 1 /* do_it */ , 0 /* free_it */ );
570 vl_msg_api_handler_no_trace_no_free (void *the_msg)
572 api_main_t *am = &api_main;
573 msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
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.
587 vl_msg_api_trace_only (void *the_msg)
589 api_main_t *am = &api_main;
591 msg_handler_internal (am, the_msg,
593 && am->rx_trace->enabled) /* trace_it */ ,
594 0 /* do_it */ , 0 /* free_it */ );
598 vl_msg_api_cleanup_handler (void *the_msg)
600 api_main_t *am = &api_main;
601 u16 id = ntohs (*((u16 *) the_msg));
603 if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
605 clib_warning ("_vl_msg_id too large: %d\n", id);
608 if (am->msg_cleanup_handlers[id])
609 (*am->msg_cleanup_handlers[id]) (the_msg);
611 vl_msg_api_free (the_msg);
615 * vl_msg_api_replay_handler
618 vl_msg_api_replay_handler (void *the_msg)
620 api_main_t *am = &api_main;
622 u16 id = ntohs (*((u16 *) the_msg));
624 if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
626 clib_warning ("_vl_msg_id too large: %d\n", id);
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... */
636 * vl_msg_api_socket_handler
639 vl_msg_api_socket_handler (void *the_msg)
641 api_main_t *am = &api_main;
643 msg_handler_internal (am, the_msg,
645 && am->rx_trace->enabled) /* trace_it */ ,
646 1 /* do_it */ , 0 /* free_it */ );
649 #define foreach_msg_api_vector \
652 _(msg_cleanup_handlers) \
653 _(msg_endian_handlers) \
654 _(msg_print_handlers) \
660 vl_msg_api_config (vl_msg_api_msg_config_t * c)
662 api_main_t *am = &api_main;
666 #define _(a) vec_validate (am->a, c->id);
667 foreach_msg_api_vector;
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;
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;
684 * vl_msg_api_set_handlers
685 * preserve the old API for a while
688 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
689 void *endian, void *print, int size, int traced)
691 vl_msg_api_msg_config_t cfg;
692 vl_msg_api_msg_config_t *c = &cfg;
696 c->handler = handler;
697 c->cleanup = cleanup;
702 c->message_bounce = 0;
704 vl_msg_api_config (c);
708 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
710 api_main_t *am = &api_main;
713 vec_validate (am->msg_cleanup_handlers, msg_id);
714 am->msg_cleanup_handlers[msg_id] = fp;
718 vl_msg_api_queue_handler (unix_shared_memory_queue_t * q)
722 while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
723 vl_msg_api_handler ((void *) msg);
727 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
731 case VL_API_TRACE_RX:
733 case VL_API_TRACE_TX:
741 vl_noop_handler (void *mp)
746 vl_api_init (vlib_main_t * vm)
749 api_main_t *am = &api_main;
756 am->region_name = "/unset";
758 * Eventually passed to fchown, -1 => "current user"
759 * instead of 0 => "root". A very fine disctinction at best.
761 if (am->api_uid == 0)
763 if (am->api_gid == 0)
769 void vl_msg_api_custom_dump_configure (api_main_t * am)
770 __attribute__ ((weak));
772 vl_msg_api_custom_dump_configure (api_main_t * am)
776 VLIB_INIT_FUNCTION (vl_api_init);
779 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
780 u32 first_index, u32 last_index,
781 vl_api_replay_t which)
783 vl_api_trace_file_header_t *hp;
788 u8 endian_swap_needed = 0;
789 api_main_t *am = &api_main;
792 void **saved_print_handlers = 0;
794 fd = open ((char *) filename, O_RDONLY);
798 vlib_cli_output (vm, "Couldn't open %s\n", filename);
802 if (fstat (fd, &statb) < 0)
804 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
809 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
811 vlib_cli_output (vm, "File not plausible: %s\n", filename);
816 file_size = statb.st_size;
817 file_size = (file_size + 4095) & ~(4096);
819 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
821 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
823 vlib_cli_output (vm, "mmap failed: %s\n", filename);
829 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
830 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
831 endian_swap_needed = 1;
833 if (endian_swap_needed)
834 nitems = ntohl (hp->nitems);
838 if (last_index == (u32) ~ 0)
840 last_index = nitems - 1;
843 if (first_index >= nitems || last_index >= nitems)
845 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
846 first_index, last_index, nitems - 1);
847 munmap (hp, file_size);
852 "Note: wrapped/incomplete trace, results may vary\n");
854 if (which == CUSTOM_DUMP)
856 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
857 vl_msg_api_custom_dump_configure (am);
861 msg = (u8 *) (hp + 1);
863 for (i = 0; i < first_index; i++)
869 size = clib_host_to_net_u32 (*(u32 *) msg);
872 if (clib_arch_is_little_endian)
873 msg_id = ntohs (*((u16 *) msg));
875 msg_id = *((u16 *) msg);
877 cfgp = am->api_trace_cfg + msg_id;
880 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
881 munmap (hp, file_size);
887 for (; i <= last_index; i++)
895 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
897 size = clib_host_to_net_u32 (*(u32 *) msg);
900 if (clib_arch_is_little_endian)
901 msg_id = ntohs (*((u16 *) msg));
903 msg_id = *((u16 *) msg);
905 cfgp = am->api_trace_cfg + msg_id;
908 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
909 munmap (hp, file_size);
914 /* Copy the buffer (from the read-only mmap'ed file) */
915 vec_validate (tmpbuf, size - 1 + sizeof (uword));
916 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
917 memset (tmpbuf, 0xf, sizeof (uword));
920 * Endian swap if needed. All msg data is supposed to be
921 * in network byte order. All msg handlers are supposed to
922 * know that. The generic message dumpers don't know that.
923 * One could fix apigen, I suppose.
925 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
927 void (*endian_fp) (void *);
928 if (msg_id >= vec_len (am->msg_endian_handlers)
929 || (am->msg_endian_handlers[msg_id] == 0))
931 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
932 munmap (hp, file_size);
936 endian_fp = am->msg_endian_handlers[msg_id];
937 (*endian_fp) (tmpbuf + sizeof (uword));
940 /* msg_id always in network byte order */
941 if (clib_arch_is_little_endian)
943 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
951 if (msg_id < vec_len (am->msg_print_handlers) &&
952 am->msg_print_handlers[msg_id])
954 u8 *(*print_fp) (void *, void *);
956 print_fp = (void *) am->msg_print_handlers[msg_id];
957 (*print_fp) (tmpbuf + sizeof (uword), vm);
961 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
968 if (msg_id < vec_len (am->msg_print_handlers) &&
969 am->msg_print_handlers[msg_id])
973 u8 *(*print_fp) (void *, void *);
975 print_fp = (void *) am->msg_print_handlers[msg_id];
977 vlib_cli_output (vm, "/*");
979 (*print_fp) (tmpbuf + sizeof (uword), vm);
980 vlib_cli_output (vm, "*/\n");
982 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
983 am->msg_names[msg_id], i,
984 am->api_trace_cfg[msg_id].size);
986 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
989 s = format (s, "\n ");
990 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
992 s = format (s, "\n};\n%c", 0);
993 vlib_cli_output (vm, (char *) s);
999 if (msg_id < vec_len (am->msg_print_handlers) &&
1000 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
1002 void (*handler) (void *);
1004 handler = (void *) am->msg_handlers[msg_id];
1006 if (!am->is_mp_safe[msg_id])
1007 vl_msg_api_barrier_sync ();
1008 (*handler) (tmpbuf + sizeof (uword));
1009 if (!am->is_mp_safe[msg_id])
1010 vl_msg_api_barrier_release ();
1014 if (cfgp->replay_enable)
1015 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
1022 _vec_len (tmpbuf) = 0;
1026 if (saved_print_handlers)
1028 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
1029 vec_len (am->msg_print_handlers) * sizeof (void *));
1030 vec_free (saved_print_handlers);
1033 munmap (hp, file_size);
1038 format_vl_msg_api_trace_status (u8 * s, va_list * args)
1040 api_main_t *am = va_arg (*args, api_main_t *);
1041 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1047 case VL_API_TRACE_TX:
1049 trace_name = "TX trace";
1052 case VL_API_TRACE_RX:
1054 trace_name = "RX trace";
1063 s = format (s, "%s: not yet configured.\n", trace_name);
1067 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1068 trace_name, vec_len (tp->traces), tp->nitems,
1069 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1073 static u8 post_mortem_dump_enabled;
1075 static clib_error_t *
1076 api_trace_command_fn (vlib_main_t * vm,
1077 unformat_input_t * input, vlib_cli_command_t * cmd)
1079 u32 nitems = 256 << 10;
1080 api_main_t *am = &api_main;
1081 vl_api_trace_which_t which = VL_API_TRACE_RX;
1084 u32 last = (u32) ~ 0;
1088 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1090 if (unformat (input, "on") || unformat (input, "enable"))
1092 if (unformat (input, "nitems %d", &nitems))
1094 vl_msg_api_trace_configure (am, which, nitems);
1095 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1097 else if (unformat (input, "off"))
1099 vl_msg_api_trace_onoff (am, which, 0);
1101 else if (unformat (input, "save %s", &filename))
1103 u8 *chroot_filename;
1104 if (strstr ((char *) filename, "..")
1105 || index ((char *) filename, '/'))
1107 vlib_cli_output (vm, "illegal characters in filename '%s'",
1112 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1114 vec_free (filename);
1116 fp = fopen ((char *) chroot_filename, "w");
1119 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1122 rv = vl_msg_api_trace_save (am, which, fp);
1125 vlib_cli_output (vm, "API Trace data not present\n");
1127 vlib_cli_output (vm, "File for writing is closed\n");
1129 vlib_cli_output (vm, "Error while writing header to file\n");
1131 vlib_cli_output (vm, "Error while writing trace to file\n");
1133 vlib_cli_output (vm,
1134 "Error while writing end of buffer trace to file\n");
1136 vlib_cli_output (vm,
1137 "Error while writing start of buffer trace to file\n");
1139 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
1141 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1142 vec_free (chroot_filename);
1144 else if (unformat (input, "dump %s", &filename))
1146 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1148 else if (unformat (input, "custom-dump %s", &filename))
1150 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1152 else if (unformat (input, "replay %s", &filename))
1154 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1156 else if (unformat (input, "initializers %s", &filename))
1158 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1160 else if (unformat (input, "tx"))
1162 which = VL_API_TRACE_TX;
1164 else if (unformat (input, "first %d", &first))
1168 else if (unformat (input, "last %d", &last))
1172 else if (unformat (input, "status"))
1174 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1177 else if (unformat (input, "free"))
1179 vl_msg_api_trace_onoff (am, which, 0);
1180 vl_msg_api_trace_free (am, which);
1182 else if (unformat (input, "post-mortem-on"))
1183 post_mortem_dump_enabled = 1;
1184 else if (unformat (input, "post-mortem-off"))
1185 post_mortem_dump_enabled = 0;
1187 return clib_error_return (0, "unknown input `%U'",
1188 format_unformat_error, input);
1194 VLIB_CLI_COMMAND (api_trace_command, static) = {
1195 .path = "api trace",
1197 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1198 .function = api_trace_command_fn,
1202 static clib_error_t *
1203 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1205 u32 nitems = 256 << 10;
1206 vl_api_trace_which_t which = VL_API_TRACE_RX;
1207 api_main_t *am = &api_main;
1209 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1211 if (unformat (input, "on") || unformat (input, "enable"))
1213 if (unformat (input, "nitems %d", &nitems))
1215 vl_msg_api_trace_configure (am, which, nitems);
1216 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1217 post_mortem_dump_enabled = 1;
1220 return clib_error_return (0, "unknown input `%U'",
1221 format_unformat_error, input);
1226 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1229 vl_msg_api_post_mortem_dump (void)
1231 api_main_t *am = &api_main;
1236 if (post_mortem_dump_enabled == 0)
1239 snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1242 fp = fopen (filename, "w");
1245 rv = write (2, "Couldn't create ", 16);
1246 rv = write (2, filename, strlen (filename));
1247 rv = write (2, "\n", 1);
1250 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1254 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1255 rv = write (2, filename, strlen (filename));
1256 rv = write (2, "\n", 1);
1261 /* Layered message handling support */
1264 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1266 api_main_t *am = &api_main;
1268 /* Mild idiot proofing */
1269 if (msg_id_host_byte_order > 10000)
1270 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1271 msg_id_host_byte_order,
1272 clib_net_to_host_u16 (msg_id_host_byte_order));
1273 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1274 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1278 vl_msg_api_pd_handler (void *mp, int rv)
1280 api_main_t *am = &api_main;
1281 int (*fp) (void *, int);
1284 if (clib_arch_is_little_endian)
1285 msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1287 msg_id = *((u16 *) mp);
1289 if (msg_id >= vec_len (am->pd_msg_handlers)
1290 || am->pd_msg_handlers[msg_id] == 0)
1293 fp = am->pd_msg_handlers[msg_id];
1294 rv = (*fp) (mp, rv);
1299 vl_msg_api_set_first_available_msg_id (u16 first_avail)
1301 api_main_t *am = &api_main;
1303 am->first_available_msg_id = first_avail;
1307 vl_msg_api_get_msg_ids (char *name, int n)
1309 api_main_t *am = &api_main;
1311 vl_api_msg_range_t *rp;
1315 if (am->msg_range_by_name == 0)
1316 am->msg_range_by_name = hash_create_string (0, sizeof (uword));
1318 name_copy = format (0, "%s%c", name, 0);
1320 p = hash_get_mem (am->msg_range_by_name, name_copy);
1323 clib_warning ("WARNING: duplicate message range registration for '%s'",
1325 vec_free (name_copy);
1329 if (n < 0 || n > 1024)
1332 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1334 vec_free (name_copy);
1338 vec_add2 (am->msg_ranges, rp, 1);
1340 rv = rp->first_msg_id = am->first_available_msg_id;
1341 am->first_available_msg_id += n;
1342 rp->last_msg_id = am->first_available_msg_id - 1;
1343 rp->name = name_copy;
1345 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1351 vl_msg_api_add_msg_name_crc (api_main_t * am, char *string, u32 id)
1355 if (am->msg_index_by_name_and_crc == 0)
1356 am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
1358 p = hash_get_mem (am->msg_index_by_name_and_crc, string);
1361 clib_warning ("attempt to redefine '%s' ignored...", string);
1365 hash_set_mem (am->msg_index_by_name_and_crc, string, id);
1370 * fd.io coding-style-patch-verification: ON
1373 * eval: (c-set-style "gnu")