Initial commit of vpp code.
[vpp.git] / vlib-api / vlibapi / api_shared.c
1 /* 
2  *------------------------------------------------------------------
3  * api_shared.c - API message handling, common code for both clients
4  * and the vlib process itself.
5  * 
6  *
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:
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
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  *------------------------------------------------------------------
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.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>
37
38 api_main_t api_main;
39
40 void vl_msg_api_barrier_sync(void) __attribute__((weak));
41 void vl_msg_api_barrier_sync(void) { }
42
43 void vl_msg_api_barrier_release(void) __attribute__((weak));
44 void vl_msg_api_barrier_release(void) { }
45
46 void vl_msg_api_increment_missing_client_counter(void)
47 {
48     api_main_t * am = &api_main;
49     am->missing_clients++;
50 }
51
52 typedef enum {
53     DUMP, 
54     CUSTOM_DUMP,
55     REPLAY,
56     INITIALIZERS,
57 } vl_api_replay_t;
58
59 int vl_msg_api_rx_trace_enabled(api_main_t *am)
60 {
61     return (am->rx_trace && am->rx_trace->enabled);
62 }
63
64 int vl_msg_api_tx_trace_enabled(api_main_t *am)
65 {
66     return (am->tx_trace && am->tx_trace->enabled);
67 }
68
69 /*
70  * vl_msg_api_trace
71  */
72 void vl_msg_api_trace(api_main_t *am, vl_api_trace_t *tp, void *msg)
73 {
74     u8 **this_trace;
75     u8 **old_trace;
76     u8 *msg_copy;
77     trace_cfg_t *cfgp;
78     u16 msg_id = ntohs(*((u16 *)msg));
79
80     cfgp = am->api_trace_cfg + msg_id;
81
82     if (!cfgp || !cfgp->trace_enable)
83         return;
84
85     msg_copy = 0;
86
87     if (tp->nitems == 0) {
88         clib_warning ("tp->nitems is 0");
89         return;
90     }
91
92     if (vec_len(tp->traces) < tp->nitems) {
93         vec_add1(tp->traces, 0);
94         this_trace = tp->traces + vec_len(tp->traces) - 1;
95     } else {
96         tp->wrapped = 1;
97         old_trace = tp->traces + tp->curindex++;
98         if (tp->curindex == tp->nitems)
99             tp->curindex = 0;
100         vec_free(*old_trace);
101         this_trace = old_trace;
102     }
103
104     vec_validate(msg_copy, cfgp->size - 1);
105     memcpy(msg_copy, msg, cfgp->size);
106     *this_trace = msg_copy;
107 }
108
109 int vl_msg_api_trace_onoff(api_main_t *am, vl_api_trace_which_t which, 
110                            int onoff)
111 {
112     vl_api_trace_t *tp;
113     int rv;
114
115     switch(which)
116     {
117     case VL_API_TRACE_TX:
118         tp = am->tx_trace;
119         if (tp == 0) {
120             vl_msg_api_trace_configure (am, which, 1024);
121             tp = am->tx_trace;
122         }
123         break;
124         
125     case VL_API_TRACE_RX:
126         tp = am->rx_trace;
127         if (tp == 0) {
128             vl_msg_api_trace_configure (am, which, 1024);
129             tp = am->rx_trace;
130         }
131         break;
132         
133     default:
134         /* duh? */
135         return -1;
136     }
137
138     /* Configured? */
139     if (tp == 0 || tp->nitems == 0)
140         return -1;
141
142     rv = tp->enabled;
143     tp->enabled = onoff;
144
145     return rv;
146 }
147
148 int vl_msg_api_trace_free(api_main_t *am, vl_api_trace_which_t which)
149 {
150     vl_api_trace_t *tp;
151     int i;
152
153     switch(which)
154     {
155     case VL_API_TRACE_TX:
156         tp = am->tx_trace;
157         break;
158         
159     case VL_API_TRACE_RX:
160         tp = am->rx_trace;
161         break;
162         
163     default:
164         /* duh? */
165         return -1;
166     }
167
168     /* Configured? */
169     if (!tp || tp->nitems == 0)
170         return -1;
171
172     tp->curindex = 0;
173     tp->wrapped = 0;
174
175     for (i = 0; i < vec_len(tp->traces); i++) {
176         vec_free(tp->traces[i]);
177     }
178     vec_free(tp->traces);
179
180     return 0;
181 }
182
183 int vl_msg_api_trace_save(api_main_t *am, 
184                           vl_api_trace_which_t which, FILE *fp)
185 {
186     vl_api_trace_t *tp;
187     vl_api_trace_file_header_t fh;
188     int i;
189     u8 *msg;
190
191     switch(which)
192     {
193     case VL_API_TRACE_TX:
194         tp = am->tx_trace;
195         break;
196         
197     case VL_API_TRACE_RX:
198         tp = am->rx_trace;
199         break;
200         
201     default:
202         /* duh? */
203         return -1;
204     }
205
206     /* Configured, data present? */
207     if (tp == 0 || tp->nitems == 0 || vec_len(tp->traces) == 0)
208         return -1;
209
210     /* "Dare to be stupid" check */
211     if (fp == 0) {
212         return -2;
213     }
214
215     /* Write the file header */
216     fh.nitems = vec_len(tp->traces);
217     fh.endian = tp->endian;
218     fh.wrapped = tp->wrapped;
219
220     if (fwrite(&fh, sizeof(fh), 1, fp) != 1) {
221         return (-10);
222     }
223
224     /* No-wrap case */
225     if (tp->wrapped == 0) {
226         /*
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. 
231          */
232         for (i = 0; i < vec_len(tp->traces); i++) {
233             /*sa_ignore NO_NULL_CHK*/
234             msg = tp->traces[i];
235             /*
236              * This retarded check required to pass
237              * [sic] SA-checking. 
238              */
239             if (!msg)
240                 continue;
241             if (fwrite(msg, 1, vec_len(msg), fp) != vec_len(msg)) {
242                 return (-11);
243             }
244         }
245     } else {                    
246         /* Wrap case: write oldest -> end of buffer */
247         for (i = tp->curindex; i < vec_len(tp->traces); i++) {
248             msg = tp->traces[i];
249             /*
250              * This retarded check required to pass
251              * [sic] SA-checking 
252              */
253             if (!msg)
254                 continue;
255
256             if (fwrite(msg, 1, vec_len(msg), fp) != vec_len(msg)) {
257                 return (-12);
258             }
259         }
260         /* write beginning of buffer -> oldest-1 */
261         for (i = 0; i < tp->curindex; i++) {
262             /*sa_ignore NO_NULL_CHK*/
263             msg = tp->traces[i];
264             /*
265              * This retarded check required to pass
266              * [sic] SA-checking 
267              */
268             if (!msg)
269                 continue;
270
271             if (fwrite(msg, 1, vec_len(msg), fp) != vec_len(msg)) {
272                 return (-13);
273             }
274         }
275     }
276     return 0;
277 }
278
279 int vl_msg_api_trace_configure(api_main_t *am, vl_api_trace_which_t which, 
280                                u32 nitems)
281 {
282     vl_api_trace_t *tp;
283     int was_on = 0;
284
285     switch(which)
286     {
287     case VL_API_TRACE_TX:
288         tp = am->tx_trace;
289         if (tp == 0) {
290             vec_validate(am->tx_trace, 0);
291             tp = am->tx_trace;
292         }
293         break;
294         
295     case VL_API_TRACE_RX:
296         tp = am->rx_trace;
297         if (tp == 0) {
298             vec_validate(am->rx_trace, 0);
299             tp = am->rx_trace;
300         }
301
302         break;
303
304     default:
305         return -1;
306
307     }
308
309     if (tp->enabled) {
310         was_on = vl_msg_api_trace_onoff(am, which, 0);
311     }
312     if (tp->traces) {
313         vl_msg_api_trace_free(am, which);
314     }
315
316     memset(tp, 0, sizeof(*tp));
317
318     if (clib_arch_is_big_endian) {
319         tp->endian = VL_API_BIG_ENDIAN;
320     } else {
321         tp->endian = VL_API_LITTLE_ENDIAN;
322     }
323
324     tp->nitems = nitems;
325     if (was_on) {
326         (void)vl_msg_api_trace_onoff(am, which, was_on);
327     }
328     return 0;
329 }
330
331 always_inline void msg_handler_internal (api_main_t *am, 
332                                          void *the_msg, 
333                                          int trace_it,
334                                          int do_it, 
335                                          int free_it)
336 {
337     u16 id = ntohs(*((u16 *)the_msg));
338     u8 *(*print_fp)(void *, void *);
339
340     if (id < vec_len(am->msg_handlers) && 
341         am->msg_handlers[id]) {
342         if (trace_it)
343             vl_msg_api_trace(am, am->rx_trace, the_msg);
344         
345         if (am->msg_print_flag) {
346             fformat (stdout, "[%d]: %s\n", id, 
347                      am->msg_names[id]);
348             print_fp = (void *)am->msg_print_handlers[id];
349             if (print_fp == 0) {
350                 fformat(stdout, "  [no registered print fn]\n");
351             } else {
352                 (*print_fp)(the_msg, stdout);
353             }
354         }
355
356         if (do_it) {
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();
362         }
363     } else {
364         clib_warning("no handler for msg id %d", id);
365     }
366
367     if (free_it) 
368         vl_msg_api_free(the_msg);
369 }
370
371 /* set to 1 if you want before/after message handler event logging */
372 #define ELOG_API_MESSAGE_HANDLERS 0
373
374 #if ELOG_API_MESSAGE_HANDLERS > 0
375 static u32 elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
376 {
377   uword * p, r;
378   static uword * h;
379   u8 *name_copy;
380
381   if (! h)
382       h = hash_create_string (0, sizeof (uword));
383
384   p = hash_get_mem (h, msg_name);
385   if (p)
386     return p[0];
387   r = elog_string (&vm->elog_main, "%s", msg_name);
388
389   name_copy = format (0, "%s%c", msg_name, 0);
390
391   hash_set_mem (h, name_copy, r);
392
393   return r;
394 }
395 #endif
396
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)
401 {
402   u16 id = ntohs(*((u16 *)the_msg));
403   u8 *(*handler)(void *, void *, void *);
404     
405 #if ELOG_API_MESSAGE_HANDLERS > 0
406     {
407       ELOG_TYPE_DECLARE (e) = {
408         .format = "api-msg: %s",
409         .format_args = "T4",
410       };
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]);
415       else
416         ed->c = elog_id_for_msg_name (vm, "BOGUS");
417     }
418 #endif    
419
420   if (id < vec_len(am->msg_handlers) && 
421       am->msg_handlers[id]) {
422     handler = (void *)am->msg_handlers[id];
423
424     if (am->rx_trace && am->rx_trace->enabled)
425       vl_msg_api_trace(am, am->rx_trace, the_msg);
426
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();
432   } else {
433     clib_warning("no hander for msg id %d", id);
434   }
435   /* 
436    * Special-case, so we can e.g. bounce messages off the vnet
437    * main thread without copying them...
438    */
439   if (!(am->message_bounce[id]))
440     vl_msg_api_free(the_msg);
441
442 #if ELOG_API_MESSAGE_HANDLERS > 0
443     {
444       ELOG_TYPE_DECLARE (e) = {
445         .format = "api-msg-done: %s",
446         .format_args = "T4",
447       };
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]);
452       else
453         ed->c = elog_id_for_msg_name (vm, "BOGUS");
454     }
455 #endif
456 }
457
458 void vl_msg_api_handler (void *the_msg)
459 {
460     api_main_t *am = &api_main;
461
462     msg_handler_internal (am, the_msg, 
463                           (am->rx_trace 
464                            && am->rx_trace->enabled) /* trace_it */, 
465                           1 /* do_it */, 1 /* free_it */);
466 }
467
468 void vl_msg_api_handler_no_free (void *the_msg)
469 {
470     api_main_t *am = &api_main;
471     msg_handler_internal (am, the_msg, 
472                           (am->rx_trace 
473                            && am->rx_trace->enabled) /* trace_it */, 
474                           1 /* do_it */, 0 /* free_it */);
475 }
476
477 void vl_msg_api_handler_no_trace_no_free (void *the_msg)
478 {
479     api_main_t *am = &api_main;
480     msg_handler_internal (am, the_msg, 0/* trace_it */, 1 /* do_it */, 
481                           0 /* free_it */);
482 }
483
484 /*
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.
491  *
492  */
493 void vl_msg_api_trace_only (void *the_msg)
494 {
495     api_main_t *am = &api_main;
496
497     msg_handler_internal (am, the_msg, 
498                           (am->rx_trace 
499                            && am->rx_trace->enabled) /* trace_it */,
500                           0 /* do_it */, 0 /* free_it */);
501 }
502
503 void vl_msg_api_cleanup_handler (void *the_msg)
504 {
505     api_main_t *am = &api_main;
506     u16 id = ntohs(*((u16 *)the_msg));
507
508     if (PREDICT_FALSE(id >= vec_len(am->msg_cleanup_handlers))) {
509         clib_warning ("_vl_msg_id too large: %d\n", id);
510         return;
511     }
512     if (am->msg_cleanup_handlers[id])
513         (*am->msg_cleanup_handlers[id])(the_msg);
514
515     vl_msg_api_free(the_msg);
516 }
517
518 /*
519  * vl_msg_api_replay_handler
520  */
521 void vl_msg_api_replay_handler(void *the_msg)
522 {
523     api_main_t *am = &api_main;
524
525     u16 id = ntohs(*((u16 *)the_msg));
526
527     if (PREDICT_FALSE(id >= vec_len(am->msg_handlers))) {
528         clib_warning ("_vl_msg_id too large: %d\n", id);
529         return;
530     }
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... */
535 }
536 /*
537  * vl_msg_api_socket_handler
538  */
539 void vl_msg_api_socket_handler(void *the_msg)
540 {
541     api_main_t *am = &api_main;
542
543     msg_handler_internal (am, the_msg, 
544                           (am->rx_trace 
545                            && am->rx_trace->enabled) /* trace_it */,
546                           1 /* do_it */, 0 /* free_it */);
547 }
548
549 #define foreach_msg_api_vector                  \
550 _(msg_names)                                    \
551 _(msg_handlers)                                 \
552 _(msg_cleanup_handlers)                         \
553 _(msg_endian_handlers)                          \
554 _(msg_print_handlers)                           \
555 _(api_trace_cfg)                                \
556 _(message_bounce)                               \
557 _(is_mp_safe)
558
559 void vl_msg_api_config (vl_msg_api_msg_config_t *c)
560 {
561     api_main_t *am = &api_main;
562
563     ASSERT(c->id > 0);
564
565 #define _(a) vec_validate (am->a, c->id);
566     foreach_msg_api_vector;
567 #undef _
568
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;
576
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;
580 }
581
582 /* 
583  * vl_msg_api_set_handlers
584  * preserve the old API for a while
585  */
586 void vl_msg_api_set_handlers(int id, char *name, void *handler, void *cleanup,
587                              void *endian, void *print, int size, int traced)
588 {
589     vl_msg_api_msg_config_t cfg;
590     vl_msg_api_msg_config_t *c = &cfg;
591
592     c->id = id;
593     c->name = name;
594     c->handler = handler;
595     c->cleanup = cleanup;
596     c->endian = endian;
597     c->print = print;
598     c->size = size;
599     c->traced = traced;
600     c->replay = 1;
601     c->message_bounce = 0;
602     c->is_mp_safe = 0;
603     vl_msg_api_config (c);
604 }
605
606 void vl_msg_api_set_cleanup_handler(int msg_id, void *fp)
607 {
608     api_main_t *am = &api_main;
609     ASSERT(msg_id > 0);
610
611     vec_validate(am->msg_cleanup_handlers, msg_id);
612     am->msg_cleanup_handlers[msg_id] = fp;
613 }
614
615 void vl_msg_api_queue_handler(unix_shared_memory_queue_t *q)
616 {
617     uword msg;
618
619     while (!unix_shared_memory_queue_sub(q, (u8 *)&msg, 0))
620         vl_msg_api_handler((void *)msg);
621 }
622
623 vl_api_trace_t *vl_msg_api_trace_get(api_main_t *am, vl_api_trace_which_t which)
624 {
625     switch(which)
626     {
627     case VL_API_TRACE_RX:
628         return am->rx_trace;
629     case VL_API_TRACE_TX:
630         return am->tx_trace;
631     default:
632         return 0;
633     }
634 }
635
636 void vl_noop_handler (void *mp) { }
637
638 clib_error_t *
639 vl_api_init (vlib_main_t *vm)
640 {
641     static u8 once;
642     api_main_t *am = &api_main;
643
644     if (once)
645         return 0;
646     
647     once = 1;
648
649     am->region_name = "/unset";
650
651     return (0);
652 }
653
654 void vl_msg_api_custom_dump_configure (api_main_t *am) __attribute__((weak));
655 void vl_msg_api_custom_dump_configure (api_main_t *am) { }
656
657 VLIB_INIT_FUNCTION (vl_api_init);
658
659 static void vl_msg_api_process_file (vlib_main_t *vm, u8 *filename, 
660                                      u32 first_index, u32 last_index, 
661                                      vl_api_replay_t which)
662 {
663     vl_api_trace_file_header_t * hp;
664     int i, fd;
665     struct stat statb;
666     size_t file_size;
667     u8 *msg;
668     u8 endian_swap_needed = 0;
669     api_main_t * am = &api_main;
670     static u8 *tmpbuf;
671     u32 nitems;
672     void **saved_print_handlers = 0;
673
674     fd = open ((char *) filename, O_RDONLY);
675
676     if (fd < 0) {
677         vlib_cli_output (vm, "Couldn't open %s\n", filename);
678         return;
679     }
680
681     if (fstat(fd, &statb) < 0) {
682         vlib_cli_output (vm, "Couldn't stat %s\n", filename);
683         return;
684     }
685
686     if (! (statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp))) {
687         vlib_cli_output (vm, "File not plausible: %s\n", filename);
688         return;
689     }
690
691     file_size = statb.st_size;
692     file_size = (file_size + 4095) & ~(4096);
693
694     hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
695
696     if (hp == (vl_api_trace_file_header_t *)MAP_FAILED) {
697         vlib_cli_output (vm, "mmap failed: %s\n", filename);
698         close(fd);
699         return;
700     }
701     close(fd);
702
703     if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
704         || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
705         endian_swap_needed = 1;
706     
707     if (endian_swap_needed)
708         nitems = ntohl(hp->nitems);
709     else
710         nitems = hp->nitems;
711
712     if (last_index == (u32) ~0) {
713         last_index = nitems - 1;
714     }
715     
716     if (first_index >= nitems || last_index >= nitems) {
717         vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
718                          first_index, last_index, nitems-1);
719         return;
720     }
721     if (hp->wrapped)
722         vlib_cli_output (vm, 
723                          "Note: wrapped/incomplete trace, results may vary\n");
724     
725     if (which == CUSTOM_DUMP) {
726         saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
727         vl_msg_api_custom_dump_configure (am);
728     }
729
730
731     msg = (u8 *)(hp+1);
732     
733     for (i = 0; i < first_index; i++) {
734         trace_cfg_t *cfgp;
735         int size;
736         u16 msg_id;
737         
738         if (clib_arch_is_little_endian)
739             msg_id = ntohs(*((u16 *)msg));
740         else
741             msg_id = *((u16 *)msg);
742         
743         cfgp = am->api_trace_cfg + msg_id;
744         if (!cfgp) {
745             vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
746             return;
747         }
748         size = cfgp->size;
749         msg += size;
750     }
751     
752     for (; i <= last_index; i++) {
753         trace_cfg_t *cfgp;
754         u16 *msg_idp;
755         u16 msg_id;
756         int size;
757         
758         if (which == DUMP)
759             vlib_cli_output (vm, "---------- trace %d -----------\n", i);
760
761         if (clib_arch_is_little_endian)
762             msg_id = ntohs(*((u16 *)msg));
763         else
764             msg_id = *((u16 *)msg);
765         
766         cfgp = am->api_trace_cfg + msg_id;
767         if (!cfgp) {
768             vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
769             return;
770         }
771         size = cfgp->size;
772
773         /* Copy the buffer (from the read-only mmap'ed file) */
774         vec_validate (tmpbuf, size-1 + sizeof(uword));
775         memcpy (tmpbuf+sizeof(uword), msg, size);
776         memset (tmpbuf, 0xf, sizeof(uword));
777
778         /* 
779          * Endian swap if needed. All msg data is supposed to be 
780          * in network byte order. All msg handlers are supposed to
781          * know that. The generic message dumpers don't know that.
782          * One could fix apigen, I suppose.
783          */
784         if ((which == DUMP && clib_arch_is_little_endian) 
785             || endian_swap_needed) {
786             void (*endian_fp)(void *);
787             if (msg_id >= vec_len (am->msg_endian_handlers)
788                 || (am->msg_endian_handlers[msg_id] == 0)) {
789                 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
790                 return;
791             }
792             endian_fp = am->msg_endian_handlers[msg_id];
793             (*endian_fp)(tmpbuf+sizeof(uword));
794         }
795
796         /* msg_id always in network byte order */
797         if (clib_arch_is_little_endian) {
798             msg_idp = (u16 *)(tmpbuf+sizeof(uword));
799             *msg_idp = msg_id;
800         }
801
802         switch (which) {
803         case CUSTOM_DUMP:
804         case DUMP:
805             if (msg_id < vec_len(am->msg_print_handlers) &&
806                 am->msg_print_handlers [msg_id]) {
807                 u8 *(*print_fp)(void *, void *);
808                 
809                 print_fp = (void *)am->msg_print_handlers[msg_id];
810                 (*print_fp)(tmpbuf+sizeof(uword), vm);
811             } else {
812                 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
813                                  msg_id);
814                 break;
815             }
816             break;
817
818         case INITIALIZERS:
819             if (msg_id < vec_len(am->msg_print_handlers) &&
820                 am->msg_print_handlers [msg_id]) {
821                 u8 * s;
822                 int j;
823                 u8 *(*print_fp)(void *, void *);
824
825                 print_fp = (void *)am->msg_print_handlers[msg_id];
826                 
827                 vlib_cli_output (vm, "/*");
828                 
829                 (*print_fp)(tmpbuf+sizeof(uword), vm);
830                 vlib_cli_output (vm, "*/\n");
831                 
832                 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
833                             am->msg_names[msg_id], i, 
834                             am->api_trace_cfg[msg_id].size);
835                 
836                 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++) {
837                     if ((j & 7) == 0)
838                         s = format (s, "\n    ");    
839                     s = format (s, "0x%02x,", tmpbuf[sizeof(uword)+j]);
840                 }
841                 s = format (s, "\n};\n%c", 0);
842                 vlib_cli_output (vm, (char *)s);
843                 vec_free(s);
844             }
845             break;
846                 
847         case REPLAY:
848             if (msg_id < vec_len(am->msg_print_handlers) &&
849                 am->msg_print_handlers [msg_id] && cfgp->replay_enable) {
850                 void (*handler)(void *);
851                 
852                 handler = (void *)am->msg_handlers[msg_id];
853
854                 if (!am->is_mp_safe[msg_id])
855                     vl_msg_api_barrier_sync();
856                 (*handler)(tmpbuf+sizeof(uword));
857                 if (!am->is_mp_safe[msg_id])
858                     vl_msg_api_barrier_release();
859             } else {
860                 if (cfgp->replay_enable)
861                     vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
862                                      msg_id);
863                 break;
864             }
865             break;
866         }
867
868         _vec_len(tmpbuf) = 0;
869         msg += size;
870     }
871     
872     if (saved_print_handlers) {
873         memcpy (am->msg_print_handlers, saved_print_handlers, 
874                 vec_len(am->msg_print_handlers) * sizeof (void *));
875         vec_free (saved_print_handlers);
876     }
877
878     munmap (hp, file_size);
879 }
880
881 u8 * format_vl_msg_api_trace_status (u8 * s, va_list * args)
882 {
883     api_main_t * am = va_arg (*args, api_main_t *);
884     vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
885     vl_api_trace_t *tp;
886     char *trace_name;
887
888     switch(which)
889     {
890     case VL_API_TRACE_TX:
891         tp = am->tx_trace;
892         trace_name = "TX trace";
893         break;
894         
895     case VL_API_TRACE_RX:
896         tp = am->rx_trace;
897         trace_name = "RX trace";
898         break;
899
900     default:
901         abort();
902     }
903
904     if (tp == 0) {
905         s = format (s, "%s: not yet configured.\n", trace_name);
906         return s;
907     }
908
909     s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
910                 trace_name, vec_len (tp->traces), tp->nitems, 
911                 tp->enabled ? "is" : "is not",
912                 tp->wrapped ? "has" : "has not");
913     return s;
914 }
915
916 static u8 post_mortem_dump_enabled;
917
918 static clib_error_t *
919 api_trace_command_fn (vlib_main_t * vm,
920                  unformat_input_t * input,
921                  vlib_cli_command_t * cmd)
922 {
923     u32 nitems = 256<<10;
924     api_main_t * am = &api_main;
925     vl_api_trace_which_t which = VL_API_TRACE_RX;
926     u8 *filename;
927     u32 first = 0;
928     u32 last = (u32)~0;
929     FILE *fp;
930     int rv;
931
932     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
933         if (unformat (input, "on") || unformat (input, "enable")) {
934             if (unformat (input, "nitems %d", &nitems))
935                 ;
936             vl_msg_api_trace_configure (am, which, nitems);
937             vl_msg_api_trace_onoff (am, which, 1 /* on */);
938         } else if (unformat (input, "off")) {
939             vl_msg_api_trace_onoff (am, which, 0);
940         } else if (unformat (input, "save %s", &filename)) {
941             u8 * chroot_filename;
942             if (strstr((char *)filename, "..") 
943                 || index((char *)filename, '/'))
944             {
945                 vlib_cli_output (vm, "illegal characters in filename '%s'", 
946                                  filename);
947                 return 0;
948             }
949
950             chroot_filename = format (0, "/tmp/%s%c", filename, 0);
951
952             vec_free(filename);
953             
954             fp = fopen ((char *)chroot_filename, "w");
955             if (fp == NULL) {
956                 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
957                 return 0;
958             }
959             rv = vl_msg_api_trace_save (am, which, fp);
960             fclose (fp);
961             if (rv < 0)
962                 vlib_cli_output (vm, "ERROR: %d", rv);
963             else
964                 vlib_cli_output (vm, "API trace saved to %s\n", 
965                                  chroot_filename);
966             vec_free (chroot_filename);
967         } else if (unformat (input, "dump %s", &filename)) {
968             vl_msg_api_process_file (vm, filename, first, last, DUMP);
969         } else if (unformat (input, "custom-dump %s", &filename)) {
970             vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
971         } else if (unformat (input, "replay %s", &filename)) {
972             vl_msg_api_process_file (vm, filename, first, last, REPLAY);
973         } else if (unformat (input, "initializers %s", &filename)) {
974             vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
975         } else if (unformat (input, "tx")) {
976             which = VL_API_TRACE_TX;
977         } else if (unformat (input, "first %d", &first)) {
978             ;
979         } else if (unformat (input, "last %d", &last)) {
980             ;
981         } else if (unformat (input, "status")) {
982             vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
983                              am, which);
984         } else if (unformat (input, "free")) {
985             vl_msg_api_trace_onoff (am, which, 0);
986             vl_msg_api_trace_free (am, which);
987         } else if (unformat (input, "post-mortem-on"))
988             post_mortem_dump_enabled = 1;
989         else if (unformat (input, "post-mortem-off"))        
990             post_mortem_dump_enabled = 0;
991         else
992             return clib_error_return (0, "unknown input `%U'",
993                                       format_unformat_error, input);
994     }
995     return 0;
996 }
997
998 VLIB_CLI_COMMAND (api_trace_command, static) = {
999     .path = "api trace",
1000     .short_help = 
1001     "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1002     .function = api_trace_command_fn,
1003 };
1004
1005 static clib_error_t *
1006 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1007 {
1008     u32 nitems = 256<<10;
1009     vl_api_trace_which_t which = VL_API_TRACE_RX;
1010     api_main_t * am = &api_main;
1011
1012     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1013         if (unformat (input, "on") || unformat (input, "enable")) {
1014             if (unformat (input, "nitems %d", &nitems))
1015                 ;
1016             vl_msg_api_trace_configure (am, which, nitems);
1017             vl_msg_api_trace_onoff (am, which, 1 /* on */);
1018             post_mortem_dump_enabled = 1;
1019         } else
1020             return clib_error_return (0, "unknown input `%U'",
1021                                       format_unformat_error, input);
1022     }
1023     return 0;
1024 }
1025
1026 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1027
1028 void vl_msg_api_post_mortem_dump (void)
1029 {
1030     api_main_t * am = &api_main;
1031     FILE *fp;
1032     char filename[64];
1033     int rv;
1034
1035     if (post_mortem_dump_enabled == 0)
1036         return;
1037
1038     snprintf (filename, sizeof(filename), "/tmp/api_post_mortem.%d",
1039               getpid());
1040
1041     fp = fopen (filename, "w");
1042     if (fp == NULL) {
1043         rv = write (2, "Couldn't create ", 16);
1044         rv = write (2, filename, strlen(filename));
1045         rv = write (2, "\n", 1);
1046         return;
1047     }
1048     rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1049     fclose (fp);
1050     if (rv < 0) {
1051         rv = write (2, "Failed to save post-mortem API trace to ", 40);
1052         rv = write (2, filename, strlen(filename));
1053         rv = write (2, "\n", 1);
1054     }
1055     
1056 }
1057
1058 /* Layered message handling support */
1059
1060 void vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1061 {
1062     api_main_t * am = &api_main;
1063
1064     /* Mild idiot proofing */
1065     if (msg_id_host_byte_order > 10000)
1066         clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1067                       msg_id_host_byte_order, 
1068                       clib_net_to_host_u16 (msg_id_host_byte_order));
1069     vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1070     am->pd_msg_handlers[msg_id_host_byte_order] = fp;
1071 }
1072
1073 int vl_msg_api_pd_handler (void *mp, int rv)
1074 {
1075     api_main_t * am = &api_main;
1076     int (*fp)(void *, int);
1077     u16 msg_id;
1078
1079     if (clib_arch_is_little_endian)
1080         msg_id = clib_net_to_host_u16(*((u16 *)mp));
1081     else
1082         msg_id = *((u16 *)mp);
1083     
1084     if (msg_id >= vec_len (am->pd_msg_handlers)
1085         || am->pd_msg_handlers[msg_id] == 0)
1086         return rv;
1087
1088     fp = am->pd_msg_handlers [msg_id];
1089     rv = (*fp)(mp, rv);
1090     return rv;
1091 }
1092
1093 void vl_msg_api_set_first_available_msg_id (u16 first_avail)
1094 {
1095     api_main_t * am = &api_main;
1096     
1097     am->first_available_msg_id = first_avail;
1098 }
1099
1100 u16 vl_msg_api_get_msg_ids (char * name, int n)
1101 {
1102     api_main_t * am = &api_main;
1103     u8 * name_copy;
1104     vl_api_msg_range_t * rp;
1105     uword * p;
1106     u16 rv;
1107
1108     if (am->msg_range_by_name == 0)
1109         am->msg_range_by_name = hash_create_string (0, sizeof(uword));
1110
1111     name_copy = format (0, "%s%c", name, 0);
1112     
1113     p = hash_get_mem (am->msg_range_by_name, name_copy);
1114     if (p) {
1115         clib_warning ("WARNING: duplicate message range registration for '%s'",
1116                       name_copy);
1117         vec_free(name_copy);
1118         return ((u16) ~0);
1119     }
1120
1121     if (n < 0 || n > 1024) {
1122         clib_warning 
1123             ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1124              n, name_copy);
1125         vec_free(name_copy);
1126         return ((u16) ~0);
1127     }
1128
1129     vec_add2 (am->msg_ranges, rp, 1);
1130
1131     rv = rp->first_msg_id = am->first_available_msg_id;
1132     am->first_available_msg_id += n;
1133     rp->last_msg_id = am->first_available_msg_id - 1;
1134     rp->name = name_copy;
1135
1136     hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1137
1138     return rv;
1139 }