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 *------------------------------------------------------------------
25 #include <sys/types.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>
40 void vl_msg_api_barrier_sync (void) __attribute__ ((weak));
42 vl_msg_api_barrier_sync (void)
46 void vl_msg_api_barrier_release (void) __attribute__ ((weak));
48 vl_msg_api_barrier_release (void)
53 vl_msg_api_increment_missing_client_counter (void)
55 api_main_t *am = &api_main;
56 am->missing_clients++;
68 vl_msg_api_rx_trace_enabled (api_main_t * am)
70 return (am->rx_trace && am->rx_trace->enabled);
74 vl_msg_api_tx_trace_enabled (api_main_t * am)
76 return (am->tx_trace && am->tx_trace->enabled);
83 vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg)
89 u16 msg_id = ntohs (*((u16 *) msg));
91 cfgp = am->api_trace_cfg + msg_id;
93 if (!cfgp || !cfgp->trace_enable)
100 clib_warning ("tp->nitems is 0");
104 if (vec_len (tp->traces) < tp->nitems)
106 vec_add1 (tp->traces, 0);
107 this_trace = tp->traces + vec_len (tp->traces) - 1;
112 old_trace = tp->traces + tp->curindex++;
113 if (tp->curindex == tp->nitems)
115 vec_free (*old_trace);
116 this_trace = old_trace;
119 vec_validate (msg_copy, cfgp->size - 1);
120 clib_memcpy (msg_copy, msg, cfgp->size);
121 *this_trace = msg_copy;
125 vl_msg_api_trace_onoff (api_main_t * am, vl_api_trace_which_t which,
133 case VL_API_TRACE_TX:
137 vl_msg_api_trace_configure (am, which, 1024);
142 case VL_API_TRACE_RX:
146 vl_msg_api_trace_configure (am, which, 1024);
157 if (tp == 0 || tp->nitems == 0)
167 vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which)
174 case VL_API_TRACE_TX:
178 case VL_API_TRACE_RX:
188 if (!tp || tp->nitems == 0)
194 for (i = 0; i < vec_len (tp->traces); i++)
196 vec_free (tp->traces[i]);
198 vec_free (tp->traces);
204 vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp)
207 vl_api_trace_file_header_t fh;
213 case VL_API_TRACE_TX:
217 case VL_API_TRACE_RX:
226 /* Configured, data present? */
227 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
230 /* "Dare to be stupid" check */
236 /* Write the file header */
237 fh.nitems = vec_len (tp->traces);
238 fh.endian = tp->endian;
239 fh.wrapped = tp->wrapped;
241 if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
247 if (tp->wrapped == 0)
250 * Note: vec_len return 0 when fed a NULL pointer.
251 * Unfortunately, the static analysis tool doesn't
252 * figure it out, hence the suppressed warnings.
253 * What a great use of my time.
255 for (i = 0; i < vec_len (tp->traces); i++)
257 /*sa_ignore NO_NULL_CHK */
260 * This retarded check required to pass
265 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
273 /* Wrap case: write oldest -> end of buffer */
274 for (i = tp->curindex; i < vec_len (tp->traces); i++)
278 * This retarded check required to pass
284 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
289 /* write beginning of buffer -> oldest-1 */
290 for (i = 0; i < tp->curindex; i++)
292 /*sa_ignore NO_NULL_CHK */
295 * This retarded check required to pass
301 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
311 vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
319 case VL_API_TRACE_TX:
323 vec_validate (am->tx_trace, 0);
328 case VL_API_TRACE_RX:
332 vec_validate (am->rx_trace, 0);
345 was_on = vl_msg_api_trace_onoff (am, which, 0);
349 vl_msg_api_trace_free (am, which);
352 memset (tp, 0, sizeof (*tp));
354 if (clib_arch_is_big_endian)
356 tp->endian = VL_API_BIG_ENDIAN;
360 tp->endian = VL_API_LITTLE_ENDIAN;
366 (void) vl_msg_api_trace_onoff (am, which, was_on);
372 msg_handler_internal (api_main_t * am,
373 void *the_msg, int trace_it, int do_it, int free_it)
375 u16 id = ntohs (*((u16 *) the_msg));
376 u8 *(*print_fp) (void *, void *);
378 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
381 vl_msg_api_trace (am, am->rx_trace, the_msg);
383 if (am->msg_print_flag)
385 fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
386 print_fp = (void *) am->msg_print_handlers[id];
389 fformat (stdout, " [no registered print fn]\n");
393 (*print_fp) (the_msg, stdout);
399 if (!am->is_mp_safe[id])
400 vl_msg_api_barrier_sync ();
401 (*am->msg_handlers[id]) (the_msg);
402 if (!am->is_mp_safe[id])
403 vl_msg_api_barrier_release ();
408 clib_warning ("no handler for msg id %d", id);
412 vl_msg_api_free (the_msg);
415 /* set to 1 if you want before/after message handler event logging */
416 #define ELOG_API_MESSAGE_HANDLERS 0
418 #if ELOG_API_MESSAGE_HANDLERS > 0
420 elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
427 h = hash_create_string (0, sizeof (uword));
429 p = hash_get_mem (h, msg_name);
432 r = elog_string (&vm->elog_main, "%s", msg_name);
434 name_copy = format (0, "%s%c", msg_name, 0);
436 hash_set_mem (h, name_copy, r);
442 /* This is only to be called from a vlib/vnet app */
444 vl_msg_api_handler_with_vm_node (api_main_t * am,
445 void *the_msg, vlib_main_t * vm,
446 vlib_node_runtime_t * node)
448 u16 id = ntohs (*((u16 *) the_msg));
449 u8 *(*handler) (void *, void *, void *);
451 #if ELOG_API_MESSAGE_HANDLERS > 0
454 ELOG_TYPE_DECLARE (e) =
456 .format = "api-msg: %s",
464 ed = ELOG_DATA (&vm->elog_main, e);
465 if (id < vec_len (am->msg_names))
466 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
468 ed->c = elog_id_for_msg_name (vm, "BOGUS");
472 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
474 handler = (void *) am->msg_handlers[id];
476 if (am->rx_trace && am->rx_trace->enabled)
477 vl_msg_api_trace (am, am->rx_trace, the_msg);
479 if (!am->is_mp_safe[id])
480 vl_msg_api_barrier_sync ();
481 (*handler) (the_msg, vm, node);
482 if (!am->is_mp_safe[id])
483 vl_msg_api_barrier_release ();
487 clib_warning ("no hander for msg id %d", id);
491 * Special-case, so we can e.g. bounce messages off the vnet
492 * main thread without copying them...
494 if (!(am->message_bounce[id]))
495 vl_msg_api_free (the_msg);
497 #if ELOG_API_MESSAGE_HANDLERS > 0
500 ELOG_TYPE_DECLARE (e) = {
501 .format = "api-msg-done: %s",
510 ed = ELOG_DATA (&vm->elog_main, e);
511 if (id < vec_len (am->msg_names))
512 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
514 ed->c = elog_id_for_msg_name (vm, "BOGUS");
520 vl_msg_api_handler (void *the_msg)
522 api_main_t *am = &api_main;
524 msg_handler_internal (am, the_msg,
526 && am->rx_trace->enabled) /* trace_it */ ,
527 1 /* do_it */ , 1 /* free_it */ );
531 vl_msg_api_handler_no_free (void *the_msg)
533 api_main_t *am = &api_main;
534 msg_handler_internal (am, the_msg,
536 && am->rx_trace->enabled) /* trace_it */ ,
537 1 /* do_it */ , 0 /* free_it */ );
541 vl_msg_api_handler_no_trace_no_free (void *the_msg)
543 api_main_t *am = &api_main;
544 msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
549 * Add a trace record to the API message trace buffer, if
550 * API message tracing is enabled. Handy for adding sufficient
551 * data to the trace to reproduce autonomous state, as opposed to
552 * state downloaded via control-plane API messages. Example: the NAT
553 * application creates database entries based on packet traffic, not
554 * control-plane messages.
558 vl_msg_api_trace_only (void *the_msg)
560 api_main_t *am = &api_main;
562 msg_handler_internal (am, the_msg,
564 && am->rx_trace->enabled) /* trace_it */ ,
565 0 /* do_it */ , 0 /* free_it */ );
569 vl_msg_api_cleanup_handler (void *the_msg)
571 api_main_t *am = &api_main;
572 u16 id = ntohs (*((u16 *) the_msg));
574 if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
576 clib_warning ("_vl_msg_id too large: %d\n", id);
579 if (am->msg_cleanup_handlers[id])
580 (*am->msg_cleanup_handlers[id]) (the_msg);
582 vl_msg_api_free (the_msg);
586 * vl_msg_api_replay_handler
589 vl_msg_api_replay_handler (void *the_msg)
591 api_main_t *am = &api_main;
593 u16 id = ntohs (*((u16 *) the_msg));
595 if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
597 clib_warning ("_vl_msg_id too large: %d\n", id);
600 /* do NOT trace the message... */
601 if (am->msg_handlers[id])
602 (*am->msg_handlers[id]) (the_msg);
603 /* do NOT free the message buffer... */
607 * vl_msg_api_socket_handler
610 vl_msg_api_socket_handler (void *the_msg)
612 api_main_t *am = &api_main;
614 msg_handler_internal (am, the_msg,
616 && am->rx_trace->enabled) /* trace_it */ ,
617 1 /* do_it */ , 0 /* free_it */ );
620 #define foreach_msg_api_vector \
623 _(msg_cleanup_handlers) \
624 _(msg_endian_handlers) \
625 _(msg_print_handlers) \
631 vl_msg_api_config (vl_msg_api_msg_config_t * c)
633 api_main_t *am = &api_main;
637 #define _(a) vec_validate (am->a, c->id);
638 foreach_msg_api_vector;
641 am->msg_names[c->id] = c->name;
642 am->msg_handlers[c->id] = c->handler;
643 am->msg_cleanup_handlers[c->id] = c->cleanup;
644 am->msg_endian_handlers[c->id] = c->endian;
645 am->msg_print_handlers[c->id] = c->print;
646 am->message_bounce[c->id] = c->message_bounce;
647 am->is_mp_safe[c->id] = c->is_mp_safe;
649 am->api_trace_cfg[c->id].size = c->size;
650 am->api_trace_cfg[c->id].trace_enable = c->traced;
651 am->api_trace_cfg[c->id].replay_enable = c->replay;
655 * vl_msg_api_set_handlers
656 * preserve the old API for a while
659 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
660 void *endian, void *print, int size, int traced)
662 vl_msg_api_msg_config_t cfg;
663 vl_msg_api_msg_config_t *c = &cfg;
667 c->handler = handler;
668 c->cleanup = cleanup;
674 c->message_bounce = 0;
676 vl_msg_api_config (c);
680 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
682 api_main_t *am = &api_main;
685 vec_validate (am->msg_cleanup_handlers, msg_id);
686 am->msg_cleanup_handlers[msg_id] = fp;
690 vl_msg_api_queue_handler (unix_shared_memory_queue_t * q)
694 while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
695 vl_msg_api_handler ((void *) msg);
699 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
703 case VL_API_TRACE_RX:
705 case VL_API_TRACE_TX:
713 vl_noop_handler (void *mp)
718 vl_api_init (vlib_main_t * vm)
721 api_main_t *am = &api_main;
728 am->region_name = "/unset";
730 * Eventually passed to fchown, -1 => "current user"
731 * instead of 0 => "root". A very fine disctinction at best.
733 if (am->api_uid == 0)
735 if (am->api_gid == 0)
741 void vl_msg_api_custom_dump_configure (api_main_t * am)
742 __attribute__ ((weak));
744 vl_msg_api_custom_dump_configure (api_main_t * am)
748 VLIB_INIT_FUNCTION (vl_api_init);
751 vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
752 u32 first_index, u32 last_index,
753 vl_api_replay_t which)
755 vl_api_trace_file_header_t *hp;
760 u8 endian_swap_needed = 0;
761 api_main_t *am = &api_main;
764 void **saved_print_handlers = 0;
766 fd = open ((char *) filename, O_RDONLY);
770 vlib_cli_output (vm, "Couldn't open %s\n", filename);
774 if (fstat (fd, &statb) < 0)
776 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
781 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
783 vlib_cli_output (vm, "File not plausible: %s\n", filename);
788 file_size = statb.st_size;
789 file_size = (file_size + 4095) & ~(4096);
791 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
793 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
795 vlib_cli_output (vm, "mmap failed: %s\n", filename);
801 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
802 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
803 endian_swap_needed = 1;
805 if (endian_swap_needed)
806 nitems = ntohl (hp->nitems);
810 if (last_index == (u32) ~ 0)
812 last_index = nitems - 1;
815 if (first_index >= nitems || last_index >= nitems)
817 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
818 first_index, last_index, nitems - 1);
819 munmap (hp, file_size);
824 "Note: wrapped/incomplete trace, results may vary\n");
826 if (which == CUSTOM_DUMP)
828 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
829 vl_msg_api_custom_dump_configure (am);
833 msg = (u8 *) (hp + 1);
835 for (i = 0; i < first_index; i++)
841 if (clib_arch_is_little_endian)
842 msg_id = ntohs (*((u16 *) msg));
844 msg_id = *((u16 *) msg);
846 cfgp = am->api_trace_cfg + msg_id;
849 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
856 for (; i <= last_index; i++)
864 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
866 if (clib_arch_is_little_endian)
867 msg_id = ntohs (*((u16 *) msg));
869 msg_id = *((u16 *) msg);
871 cfgp = am->api_trace_cfg + msg_id;
874 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
879 /* Copy the buffer (from the read-only mmap'ed file) */
880 vec_validate (tmpbuf, size - 1 + sizeof (uword));
881 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
882 memset (tmpbuf, 0xf, sizeof (uword));
885 * Endian swap if needed. All msg data is supposed to be
886 * in network byte order. All msg handlers are supposed to
887 * know that. The generic message dumpers don't know that.
888 * One could fix apigen, I suppose.
890 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
892 void (*endian_fp) (void *);
893 if (msg_id >= vec_len (am->msg_endian_handlers)
894 || (am->msg_endian_handlers[msg_id] == 0))
896 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
899 endian_fp = am->msg_endian_handlers[msg_id];
900 (*endian_fp) (tmpbuf + sizeof (uword));
903 /* msg_id always in network byte order */
904 if (clib_arch_is_little_endian)
906 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
914 if (msg_id < vec_len (am->msg_print_handlers) &&
915 am->msg_print_handlers[msg_id])
917 u8 *(*print_fp) (void *, void *);
919 print_fp = (void *) am->msg_print_handlers[msg_id];
920 (*print_fp) (tmpbuf + sizeof (uword), vm);
924 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
931 if (msg_id < vec_len (am->msg_print_handlers) &&
932 am->msg_print_handlers[msg_id])
936 u8 *(*print_fp) (void *, void *);
938 print_fp = (void *) am->msg_print_handlers[msg_id];
940 vlib_cli_output (vm, "/*");
942 (*print_fp) (tmpbuf + sizeof (uword), vm);
943 vlib_cli_output (vm, "*/\n");
945 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
946 am->msg_names[msg_id], i,
947 am->api_trace_cfg[msg_id].size);
949 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
952 s = format (s, "\n ");
953 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
955 s = format (s, "\n};\n%c", 0);
956 vlib_cli_output (vm, (char *) s);
962 if (msg_id < vec_len (am->msg_print_handlers) &&
963 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
965 void (*handler) (void *);
967 handler = (void *) am->msg_handlers[msg_id];
969 if (!am->is_mp_safe[msg_id])
970 vl_msg_api_barrier_sync ();
971 (*handler) (tmpbuf + sizeof (uword));
972 if (!am->is_mp_safe[msg_id])
973 vl_msg_api_barrier_release ();
977 if (cfgp->replay_enable)
978 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
985 _vec_len (tmpbuf) = 0;
989 if (saved_print_handlers)
991 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
992 vec_len (am->msg_print_handlers) * sizeof (void *));
993 vec_free (saved_print_handlers);
996 munmap (hp, file_size);
1000 format_vl_msg_api_trace_status (u8 * s, va_list * args)
1002 api_main_t *am = va_arg (*args, api_main_t *);
1003 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1009 case VL_API_TRACE_TX:
1011 trace_name = "TX trace";
1014 case VL_API_TRACE_RX:
1016 trace_name = "RX trace";
1025 s = format (s, "%s: not yet configured.\n", trace_name);
1029 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1030 trace_name, vec_len (tp->traces), tp->nitems,
1031 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1035 static u8 post_mortem_dump_enabled;
1037 static clib_error_t *
1038 api_trace_command_fn (vlib_main_t * vm,
1039 unformat_input_t * input, vlib_cli_command_t * cmd)
1041 u32 nitems = 256 << 10;
1042 api_main_t *am = &api_main;
1043 vl_api_trace_which_t which = VL_API_TRACE_RX;
1046 u32 last = (u32) ~ 0;
1050 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1052 if (unformat (input, "on") || unformat (input, "enable"))
1054 if (unformat (input, "nitems %d", &nitems))
1056 vl_msg_api_trace_configure (am, which, nitems);
1057 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1059 else if (unformat (input, "off"))
1061 vl_msg_api_trace_onoff (am, which, 0);
1063 else if (unformat (input, "save %s", &filename))
1065 u8 *chroot_filename;
1066 if (strstr ((char *) filename, "..")
1067 || index ((char *) filename, '/'))
1069 vlib_cli_output (vm, "illegal characters in filename '%s'",
1074 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1076 vec_free (filename);
1078 fp = fopen ((char *) chroot_filename, "w");
1081 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1084 rv = vl_msg_api_trace_save (am, which, fp);
1087 vlib_cli_output (vm, "API Trace data not present\n");
1089 vlib_cli_output (vm, "File for writing is closed\n");
1091 vlib_cli_output (vm, "Error while writing header to file\n");
1093 vlib_cli_output (vm, "Error while writing trace to file\n");
1095 vlib_cli_output (vm,
1096 "Error while writing end of buffer trace to file\n");
1098 vlib_cli_output (vm,
1099 "Error while writing start of buffer trace to file\n");
1101 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
1103 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1104 vec_free (chroot_filename);
1106 else if (unformat (input, "dump %s", &filename))
1108 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1110 else if (unformat (input, "custom-dump %s", &filename))
1112 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1114 else if (unformat (input, "replay %s", &filename))
1116 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1118 else if (unformat (input, "initializers %s", &filename))
1120 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1122 else if (unformat (input, "tx"))
1124 which = VL_API_TRACE_TX;
1126 else if (unformat (input, "first %d", &first))
1130 else if (unformat (input, "last %d", &last))
1134 else if (unformat (input, "status"))
1136 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1139 else if (unformat (input, "free"))
1141 vl_msg_api_trace_onoff (am, which, 0);
1142 vl_msg_api_trace_free (am, which);
1144 else if (unformat (input, "post-mortem-on"))
1145 post_mortem_dump_enabled = 1;
1146 else if (unformat (input, "post-mortem-off"))
1147 post_mortem_dump_enabled = 0;
1149 return clib_error_return (0, "unknown input `%U'",
1150 format_unformat_error, input);
1156 VLIB_CLI_COMMAND (api_trace_command, static) = {
1157 .path = "api trace",
1159 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1160 .function = api_trace_command_fn,
1164 static clib_error_t *
1165 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1167 u32 nitems = 256 << 10;
1168 vl_api_trace_which_t which = VL_API_TRACE_RX;
1169 api_main_t *am = &api_main;
1171 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1173 if (unformat (input, "on") || unformat (input, "enable"))
1175 if (unformat (input, "nitems %d", &nitems))
1177 vl_msg_api_trace_configure (am, which, nitems);
1178 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1179 post_mortem_dump_enabled = 1;
1182 return clib_error_return (0, "unknown input `%U'",
1183 format_unformat_error, input);
1188 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1191 vl_msg_api_post_mortem_dump (void)
1193 api_main_t *am = &api_main;
1198 if (post_mortem_dump_enabled == 0)
1201 snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1204 fp = fopen (filename, "w");
1207 rv = write (2, "Couldn't create ", 16);
1208 rv = write (2, filename, strlen (filename));
1209 rv = write (2, "\n", 1);
1212 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1216 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1217 rv = write (2, filename, strlen (filename));
1218 rv = write (2, "\n", 1);
1223 /* Layered message handling support */
1226 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1228 api_main_t *am = &api_main;
1230 /* Mild idiot proofing */
1231 if (msg_id_host_byte_order > 10000)
1232 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1233 msg_id_host_byte_order,
1234 clib_net_to_host_u16 (msg_id_host_byte_order));
1235 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1236 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1240 vl_msg_api_pd_handler (void *mp, int rv)
1242 api_main_t *am = &api_main;
1243 int (*fp) (void *, int);
1246 if (clib_arch_is_little_endian)
1247 msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1249 msg_id = *((u16 *) mp);
1251 if (msg_id >= vec_len (am->pd_msg_handlers)
1252 || am->pd_msg_handlers[msg_id] == 0)
1255 fp = am->pd_msg_handlers[msg_id];
1256 rv = (*fp) (mp, rv);
1261 vl_msg_api_set_first_available_msg_id (u16 first_avail)
1263 api_main_t *am = &api_main;
1265 am->first_available_msg_id = first_avail;
1269 vl_msg_api_get_msg_ids (char *name, int n)
1271 api_main_t *am = &api_main;
1273 vl_api_msg_range_t *rp;
1277 if (am->msg_range_by_name == 0)
1278 am->msg_range_by_name = hash_create_string (0, sizeof (uword));
1280 name_copy = format (0, "%s%c", name, 0);
1282 p = hash_get_mem (am->msg_range_by_name, name_copy);
1285 clib_warning ("WARNING: duplicate message range registration for '%s'",
1287 vec_free (name_copy);
1291 if (n < 0 || n > 1024)
1294 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1296 vec_free (name_copy);
1300 vec_add2 (am->msg_ranges, rp, 1);
1302 rv = rp->first_msg_id = am->first_available_msg_id;
1303 am->first_available_msg_id += n;
1304 rp->last_msg_id = am->first_available_msg_id - 1;
1305 rp->name = name_copy;
1307 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1313 * fd.io coding-style-patch-verification: ON
1316 * eval: (c-set-style "gnu")