6rd: Move to plugin
[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     clib_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      * Eventually passed to fchown, -1 => "current user" 
652      * instead of 0 => "root". A very fine disctinction at best.
653      */
654     if (am->api_uid == 0)
655         am->api_uid = -1;
656     if (am->api_gid == 0)
657         am->api_gid = -1;
658
659     return (0);
660 }
661
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) { }
664
665 VLIB_INIT_FUNCTION (vl_api_init);
666
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)
670 {
671     vl_api_trace_file_header_t * hp;
672     int i, fd;
673     struct stat statb;
674     size_t file_size;
675     u8 *msg;
676     u8 endian_swap_needed = 0;
677     api_main_t * am = &api_main;
678     static u8 *tmpbuf;
679     u32 nitems;
680     void **saved_print_handlers = 0;
681
682     fd = open ((char *) filename, O_RDONLY);
683
684     if (fd < 0) {
685         vlib_cli_output (vm, "Couldn't open %s\n", filename);
686         return;
687     }
688
689     if (fstat(fd, &statb) < 0) {
690         vlib_cli_output (vm, "Couldn't stat %s\n", filename);
691         return;
692     }
693
694     if (! (statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp))) {
695         vlib_cli_output (vm, "File not plausible: %s\n", filename);
696         return;
697     }
698
699     file_size = statb.st_size;
700     file_size = (file_size + 4095) & ~(4096);
701
702     hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
703
704     if (hp == (vl_api_trace_file_header_t *)MAP_FAILED) {
705         vlib_cli_output (vm, "mmap failed: %s\n", filename);
706         close(fd);
707         return;
708     }
709     close(fd);
710
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;
714     
715     if (endian_swap_needed)
716         nitems = ntohl(hp->nitems);
717     else
718         nitems = hp->nitems;
719
720     if (last_index == (u32) ~0) {
721         last_index = nitems - 1;
722     }
723     
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);
727         return;
728     }
729     if (hp->wrapped)
730         vlib_cli_output (vm, 
731                          "Note: wrapped/incomplete trace, results may vary\n");
732     
733     if (which == CUSTOM_DUMP) {
734         saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
735         vl_msg_api_custom_dump_configure (am);
736     }
737
738
739     msg = (u8 *)(hp+1);
740     
741     for (i = 0; i < first_index; i++) {
742         trace_cfg_t *cfgp;
743         int size;
744         u16 msg_id;
745         
746         if (clib_arch_is_little_endian)
747             msg_id = ntohs(*((u16 *)msg));
748         else
749             msg_id = *((u16 *)msg);
750         
751         cfgp = am->api_trace_cfg + msg_id;
752         if (!cfgp) {
753             vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
754             return;
755         }
756         size = cfgp->size;
757         msg += size;
758     }
759     
760     for (; i <= last_index; i++) {
761         trace_cfg_t *cfgp;
762         u16 *msg_idp;
763         u16 msg_id;
764         int size;
765         
766         if (which == DUMP)
767             vlib_cli_output (vm, "---------- trace %d -----------\n", i);
768
769         if (clib_arch_is_little_endian)
770             msg_id = ntohs(*((u16 *)msg));
771         else
772             msg_id = *((u16 *)msg);
773         
774         cfgp = am->api_trace_cfg + msg_id;
775         if (!cfgp) {
776             vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
777             return;
778         }
779         size = cfgp->size;
780
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));
785
786         /* 
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.
791          */
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);
798                 return;
799             }
800             endian_fp = am->msg_endian_handlers[msg_id];
801             (*endian_fp)(tmpbuf+sizeof(uword));
802         }
803
804         /* msg_id always in network byte order */
805         if (clib_arch_is_little_endian) {
806             msg_idp = (u16 *)(tmpbuf+sizeof(uword));
807             *msg_idp = msg_id;
808         }
809
810         switch (which) {
811         case CUSTOM_DUMP:
812         case DUMP:
813             if (msg_id < vec_len(am->msg_print_handlers) &&
814                 am->msg_print_handlers [msg_id]) {
815                 u8 *(*print_fp)(void *, void *);
816                 
817                 print_fp = (void *)am->msg_print_handlers[msg_id];
818                 (*print_fp)(tmpbuf+sizeof(uword), vm);
819             } else {
820                 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
821                                  msg_id);
822                 break;
823             }
824             break;
825
826         case INITIALIZERS:
827             if (msg_id < vec_len(am->msg_print_handlers) &&
828                 am->msg_print_handlers [msg_id]) {
829                 u8 * s;
830                 int j;
831                 u8 *(*print_fp)(void *, void *);
832
833                 print_fp = (void *)am->msg_print_handlers[msg_id];
834                 
835                 vlib_cli_output (vm, "/*");
836                 
837                 (*print_fp)(tmpbuf+sizeof(uword), vm);
838                 vlib_cli_output (vm, "*/\n");
839                 
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);
843                 
844                 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++) {
845                     if ((j & 7) == 0)
846                         s = format (s, "\n    ");    
847                     s = format (s, "0x%02x,", tmpbuf[sizeof(uword)+j]);
848                 }
849                 s = format (s, "\n};\n%c", 0);
850                 vlib_cli_output (vm, (char *)s);
851                 vec_free(s);
852             }
853             break;
854                 
855         case REPLAY:
856             if (msg_id < vec_len(am->msg_print_handlers) &&
857                 am->msg_print_handlers [msg_id] && cfgp->replay_enable) {
858                 void (*handler)(void *);
859                 
860                 handler = (void *)am->msg_handlers[msg_id];
861
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();
867             } else {
868                 if (cfgp->replay_enable)
869                     vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
870                                      msg_id);
871                 break;
872             }
873             break;
874         }
875
876         _vec_len(tmpbuf) = 0;
877         msg += size;
878     }
879     
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);
884     }
885
886     munmap (hp, file_size);
887 }
888
889 u8 * format_vl_msg_api_trace_status (u8 * s, va_list * args)
890 {
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);
893     vl_api_trace_t *tp;
894     char *trace_name;
895
896     switch(which)
897     {
898     case VL_API_TRACE_TX:
899         tp = am->tx_trace;
900         trace_name = "TX trace";
901         break;
902         
903     case VL_API_TRACE_RX:
904         tp = am->rx_trace;
905         trace_name = "RX trace";
906         break;
907
908     default:
909         abort();
910     }
911
912     if (tp == 0) {
913         s = format (s, "%s: not yet configured.\n", trace_name);
914         return s;
915     }
916
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");
921     return s;
922 }
923
924 static u8 post_mortem_dump_enabled;
925
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)
930 {
931     u32 nitems = 256<<10;
932     api_main_t * am = &api_main;
933     vl_api_trace_which_t which = VL_API_TRACE_RX;
934     u8 *filename;
935     u32 first = 0;
936     u32 last = (u32)~0;
937     FILE *fp;
938     int rv;
939
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))
943                 ;
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, '/'))
952             {
953                 vlib_cli_output (vm, "illegal characters in filename '%s'", 
954                                  filename);
955                 return 0;
956             }
957
958             chroot_filename = format (0, "/tmp/%s%c", filename, 0);
959
960             vec_free(filename);
961             
962             fp = fopen ((char *)chroot_filename, "w");
963             if (fp == NULL) {
964                 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
965                 return 0;
966             }
967             rv = vl_msg_api_trace_save (am, which, fp);
968             fclose (fp);
969             if (rv < 0)
970                 vlib_cli_output (vm, "ERROR: %d", rv);
971             else
972                 vlib_cli_output (vm, "API trace saved to %s\n", 
973                                  chroot_filename);
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)) {
986             ;
987         } else if (unformat (input, "last %d", &last)) {
988             ;
989         } else if (unformat (input, "status")) {
990             vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
991                              am, which);
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;
999         else
1000             return clib_error_return (0, "unknown input `%U'",
1001                                       format_unformat_error, input);
1002     }
1003     return 0;
1004 }
1005
1006 VLIB_CLI_COMMAND (api_trace_command, static) = {
1007     .path = "api trace",
1008     .short_help = 
1009     "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1010     .function = api_trace_command_fn,
1011 };
1012
1013 static clib_error_t *
1014 api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1015 {
1016     u32 nitems = 256<<10;
1017     vl_api_trace_which_t which = VL_API_TRACE_RX;
1018     api_main_t * am = &api_main;
1019
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))
1023                 ;
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;
1027         } else
1028             return clib_error_return (0, "unknown input `%U'",
1029                                       format_unformat_error, input);
1030     }
1031     return 0;
1032 }
1033
1034 VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1035
1036 void vl_msg_api_post_mortem_dump (void)
1037 {
1038     api_main_t * am = &api_main;
1039     FILE *fp;
1040     char filename[64];
1041     int rv;
1042
1043     if (post_mortem_dump_enabled == 0)
1044         return;
1045
1046     snprintf (filename, sizeof(filename), "/tmp/api_post_mortem.%d",
1047               getpid());
1048
1049     fp = fopen (filename, "w");
1050     if (fp == NULL) {
1051         rv = write (2, "Couldn't create ", 16);
1052         rv = write (2, filename, strlen(filename));
1053         rv = write (2, "\n", 1);
1054         return;
1055     }
1056     rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1057     fclose (fp);
1058     if (rv < 0) {
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);
1062     }
1063     
1064 }
1065
1066 /* Layered message handling support */
1067
1068 void vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
1069 {
1070     api_main_t * am = &api_main;
1071
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;
1079 }
1080
1081 int vl_msg_api_pd_handler (void *mp, int rv)
1082 {
1083     api_main_t * am = &api_main;
1084     int (*fp)(void *, int);
1085     u16 msg_id;
1086
1087     if (clib_arch_is_little_endian)
1088         msg_id = clib_net_to_host_u16(*((u16 *)mp));
1089     else
1090         msg_id = *((u16 *)mp);
1091     
1092     if (msg_id >= vec_len (am->pd_msg_handlers)
1093         || am->pd_msg_handlers[msg_id] == 0)
1094         return rv;
1095
1096     fp = am->pd_msg_handlers [msg_id];
1097     rv = (*fp)(mp, rv);
1098     return rv;
1099 }
1100
1101 void vl_msg_api_set_first_available_msg_id (u16 first_avail)
1102 {
1103     api_main_t * am = &api_main;
1104     
1105     am->first_available_msg_id = first_avail;
1106 }
1107
1108 u16 vl_msg_api_get_msg_ids (char * name, int n)
1109 {
1110     api_main_t * am = &api_main;
1111     u8 * name_copy;
1112     vl_api_msg_range_t * rp;
1113     uword * p;
1114     u16 rv;
1115
1116     if (am->msg_range_by_name == 0)
1117         am->msg_range_by_name = hash_create_string (0, sizeof(uword));
1118
1119     name_copy = format (0, "%s%c", name, 0);
1120     
1121     p = hash_get_mem (am->msg_range_by_name, name_copy);
1122     if (p) {
1123         clib_warning ("WARNING: duplicate message range registration for '%s'",
1124                       name_copy);
1125         vec_free(name_copy);
1126         return ((u16) ~0);
1127     }
1128
1129     if (n < 0 || n > 1024) {
1130         clib_warning 
1131             ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1132              n, name_copy);
1133         vec_free(name_copy);
1134         return ((u16) ~0);
1135     }
1136
1137     vec_add2 (am->msg_ranges, rp, 1);
1138
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;
1143
1144     hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1145
1146     return rv;
1147 }