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 handler 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 if (am->msg_names[c->id])
671 clib_warning ("BUG: multiple registrations of 'vl_api_%s_t_handler'",
674 am->msg_names[c->id] = c->name;
675 am->msg_handlers[c->id] = c->handler;
676 am->msg_cleanup_handlers[c->id] = c->cleanup;
677 am->msg_endian_handlers[c->id] = c->endian;
678 am->msg_print_handlers[c->id] = c->print;
679 am->message_bounce[c->id] = c->message_bounce;
680 am->is_mp_safe[c->id] = c->is_mp_safe;
682 am->api_trace_cfg[c->id].size = c->size;
683 am->api_trace_cfg[c->id].trace_enable = c->traced;
684 am->api_trace_cfg[c->id].replay_enable = c->replay;
688 * vl_msg_api_set_handlers
689 * preserve the old API for a while
692 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
693 void *endian, void *print, int size, int traced)
695 vl_msg_api_msg_config_t cfg;
696 vl_msg_api_msg_config_t *c = &cfg;
698 memset (c, 0, sizeof (*c));
702 c->handler = handler;
703 c->cleanup = cleanup;
708 c->message_bounce = 0;
710 vl_msg_api_config (c);
714 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
716 api_main_t *am = &api_main;
719 vec_validate (am->msg_cleanup_handlers, msg_id);
720 am->msg_cleanup_handlers[msg_id] = fp;
724 vl_msg_api_queue_handler (unix_shared_memory_queue_t * q)
728 while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
729 vl_msg_api_handler ((void *) msg);
733 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
737 case VL_API_TRACE_RX:
739 case VL_API_TRACE_TX:
747 vl_noop_handler (void *mp)
752 vl_api_init (vlib_main_t * vm)
755 api_main_t *am = &api_main;
762 am->region_name = "/unset";
764 * Eventually passed to fchown, -1 => "current user"
765 * instead of 0 => "root". A very fine disctinction at best.
767 if (am->api_uid == 0)
769 if (am->api_gid == 0)
775 void vl_msg_api_custom_dump_configure (api_main_t * am)
776 __attribute__ ((weak));
778 vl_msg_api_custom_dump_configure (api_main_t * am)
782 VLIB_INIT_FUNCTION (vl_api_init);
785 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
786 u32 first_index, u32 last_index,
787 vl_api_replay_t which)
789 vl_api_trace_file_header_t *hp;
794 u8 endian_swap_needed = 0;
795 api_main_t *am = &api_main;
798 void **saved_print_handlers = 0;
800 fd = open ((char *) filename, O_RDONLY);
804 vlib_cli_output (vm, "Couldn't open %s\n", filename);
808 if (fstat (fd, &statb) < 0)
810 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
815 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
817 vlib_cli_output (vm, "File not plausible: %s\n", filename);
822 file_size = statb.st_size;
823 file_size = (file_size + 4095) & ~(4096);
825 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
827 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
829 vlib_cli_output (vm, "mmap failed: %s\n", filename);
835 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
836 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
837 endian_swap_needed = 1;
839 if (endian_swap_needed)
840 nitems = ntohl (hp->nitems);
844 if (last_index == (u32) ~ 0)
846 last_index = nitems - 1;
849 if (first_index >= nitems || last_index >= nitems)
851 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
852 first_index, last_index, nitems - 1);
853 munmap (hp, file_size);
858 "Note: wrapped/incomplete trace, results may vary\n");
860 if (which == CUSTOM_DUMP)
862 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
863 vl_msg_api_custom_dump_configure (am);
867 msg = (u8 *) (hp + 1);
869 for (i = 0; i < first_index; i++)
875 size = clib_host_to_net_u32 (*(u32 *) msg);
878 if (clib_arch_is_little_endian)
879 msg_id = ntohs (*((u16 *) msg));
881 msg_id = *((u16 *) msg);
883 cfgp = am->api_trace_cfg + msg_id;
886 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
887 munmap (hp, file_size);
894 am->replay_in_progress = 1;
896 for (; i <= last_index; i++)
904 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
906 size = clib_host_to_net_u32 (*(u32 *) msg);
909 if (clib_arch_is_little_endian)
910 msg_id = ntohs (*((u16 *) msg));
912 msg_id = *((u16 *) msg);
914 cfgp = am->api_trace_cfg + msg_id;
917 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
918 munmap (hp, file_size);
920 am->replay_in_progress = 0;
924 /* Copy the buffer (from the read-only mmap'ed file) */
925 vec_validate (tmpbuf, size - 1 + sizeof (uword));
926 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
927 memset (tmpbuf, 0xf, sizeof (uword));
930 * Endian swap if needed. All msg data is supposed to be
931 * in network byte order. All msg handlers are supposed to
932 * know that. The generic message dumpers don't know that.
933 * One could fix apigen, I suppose.
935 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
937 void (*endian_fp) (void *);
938 if (msg_id >= vec_len (am->msg_endian_handlers)
939 || (am->msg_endian_handlers[msg_id] == 0))
941 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
942 munmap (hp, file_size);
944 am->replay_in_progress = 0;
947 endian_fp = am->msg_endian_handlers[msg_id];
948 (*endian_fp) (tmpbuf + sizeof (uword));
951 /* msg_id always in network byte order */
952 if (clib_arch_is_little_endian)
954 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
962 if (msg_id < vec_len (am->msg_print_handlers) &&
963 am->msg_print_handlers[msg_id])
965 u8 *(*print_fp) (void *, void *);
967 print_fp = (void *) am->msg_print_handlers[msg_id];
968 (*print_fp) (tmpbuf + sizeof (uword), vm);
972 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
979 if (msg_id < vec_len (am->msg_print_handlers) &&
980 am->msg_print_handlers[msg_id])
984 u8 *(*print_fp) (void *, void *);
986 print_fp = (void *) am->msg_print_handlers[msg_id];
988 vlib_cli_output (vm, "/*");
990 (*print_fp) (tmpbuf + sizeof (uword), vm);
991 vlib_cli_output (vm, "*/\n");
993 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
994 am->msg_names[msg_id], i,
995 am->api_trace_cfg[msg_id].size);
997 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
1000 s = format (s, "\n ");
1001 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
1003 s = format (s, "\n};\n%c", 0);
1004 vlib_cli_output (vm, (char *) s);
1010 if (msg_id < vec_len (am->msg_print_handlers) &&
1011 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
1013 void (*handler) (void *);
1015 handler = (void *) am->msg_handlers[msg_id];
1017 if (!am->is_mp_safe[msg_id])
1018 vl_msg_api_barrier_sync ();
1019 (*handler) (tmpbuf + sizeof (uword));
1020 if (!am->is_mp_safe[msg_id])
1021 vl_msg_api_barrier_release ();
1025 if (cfgp->replay_enable)
1026 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
1033 _vec_len (tmpbuf) = 0;
1037 if (saved_print_handlers)
1039 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
1040 vec_len (am->msg_print_handlers) * sizeof (void *));
1041 vec_free (saved_print_handlers);
1044 munmap (hp, file_size);
1046 am->replay_in_progress = 0;
1050 format_vl_msg_api_trace_status (u8 * s, va_list * args)
1052 api_main_t *am = va_arg (*args, api_main_t *);
1053 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1059 case VL_API_TRACE_TX:
1061 trace_name = "TX trace";
1064 case VL_API_TRACE_RX:
1066 trace_name = "RX trace";
1075 s = format (s, "%s: not yet configured.\n", trace_name);
1079 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1080 trace_name, vec_len (tp->traces), tp->nitems,
1081 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1085 static u8 post_mortem_dump_enabled;
1087 static clib_error_t *
1088 api_trace_command_fn (vlib_main_t * vm,
1089 unformat_input_t * input, vlib_cli_command_t * cmd)
1091 u32 nitems = 256 << 10;
1092 api_main_t *am = &api_main;
1093 vl_api_trace_which_t which = VL_API_TRACE_RX;
1096 u32 last = (u32) ~ 0;
1100 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1102 if (unformat (input, "on") || unformat (input, "enable"))
1104 if (unformat (input, "nitems %d", &nitems))
1106 vl_msg_api_trace_configure (am, which, nitems);
1107 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1109 else if (unformat (input, "off"))
1111 vl_msg_api_trace_onoff (am, which, 0);
1113 else if (unformat (input, "save %s", &filename))
1115 u8 *chroot_filename;
1116 if (strstr ((char *) filename, "..")
1117 || index ((char *) filename, '/'))
1119 vlib_cli_output (vm, "illegal characters in filename '%s'",
1124 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1126 vec_free (filename);
1128 fp = fopen ((char *) chroot_filename, "w");
1131 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1134 rv = vl_msg_api_trace_save (am, which, fp);
1137 vlib_cli_output (vm, "API Trace data not present\n");
1139 vlib_cli_output (vm, "File for writing is closed\n");
1141 vlib_cli_output (vm, "Error while writing header to file\n");
1143 vlib_cli_output (vm, "Error while writing trace to file\n");
1145 vlib_cli_output (vm,
1146 "Error while writing end of buffer trace to file\n");
1148 vlib_cli_output (vm,
1149 "Error while writing start of buffer trace to file\n");
1151 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
1153 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1154 vec_free (chroot_filename);
1156 else if (unformat (input, "dump %s", &filename))
1158 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1160 else if (unformat (input, "custom-dump %s", &filename))
1162 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1164 else if (unformat (input, "replay %s", &filename))
1166 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1168 else if (unformat (input, "initializers %s", &filename))
1170 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1172 else if (unformat (input, "tx"))
1174 which = VL_API_TRACE_TX;
1176 else if (unformat (input, "first %d", &first))
1180 else if (unformat (input, "last %d", &last))
1184 else if (unformat (input, "status"))
1186 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1189 else if (unformat (input, "free"))
1191 vl_msg_api_trace_onoff (am, which, 0);
1192 vl_msg_api_trace_free (am, which);
1194 else if (unformat (input, "post-mortem-on"))
1195 post_mortem_dump_enabled = 1;
1196 else if (unformat (input, "post-mortem-off"))
1197 post_mortem_dump_enabled = 0;
1199 return clib_error_return (0, "unknown input `%U'",
1200 format_unformat_error, input);
1206 VLIB_CLI_COMMAND (api_trace_command, static) = {
1207 .path = "api trace",
1209 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1210 .function = api_trace_command_fn,
1214 static clib_error_t *
1215 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1217 u32 nitems = 256 << 10;
1218 vl_api_trace_which_t which = VL_API_TRACE_RX;
1219 api_main_t *am = &api_main;
1221 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1223 if (unformat (input, "on") || unformat (input, "enable"))
1225 if (unformat (input, "nitems %d", &nitems))
1227 vl_msg_api_trace_configure (am, which, nitems);
1228 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1229 post_mortem_dump_enabled = 1;
1232 return clib_error_return (0, "unknown input `%U'",
1233 format_unformat_error, input);
1238 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1241 vl_msg_api_post_mortem_dump (void)
1243 api_main_t *am = &api_main;
1248 if (post_mortem_dump_enabled == 0)
1251 snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1254 fp = fopen (filename, "w");
1257 rv = write (2, "Couldn't create ", 16);
1258 rv = write (2, filename, strlen (filename));
1259 rv = write (2, "\n", 1);
1262 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1266 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1267 rv = write (2, filename, strlen (filename));
1268 rv = write (2, "\n", 1);
1273 /* Layered message handling support */
1276 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1278 api_main_t *am = &api_main;
1280 /* Mild idiot proofing */
1281 if (msg_id_host_byte_order > 10000)
1282 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1283 msg_id_host_byte_order,
1284 clib_net_to_host_u16 (msg_id_host_byte_order));
1285 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1286 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1290 vl_msg_api_pd_handler (void *mp, int rv)
1292 api_main_t *am = &api_main;
1293 int (*fp) (void *, int);
1296 if (clib_arch_is_little_endian)
1297 msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1299 msg_id = *((u16 *) mp);
1301 if (msg_id >= vec_len (am->pd_msg_handlers)
1302 || am->pd_msg_handlers[msg_id] == 0)
1305 fp = am->pd_msg_handlers[msg_id];
1306 rv = (*fp) (mp, rv);
1311 vl_msg_api_set_first_available_msg_id (u16 first_avail)
1313 api_main_t *am = &api_main;
1315 am->first_available_msg_id = first_avail;
1319 vl_msg_api_get_msg_ids (char *name, int n)
1321 api_main_t *am = &api_main;
1323 vl_api_msg_range_t *rp;
1327 if (am->msg_range_by_name == 0)
1328 am->msg_range_by_name = hash_create_string (0, sizeof (uword));
1330 name_copy = format (0, "%s%c", name, 0);
1332 p = hash_get_mem (am->msg_range_by_name, name_copy);
1335 clib_warning ("WARNING: duplicate message range registration for '%s'",
1337 vec_free (name_copy);
1341 if (n < 0 || n > 1024)
1344 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1346 vec_free (name_copy);
1350 vec_add2 (am->msg_ranges, rp, 1);
1352 rv = rp->first_msg_id = am->first_available_msg_id;
1353 am->first_available_msg_id += n;
1354 rp->last_msg_id = am->first_available_msg_id - 1;
1355 rp->name = name_copy;
1357 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1363 vl_msg_api_add_msg_name_crc (api_main_t * am, char *string, u32 id)
1367 if (am->msg_index_by_name_and_crc == 0)
1368 am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
1370 p = hash_get_mem (am->msg_index_by_name_and_crc, string);
1373 clib_warning ("attempt to redefine '%s' ignored...", string);
1377 hash_set_mem (am->msg_index_by_name_and_crc, string, id);
1382 * fd.io coding-style-patch-verification: ON
1385 * eval: (c-set-style "gnu")