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));
41 void vl_msg_api_barrier_sync(void) { }
43 void vl_msg_api_barrier_release(void) __attribute__((weak));
44 void vl_msg_api_barrier_release(void) { }
46 void vl_msg_api_increment_missing_client_counter(void)
48 api_main_t * am = &api_main;
49 am->missing_clients++;
59 int vl_msg_api_rx_trace_enabled(api_main_t *am)
61 return (am->rx_trace && am->rx_trace->enabled);
64 int vl_msg_api_tx_trace_enabled(api_main_t *am)
66 return (am->tx_trace && am->tx_trace->enabled);
72 void vl_msg_api_trace(api_main_t *am, vl_api_trace_t *tp, void *msg)
78 u16 msg_id = ntohs(*((u16 *)msg));
80 cfgp = am->api_trace_cfg + msg_id;
82 if (!cfgp || !cfgp->trace_enable)
87 if (tp->nitems == 0) {
88 clib_warning ("tp->nitems is 0");
92 if (vec_len(tp->traces) < tp->nitems) {
93 vec_add1(tp->traces, 0);
94 this_trace = tp->traces + vec_len(tp->traces) - 1;
97 old_trace = tp->traces + tp->curindex++;
98 if (tp->curindex == tp->nitems)
100 vec_free(*old_trace);
101 this_trace = old_trace;
104 vec_validate(msg_copy, cfgp->size - 1);
105 clib_memcpy(msg_copy, msg, cfgp->size);
106 *this_trace = msg_copy;
109 int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which,
117 case VL_API_TRACE_TX:
120 vl_msg_api_trace_configure (am, which, 1024);
125 case VL_API_TRACE_RX:
128 vl_msg_api_trace_configure (am, which, 1024);
139 if (tp == 0 || tp->nitems == 0)
148 int vl_msg_api_trace_free(api_main_t *am, vl_api_trace_which_t which)
155 case VL_API_TRACE_TX:
159 case VL_API_TRACE_RX:
169 if (!tp || tp->nitems == 0)
175 for (i = 0; i < vec_len(tp->traces); i++) {
176 vec_free(tp->traces[i]);
178 vec_free(tp->traces);
183 int vl_msg_api_trace_save(api_main_t *am,
184 vl_api_trace_which_t which, FILE *fp)
187 vl_api_trace_file_header_t fh;
193 case VL_API_TRACE_TX:
197 case VL_API_TRACE_RX:
206 /* Configured, data present? */
207 if (tp == 0 || tp->nitems == 0 || vec_len(tp->traces) == 0)
210 /* "Dare to be stupid" check */
215 /* Write the file header */
216 fh.nitems = vec_len(tp->traces);
217 fh.endian = tp->endian;
218 fh.wrapped = tp->wrapped;
220 if (fwrite(&fh, sizeof(fh), 1, fp) != 1) {
225 if (tp->wrapped == 0) {
227 * Note: vec_len return 0 when fed a NULL pointer.
228 * Unfortunately, the static analysis tool doesn't
229 * figure it out, hence the suppressed warnings.
230 * What a great use of my time.
232 for (i = 0; i < vec_len(tp->traces); i++) {
233 /*sa_ignore NO_NULL_CHK*/
236 * This retarded check required to pass
241 if (fwrite(msg, 1, vec_len(msg), fp) != vec_len(msg)) {
246 /* Wrap case: write oldest -> end of buffer */
247 for (i = tp->curindex; i < vec_len(tp->traces); i++) {
250 * This retarded check required to pass
256 if (fwrite(msg, 1, vec_len(msg), fp) != vec_len(msg)) {
260 /* write beginning of buffer -> oldest-1 */
261 for (i = 0; i < tp->curindex; i++) {
262 /*sa_ignore NO_NULL_CHK*/
265 * This retarded check required to pass
271 if (fwrite(msg, 1, vec_len(msg), fp) != vec_len(msg)) {
279 int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which,
287 case VL_API_TRACE_TX:
290 vec_validate(am->tx_trace, 0);
295 case VL_API_TRACE_RX:
298 vec_validate(am->rx_trace, 0);
310 was_on = vl_msg_api_trace_onoff(am, which, 0);
313 vl_msg_api_trace_free(am, which);
316 memset(tp, 0, sizeof(*tp));
318 if (clib_arch_is_big_endian) {
319 tp->endian = VL_API_BIG_ENDIAN;
321 tp->endian = VL_API_LITTLE_ENDIAN;
326 (void)vl_msg_api_trace_onoff(am, which, was_on);
331 always_inline void msg_handler_internal (api_main_t *am,
337 u16 id = ntohs(*((u16 *)the_msg));
338 u8 *(*print_fp)(void *, void *);
340 if (id < vec_len(am->msg_handlers) &&
341 am->msg_handlers[id]) {
343 vl_msg_api_trace(am, am->rx_trace, the_msg);
345 if (am->msg_print_flag) {
346 fformat (stdout, "[%d]: %s\n", id,
348 print_fp = (void *)am->msg_print_handlers[id];
350 fformat(stdout, " [no registered print fn]\n");
352 (*print_fp)(the_msg, stdout);
357 if (!am->is_mp_safe[id])
358 vl_msg_api_barrier_sync();
359 (*am->msg_handlers[id])(the_msg);
360 if (!am->is_mp_safe[id])
361 vl_msg_api_barrier_release();
364 clib_warning("no handler for msg id %d", id);
368 vl_msg_api_free(the_msg);
371 /* set to 1 if you want before/after message handler event logging */
372 #define ELOG_API_MESSAGE_HANDLERS 0
374 #if ELOG_API_MESSAGE_HANDLERS > 0
375 static u32 elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
382 h = hash_create_string (0, sizeof (uword));
384 p = hash_get_mem (h, msg_name);
387 r = elog_string (&vm->elog_main, "%s", msg_name);
389 name_copy = format (0, "%s%c", msg_name, 0);
391 hash_set_mem (h, name_copy, r);
397 /* This is only to be called from a vlib/vnet app */
398 void vl_msg_api_handler_with_vm_node (api_main_t *am,
399 void *the_msg, vlib_main_t *vm,
400 vlib_node_runtime_t *node)
402 u16 id = ntohs(*((u16 *)the_msg));
403 u8 *(*handler)(void *, void *, void *);
405 #if ELOG_API_MESSAGE_HANDLERS > 0
407 ELOG_TYPE_DECLARE (e) = {
408 .format = "api-msg: %s",
411 struct { u32 c; } * ed;
412 ed = ELOG_DATA (&vm->elog_main, e);
413 if (id < vec_len (am->msg_names))
414 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
416 ed->c = elog_id_for_msg_name (vm, "BOGUS");
420 if (id < vec_len(am->msg_handlers) &&
421 am->msg_handlers[id]) {
422 handler = (void *)am->msg_handlers[id];
424 if (am->rx_trace && am->rx_trace->enabled)
425 vl_msg_api_trace(am, am->rx_trace, the_msg);
427 if (!am->is_mp_safe[id])
428 vl_msg_api_barrier_sync();
429 (*handler)(the_msg, vm, node);
430 if (!am->is_mp_safe[id])
431 vl_msg_api_barrier_release();
433 clib_warning("no hander for msg id %d", id);
436 * Special-case, so we can e.g. bounce messages off the vnet
437 * main thread without copying them...
439 if (!(am->message_bounce[id]))
440 vl_msg_api_free(the_msg);
442 #if ELOG_API_MESSAGE_HANDLERS > 0
444 ELOG_TYPE_DECLARE (e) = {
445 .format = "api-msg-done: %s",
448 struct { u32 c; } * ed;
449 ed = ELOG_DATA (&vm->elog_main, e);
450 if (id < vec_len (am->msg_names))
451 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
453 ed->c = elog_id_for_msg_name (vm, "BOGUS");
458 void vl_msg_api_handler (void *the_msg)
460 api_main_t *am = &api_main;
462 msg_handler_internal (am, the_msg,
464 && am->rx_trace->enabled) /* trace_it */,
465 1 /* do_it */, 1 /* free_it */);
468 void vl_msg_api_handler_no_free (void *the_msg)
470 api_main_t *am = &api_main;
471 msg_handler_internal (am, the_msg,
473 && am->rx_trace->enabled) /* trace_it */,
474 1 /* do_it */, 0 /* free_it */);
477 void vl_msg_api_handler_no_trace_no_free (void *the_msg)
479 api_main_t *am = &api_main;
480 msg_handler_internal (am, the_msg, 0/* trace_it */, 1 /* do_it */,
485 * Add a trace record to the API message trace buffer, if
486 * API message tracing is enabled. Handy for adding sufficient
487 * data to the trace to reproduce autonomous state, as opposed to
488 * state downloaded via control-plane API messages. Example: the NAT
489 * application creates database entries based on packet traffic, not
490 * control-plane messages.
493 void vl_msg_api_trace_only (void *the_msg)
495 api_main_t *am = &api_main;
497 msg_handler_internal (am, the_msg,
499 && am->rx_trace->enabled) /* trace_it */,
500 0 /* do_it */, 0 /* free_it */);
503 void vl_msg_api_cleanup_handler (void *the_msg)
505 api_main_t *am = &api_main;
506 u16 id = ntohs(*((u16 *)the_msg));
508 if (PREDICT_FALSE(id >= vec_len(am->msg_cleanup_handlers))) {
509 clib_warning ("_vl_msg_id too large: %d\n", id);
512 if (am->msg_cleanup_handlers[id])
513 (*am->msg_cleanup_handlers[id])(the_msg);
515 vl_msg_api_free(the_msg);
519 * vl_msg_api_replay_handler
521 void vl_msg_api_replay_handler(void *the_msg)
523 api_main_t *am = &api_main;
525 u16 id = ntohs(*((u16 *)the_msg));
527 if (PREDICT_FALSE(id >= vec_len(am->msg_handlers))) {
528 clib_warning ("_vl_msg_id too large: %d\n", id);
531 /* do NOT trace the message... */
532 if (am->msg_handlers[id])
533 (*am->msg_handlers[id])(the_msg);
534 /* do NOT free the message buffer... */
537 * vl_msg_api_socket_handler
539 void vl_msg_api_socket_handler(void *the_msg)
541 api_main_t *am = &api_main;
543 msg_handler_internal (am, the_msg,
545 && am->rx_trace->enabled) /* trace_it */,
546 1 /* do_it */, 0 /* free_it */);
549 #define foreach_msg_api_vector \
552 _(msg_cleanup_handlers) \
553 _(msg_endian_handlers) \
554 _(msg_print_handlers) \
559 void vl_msg_api_config (vl_msg_api_msg_config_t *c)
561 api_main_t *am = &api_main;
565 #define _(a) vec_validate (am->a, c->id);
566 foreach_msg_api_vector;
569 am->msg_names[c->id] = c->name;
570 am->msg_handlers[c->id] = c->handler;
571 am->msg_cleanup_handlers[c->id] = c->cleanup;
572 am->msg_endian_handlers[c->id] = c->endian;
573 am->msg_print_handlers[c->id] = c->print;
574 am->message_bounce[c->id] = c->message_bounce;
575 am->is_mp_safe[c->id] = c->is_mp_safe;
577 am->api_trace_cfg[c->id].size = c->size;
578 am->api_trace_cfg[c->id].trace_enable = c->traced;
579 am->api_trace_cfg[c->id].replay_enable = c->replay;
583 * vl_msg_api_set_handlers
584 * preserve the old API for a while
586 void vl_msg_api_set_handlers(int id, char *name, void *handler, void *cleanup,
587 void *endian, void *print, int size, int traced)
589 vl_msg_api_msg_config_t cfg;
590 vl_msg_api_msg_config_t *c = &cfg;
594 c->handler = handler;
595 c->cleanup = cleanup;
601 c->message_bounce = 0;
603 vl_msg_api_config (c);
606 void vl_msg_api_set_cleanup_handler(int msg_id, void *fp)
608 api_main_t *am = &api_main;
611 vec_validate(am->msg_cleanup_handlers, msg_id);
612 am->msg_cleanup_handlers[msg_id] = fp;
615 void vl_msg_api_queue_handler(unix_shared_memory_queue_t *q)
619 while (!unix_shared_memory_queue_sub(q, (u8 *)&msg, 0))
620 vl_msg_api_handler((void *)msg);
623 vl_api_trace_t *vl_msg_api_trace_get(api_main_t *am, vl_api_trace_which_t which)
627 case VL_API_TRACE_RX:
629 case VL_API_TRACE_TX:
636 void vl_noop_handler (void *mp) { }
639 vl_api_init (vlib_main_t *vm)
642 api_main_t *am = &api_main;
649 am->region_name = "/unset";
651 * Eventually passed to fchown, -1 => "current user"
652 * instead of 0 => "root". A very fine disctinction at best.
654 if (am->api_uid == 0)
656 if (am->api_gid == 0)
662 void vl_msg_api_custom_dump_configure (api_main_t *am) __attribute__((weak));
663 void vl_msg_api_custom_dump_configure (api_main_t *am) { }
665 VLIB_INIT_FUNCTION (vl_api_init);
667 static void vl_msg_api_process_file (vlib_main_t *vm, u8 *filename,
668 u32 first_index, u32 last_index,
669 vl_api_replay_t which)
671 vl_api_trace_file_header_t * hp;
676 u8 endian_swap_needed = 0;
677 api_main_t * am = &api_main;
680 void **saved_print_handlers = 0;
682 fd = open ((char *) filename, O_RDONLY);
685 vlib_cli_output (vm, "Couldn't open %s\n", filename);
689 if (fstat(fd, &statb) < 0) {
690 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
694 if (! (statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp))) {
695 vlib_cli_output (vm, "File not plausible: %s\n", filename);
699 file_size = statb.st_size;
700 file_size = (file_size + 4095) & ~(4096);
702 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
704 if (hp == (vl_api_trace_file_header_t *)MAP_FAILED) {
705 vlib_cli_output (vm, "mmap failed: %s\n", filename);
711 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
712 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
713 endian_swap_needed = 1;
715 if (endian_swap_needed)
716 nitems = ntohl(hp->nitems);
720 if (last_index == (u32) ~0) {
721 last_index = nitems - 1;
724 if (first_index >= nitems || last_index >= nitems) {
725 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
726 first_index, last_index, nitems-1);
731 "Note: wrapped/incomplete trace, results may vary\n");
733 if (which == CUSTOM_DUMP) {
734 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
735 vl_msg_api_custom_dump_configure (am);
741 for (i = 0; i < first_index; i++) {
746 if (clib_arch_is_little_endian)
747 msg_id = ntohs(*((u16 *)msg));
749 msg_id = *((u16 *)msg);
751 cfgp = am->api_trace_cfg + msg_id;
753 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
760 for (; i <= last_index; i++) {
767 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
769 if (clib_arch_is_little_endian)
770 msg_id = ntohs(*((u16 *)msg));
772 msg_id = *((u16 *)msg);
774 cfgp = am->api_trace_cfg + msg_id;
776 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
781 /* Copy the buffer (from the read-only mmap'ed file) */
782 vec_validate (tmpbuf, size-1 + sizeof(uword));
783 clib_memcpy (tmpbuf+sizeof(uword), msg, size);
784 memset (tmpbuf, 0xf, sizeof(uword));
787 * Endian swap if needed. All msg data is supposed to be
788 * in network byte order. All msg handlers are supposed to
789 * know that. The generic message dumpers don't know that.
790 * One could fix apigen, I suppose.
792 if ((which == DUMP && clib_arch_is_little_endian)
793 || endian_swap_needed) {
794 void (*endian_fp)(void *);
795 if (msg_id >= vec_len (am->msg_endian_handlers)
796 || (am->msg_endian_handlers[msg_id] == 0)) {
797 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
800 endian_fp = am->msg_endian_handlers[msg_id];
801 (*endian_fp)(tmpbuf+sizeof(uword));
804 /* msg_id always in network byte order */
805 if (clib_arch_is_little_endian) {
806 msg_idp = (u16 *)(tmpbuf+sizeof(uword));
813 if (msg_id < vec_len(am->msg_print_handlers) &&
814 am->msg_print_handlers [msg_id]) {
815 u8 *(*print_fp)(void *, void *);
817 print_fp = (void *)am->msg_print_handlers[msg_id];
818 (*print_fp)(tmpbuf+sizeof(uword), vm);
820 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
827 if (msg_id < vec_len(am->msg_print_handlers) &&
828 am->msg_print_handlers [msg_id]) {
831 u8 *(*print_fp)(void *, void *);
833 print_fp = (void *)am->msg_print_handlers[msg_id];
835 vlib_cli_output (vm, "/*");
837 (*print_fp)(tmpbuf+sizeof(uword), vm);
838 vlib_cli_output (vm, "*/\n");
840 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
841 am->msg_names[msg_id], i,
842 am->api_trace_cfg[msg_id].size);
844 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++) {
846 s = format (s, "\n ");
847 s = format (s, "0x%02x,", tmpbuf[sizeof(uword)+j]);
849 s = format (s, "\n};\n%c", 0);
850 vlib_cli_output (vm, (char *)s);
856 if (msg_id < vec_len(am->msg_print_handlers) &&
857 am->msg_print_handlers [msg_id] && cfgp->replay_enable) {
858 void (*handler)(void *);
860 handler = (void *)am->msg_handlers[msg_id];
862 if (!am->is_mp_safe[msg_id])
863 vl_msg_api_barrier_sync();
864 (*handler)(tmpbuf+sizeof(uword));
865 if (!am->is_mp_safe[msg_id])
866 vl_msg_api_barrier_release();
868 if (cfgp->replay_enable)
869 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
876 _vec_len(tmpbuf) = 0;
880 if (saved_print_handlers) {
881 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
882 vec_len(am->msg_print_handlers) * sizeof (void *));
883 vec_free (saved_print_handlers);
886 munmap (hp, file_size);
889 u8 * format_vl_msg_api_trace_status (u8 * s, va_list * args)
891 api_main_t * am = va_arg (*args, api_main_t *);
892 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
898 case VL_API_TRACE_TX:
900 trace_name = "TX trace";
903 case VL_API_TRACE_RX:
905 trace_name = "RX trace";
913 s = format (s, "%s: not yet configured.\n", trace_name);
917 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
918 trace_name, vec_len (tp->traces), tp->nitems,
919 tp->enabled ? "is" : "is not",
920 tp->wrapped ? "has" : "has not");
924 static u8 post_mortem_dump_enabled;
926 static clib_error_t *
927 api_trace_command_fn (vlib_main_t * vm,
928 unformat_input_t * input,
929 vlib_cli_command_t * cmd)
931 u32 nitems = 256<<10;
932 api_main_t * am = &api_main;
933 vl_api_trace_which_t which = VL_API_TRACE_RX;
940 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
941 if (unformat (input, "on") || unformat (input, "enable")) {
942 if (unformat (input, "nitems %d", &nitems))
944 vl_msg_api_trace_configure (am, which, nitems);
945 vl_msg_api_trace_onoff (am, which, 1 /* on */);
946 } else if (unformat (input, "off")) {
947 vl_msg_api_trace_onoff (am, which, 0);
948 } else if (unformat (input, "save %s", &filename)) {
949 u8 * chroot_filename;
950 if (strstr((char *)filename, "..")
951 || index((char *)filename, '/'))
953 vlib_cli_output (vm, "illegal characters in filename '%s'",
958 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
962 fp = fopen ((char *)chroot_filename, "w");
964 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
967 rv = vl_msg_api_trace_save (am, which, fp);
970 vlib_cli_output (vm, "ERROR: %d", rv);
972 vlib_cli_output (vm, "API trace saved to %s\n",
974 vec_free (chroot_filename);
975 } else if (unformat (input, "dump %s", &filename)) {
976 vl_msg_api_process_file (vm, filename, first, last, DUMP);
977 } else if (unformat (input, "custom-dump %s", &filename)) {
978 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
979 } else if (unformat (input, "replay %s", &filename)) {
980 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
981 } else if (unformat (input, "initializers %s", &filename)) {
982 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
983 } else if (unformat (input, "tx")) {
984 which = VL_API_TRACE_TX;
985 } else if (unformat (input, "first %d", &first)) {
987 } else if (unformat (input, "last %d", &last)) {
989 } else if (unformat (input, "status")) {
990 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
992 } else if (unformat (input, "free")) {
993 vl_msg_api_trace_onoff (am, which, 0);
994 vl_msg_api_trace_free (am, which);
995 } else if (unformat (input, "post-mortem-on"))
996 post_mortem_dump_enabled = 1;
997 else if (unformat (input, "post-mortem-off"))
998 post_mortem_dump_enabled = 0;
1000 return clib_error_return (0, "unknown input `%U'",
1001 format_unformat_error, input);
1006 VLIB_CLI_COMMAND (api_trace_command, static) = {
1007 .path = "api trace",
1009 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1010 .function = api_trace_command_fn,
1013 static clib_error_t *
1014 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1016 u32 nitems = 256<<10;
1017 vl_api_trace_which_t which = VL_API_TRACE_RX;
1018 api_main_t * am = &api_main;
1020 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1021 if (unformat (input, "on") || unformat (input, "enable")) {
1022 if (unformat (input, "nitems %d", &nitems))
1024 vl_msg_api_trace_configure (am, which, nitems);
1025 vl_msg_api_trace_onoff (am, which, 1 /* on */);
1026 post_mortem_dump_enabled = 1;
1028 return clib_error_return (0, "unknown input `%U'",
1029 format_unformat_error, input);
1034 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1036 void vl_msg_api_post_mortem_dump (void)
1038 api_main_t * am = &api_main;
1043 if (post_mortem_dump_enabled == 0)
1046 snprintf (filename, sizeof(filename), "/tmp/api_post_mortem.%d",
1049 fp = fopen (filename, "w");
1051 rv = write (2, "Couldn't create ", 16);
1052 rv = write (2, filename, strlen(filename));
1053 rv = write (2, "\n", 1);
1056 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1059 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1060 rv = write (2, filename, strlen(filename));
1061 rv = write (2, "\n", 1);
1066 /* Layered message handling support */
1068 void vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1070 api_main_t * am = &api_main;
1072 /* Mild idiot proofing */
1073 if (msg_id_host_byte_order > 10000)
1074 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1075 msg_id_host_byte_order,
1076 clib_net_to_host_u16 (msg_id_host_byte_order));
1077 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1078 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1081 int vl_msg_api_pd_handler (void *mp, int rv)
1083 api_main_t * am = &api_main;
1084 int (*fp)(void *, int);
1087 if (clib_arch_is_little_endian)
1088 msg_id = clib_net_to_host_u16(*((u16 *)mp));
1090 msg_id = *((u16 *)mp);
1092 if (msg_id >= vec_len (am->pd_msg_handlers)
1093 || am->pd_msg_handlers[msg_id] == 0)
1096 fp = am->pd_msg_handlers [msg_id];
1101 void vl_msg_api_set_first_available_msg_id (u16 first_avail)
1103 api_main_t * am = &api_main;
1105 am->first_available_msg_id = first_avail;
1108 u16 vl_msg_api_get_msg_ids (char * name, int n)
1110 api_main_t * am = &api_main;
1112 vl_api_msg_range_t * rp;
1116 if (am->msg_range_by_name == 0)
1117 am->msg_range_by_name = hash_create_string (0, sizeof(uword));
1119 name_copy = format (0, "%s%c", name, 0);
1121 p = hash_get_mem (am->msg_range_by_name, name_copy);
1123 clib_warning ("WARNING: duplicate message range registration for '%s'",
1125 vec_free(name_copy);
1129 if (n < 0 || n > 1024) {
1131 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1133 vec_free(name_copy);
1137 vec_add2 (am->msg_ranges, rp, 1);
1139 rv = rp->first_msg_id = am->first_available_msg_id;
1140 am->first_available_msg_id += n;
1141 rp->last_msg_id = am->first_available_msg_id - 1;
1142 rp->name = name_copy;
1144 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);