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;
694 memset (c, 0, sizeof (*c));
698 c->handler = handler;
699 c->cleanup = cleanup;
704 c->message_bounce = 0;
706 vl_msg_api_config (c);
710 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
712 api_main_t *am = &api_main;
715 vec_validate (am->msg_cleanup_handlers, msg_id);
716 am->msg_cleanup_handlers[msg_id] = fp;
720 vl_msg_api_queue_handler (unix_shared_memory_queue_t * q)
724 while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
725 vl_msg_api_handler ((void *) msg);
729 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
733 case VL_API_TRACE_RX:
735 case VL_API_TRACE_TX:
743 vl_noop_handler (void *mp)
748 vl_api_init (vlib_main_t * vm)
751 api_main_t *am = &api_main;
758 am->region_name = "/unset";
760 * Eventually passed to fchown, -1 => "current user"
761 * instead of 0 => "root". A very fine disctinction at best.
763 if (am->api_uid == 0)
765 if (am->api_gid == 0)
771 void vl_msg_api_custom_dump_configure (api_main_t * am)
772 __attribute__ ((weak));
774 vl_msg_api_custom_dump_configure (api_main_t * am)
778 VLIB_INIT_FUNCTION (vl_api_init);
781 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
782 u32 first_index, u32 last_index,
783 vl_api_replay_t which)
785 vl_api_trace_file_header_t *hp;
790 u8 endian_swap_needed = 0;
791 api_main_t *am = &api_main;
794 void **saved_print_handlers = 0;
796 fd = open ((char *) filename, O_RDONLY);
800 vlib_cli_output (vm, "Couldn't open %s\n", filename);
804 if (fstat (fd, &statb) < 0)
806 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
811 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
813 vlib_cli_output (vm, "File not plausible: %s\n", filename);
818 file_size = statb.st_size;
819 file_size = (file_size + 4095) & ~(4096);
821 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
823 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
825 vlib_cli_output (vm, "mmap failed: %s\n", filename);
831 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
832 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
833 endian_swap_needed = 1;
835 if (endian_swap_needed)
836 nitems = ntohl (hp->nitems);
840 if (last_index == (u32) ~ 0)
842 last_index = nitems - 1;
845 if (first_index >= nitems || last_index >= nitems)
847 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
848 first_index, last_index, nitems - 1);
849 munmap (hp, file_size);
854 "Note: wrapped/incomplete trace, results may vary\n");
856 if (which == CUSTOM_DUMP)
858 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
859 vl_msg_api_custom_dump_configure (am);
863 msg = (u8 *) (hp + 1);
865 for (i = 0; i < first_index; i++)
871 size = clib_host_to_net_u32 (*(u32 *) msg);
874 if (clib_arch_is_little_endian)
875 msg_id = ntohs (*((u16 *) msg));
877 msg_id = *((u16 *) msg);
879 cfgp = am->api_trace_cfg + msg_id;
882 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
883 munmap (hp, file_size);
889 for (; i <= last_index; i++)
897 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
899 size = clib_host_to_net_u32 (*(u32 *) msg);
902 if (clib_arch_is_little_endian)
903 msg_id = ntohs (*((u16 *) msg));
905 msg_id = *((u16 *) msg);
907 cfgp = am->api_trace_cfg + msg_id;
910 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
911 munmap (hp, file_size);
916 /* Copy the buffer (from the read-only mmap'ed file) */
917 vec_validate (tmpbuf, size - 1 + sizeof (uword));
918 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
919 memset (tmpbuf, 0xf, sizeof (uword));
922 * Endian swap if needed. All msg data is supposed to be
923 * in network byte order. All msg handlers are supposed to
924 * know that. The generic message dumpers don't know that.
925 * One could fix apigen, I suppose.
927 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
929 void (*endian_fp) (void *);
930 if (msg_id >= vec_len (am->msg_endian_handlers)
931 || (am->msg_endian_handlers[msg_id] == 0))
933 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
934 munmap (hp, file_size);
938 endian_fp = am->msg_endian_handlers[msg_id];
939 (*endian_fp) (tmpbuf + sizeof (uword));
942 /* msg_id always in network byte order */
943 if (clib_arch_is_little_endian)
945 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
953 if (msg_id < vec_len (am->msg_print_handlers) &&
954 am->msg_print_handlers[msg_id])
956 u8 *(*print_fp) (void *, void *);
958 print_fp = (void *) am->msg_print_handlers[msg_id];
959 (*print_fp) (tmpbuf + sizeof (uword), vm);
963 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
970 if (msg_id < vec_len (am->msg_print_handlers) &&
971 am->msg_print_handlers[msg_id])
975 u8 *(*print_fp) (void *, void *);
977 print_fp = (void *) am->msg_print_handlers[msg_id];
979 vlib_cli_output (vm, "/*");
981 (*print_fp) (tmpbuf + sizeof (uword), vm);
982 vlib_cli_output (vm, "*/\n");
984 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
985 am->msg_names[msg_id], i,
986 am->api_trace_cfg[msg_id].size);
988 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
991 s = format (s, "\n ");
992 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
994 s = format (s, "\n};\n%c", 0);
995 vlib_cli_output (vm, (char *) s);
1001 if (msg_id < vec_len (am->msg_print_handlers) &&
1002 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
1004 void (*handler) (void *);
1006 handler = (void *) am->msg_handlers[msg_id];
1008 if (!am->is_mp_safe[msg_id])
1009 vl_msg_api_barrier_sync ();
1010 (*handler) (tmpbuf + sizeof (uword));
1011 if (!am->is_mp_safe[msg_id])
1012 vl_msg_api_barrier_release ();
1016 if (cfgp->replay_enable)
1017 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
1024 _vec_len (tmpbuf) = 0;
1028 if (saved_print_handlers)
1030 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
1031 vec_len (am->msg_print_handlers) * sizeof (void *));
1032 vec_free (saved_print_handlers);
1035 munmap (hp, file_size);
1040 format_vl_msg_api_trace_status (u8 * s, va_list * args)
1042 api_main_t *am = va_arg (*args, api_main_t *);
1043 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1049 case VL_API_TRACE_TX:
1051 trace_name = "TX trace";
1054 case VL_API_TRACE_RX:
1056 trace_name = "RX trace";
1065 s = format (s, "%s: not yet configured.\n", trace_name);
1069 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1070 trace_name, vec_len (tp->traces), tp->nitems,
1071 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1075 static u8 post_mortem_dump_enabled;
1077 static clib_error_t *
1078 api_trace_command_fn (vlib_main_t * vm,
1079 unformat_input_t * input, vlib_cli_command_t * cmd)
1081 u32 nitems = 256 << 10;
1082 api_main_t *am = &api_main;
1083 vl_api_trace_which_t which = VL_API_TRACE_RX;
1086 u32 last = (u32) ~ 0;
1090 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1092 if (unformat (input, "on") || unformat (input, "enable"))
1094 if (unformat (input, "nitems %d", &nitems))
1096 vl_msg_api_trace_configure (am, which, nitems);
1097 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1099 else if (unformat (input, "off"))
1101 vl_msg_api_trace_onoff (am, which, 0);
1103 else if (unformat (input, "save %s", &filename))
1105 u8 *chroot_filename;
1106 if (strstr ((char *) filename, "..")
1107 || index ((char *) filename, '/'))
1109 vlib_cli_output (vm, "illegal characters in filename '%s'",
1114 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1116 vec_free (filename);
1118 fp = fopen ((char *) chroot_filename, "w");
1121 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1124 rv = vl_msg_api_trace_save (am, which, fp);
1127 vlib_cli_output (vm, "API Trace data not present\n");
1129 vlib_cli_output (vm, "File for writing is closed\n");
1131 vlib_cli_output (vm, "Error while writing header to file\n");
1133 vlib_cli_output (vm, "Error while writing trace to file\n");
1135 vlib_cli_output (vm,
1136 "Error while writing end of buffer trace to file\n");
1138 vlib_cli_output (vm,
1139 "Error while writing start of buffer trace to file\n");
1141 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
1143 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1144 vec_free (chroot_filename);
1146 else if (unformat (input, "dump %s", &filename))
1148 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1150 else if (unformat (input, "custom-dump %s", &filename))
1152 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1154 else if (unformat (input, "replay %s", &filename))
1156 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1158 else if (unformat (input, "initializers %s", &filename))
1160 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1162 else if (unformat (input, "tx"))
1164 which = VL_API_TRACE_TX;
1166 else if (unformat (input, "first %d", &first))
1170 else if (unformat (input, "last %d", &last))
1174 else if (unformat (input, "status"))
1176 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1179 else if (unformat (input, "free"))
1181 vl_msg_api_trace_onoff (am, which, 0);
1182 vl_msg_api_trace_free (am, which);
1184 else if (unformat (input, "post-mortem-on"))
1185 post_mortem_dump_enabled = 1;
1186 else if (unformat (input, "post-mortem-off"))
1187 post_mortem_dump_enabled = 0;
1189 return clib_error_return (0, "unknown input `%U'",
1190 format_unformat_error, input);
1196 VLIB_CLI_COMMAND (api_trace_command, static) = {
1197 .path = "api trace",
1199 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1200 .function = api_trace_command_fn,
1204 static clib_error_t *
1205 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1207 u32 nitems = 256 << 10;
1208 vl_api_trace_which_t which = VL_API_TRACE_RX;
1209 api_main_t *am = &api_main;
1211 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1213 if (unformat (input, "on") || unformat (input, "enable"))
1215 if (unformat (input, "nitems %d", &nitems))
1217 vl_msg_api_trace_configure (am, which, nitems);
1218 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1219 post_mortem_dump_enabled = 1;
1222 return clib_error_return (0, "unknown input `%U'",
1223 format_unformat_error, input);
1228 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1231 vl_msg_api_post_mortem_dump (void)
1233 api_main_t *am = &api_main;
1238 if (post_mortem_dump_enabled == 0)
1241 snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1244 fp = fopen (filename, "w");
1247 rv = write (2, "Couldn't create ", 16);
1248 rv = write (2, filename, strlen (filename));
1249 rv = write (2, "\n", 1);
1252 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1256 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1257 rv = write (2, filename, strlen (filename));
1258 rv = write (2, "\n", 1);
1263 /* Layered message handling support */
1266 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1268 api_main_t *am = &api_main;
1270 /* Mild idiot proofing */
1271 if (msg_id_host_byte_order > 10000)
1272 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1273 msg_id_host_byte_order,
1274 clib_net_to_host_u16 (msg_id_host_byte_order));
1275 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1276 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1280 vl_msg_api_pd_handler (void *mp, int rv)
1282 api_main_t *am = &api_main;
1283 int (*fp) (void *, int);
1286 if (clib_arch_is_little_endian)
1287 msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1289 msg_id = *((u16 *) mp);
1291 if (msg_id >= vec_len (am->pd_msg_handlers)
1292 || am->pd_msg_handlers[msg_id] == 0)
1295 fp = am->pd_msg_handlers[msg_id];
1296 rv = (*fp) (mp, rv);
1301 vl_msg_api_set_first_available_msg_id (u16 first_avail)
1303 api_main_t *am = &api_main;
1305 am->first_available_msg_id = first_avail;
1309 vl_msg_api_get_msg_ids (char *name, int n)
1311 api_main_t *am = &api_main;
1313 vl_api_msg_range_t *rp;
1317 if (am->msg_range_by_name == 0)
1318 am->msg_range_by_name = hash_create_string (0, sizeof (uword));
1320 name_copy = format (0, "%s%c", name, 0);
1322 p = hash_get_mem (am->msg_range_by_name, name_copy);
1325 clib_warning ("WARNING: duplicate message range registration for '%s'",
1327 vec_free (name_copy);
1331 if (n < 0 || n > 1024)
1334 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1336 vec_free (name_copy);
1340 vec_add2 (am->msg_ranges, rp, 1);
1342 rv = rp->first_msg_id = am->first_available_msg_id;
1343 am->first_available_msg_id += n;
1344 rp->last_msg_id = am->first_available_msg_id - 1;
1345 rp->name = name_copy;
1347 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1353 vl_msg_api_add_msg_name_crc (api_main_t * am, char *string, u32 id)
1357 if (am->msg_index_by_name_and_crc == 0)
1358 am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
1360 p = hash_get_mem (am->msg_index_by_name_and_crc, string);
1363 clib_warning ("attempt to redefine '%s' ignored...", string);
1367 hash_set_mem (am->msg_index_by_name_and_crc, string, id);
1372 * fd.io coding-style-patch-verification: ON
1375 * eval: (c-set-style "gnu")