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