api: enable binary API event logging in vat
[vpp.git] / src / 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 <stddef.h>
25 #include <string.h>
26 #include <vppinfra/format.h>
27 #include <vppinfra/byte_order.h>
28 #include <vppinfra/error.h>
29 #include <vlib/vlib.h>
30 #include <vlib/unix/unix.h>
31 #include <vlibapi/api.h>
32 #include <vppinfra/elog.h>
33
34 /* *INDENT-OFF* */
35 api_main_t api_main =
36   {
37     .region_name = "/unset",
38     .api_uid = -1,
39     .api_gid = -1,
40   };
41 /* *INDENT-ON* */
42
43 void
44 vl_msg_api_increment_missing_client_counter (void)
45 {
46   api_main_t *am = &api_main;
47   am->missing_clients++;
48 }
49
50 int
51 vl_msg_api_rx_trace_enabled (api_main_t * am)
52 {
53   return (am->rx_trace && am->rx_trace->enabled);
54 }
55
56 int
57 vl_msg_api_tx_trace_enabled (api_main_t * am)
58 {
59   return (am->tx_trace && am->tx_trace->enabled);
60 }
61
62 /*
63  * vl_msg_api_trace
64  */
65 void
66 vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg)
67 {
68   u8 **this_trace;
69   u8 **old_trace;
70   u8 *msg_copy;
71   u32 length;
72   trace_cfg_t *cfgp;
73   u16 msg_id = clib_net_to_host_u16 (*((u16 *) msg));
74   msgbuf_t *header = (msgbuf_t *) (((u8 *) msg) - offsetof (msgbuf_t, data));
75
76   cfgp = am->api_trace_cfg + msg_id;
77
78   if (!cfgp || !cfgp->trace_enable)
79     return;
80
81   msg_copy = 0;
82
83   if (tp->nitems == 0)
84     {
85       clib_warning ("tp->nitems is 0");
86       return;
87     }
88
89   if (vec_len (tp->traces) < tp->nitems)
90     {
91       vec_add1 (tp->traces, 0);
92       this_trace = tp->traces + vec_len (tp->traces) - 1;
93     }
94   else
95     {
96       tp->wrapped = 1;
97       old_trace = tp->traces + tp->curindex++;
98       if (tp->curindex == tp->nitems)
99         tp->curindex = 0;
100       /* Reuse the trace record, may save some memory allocator traffic */
101       msg_copy = *old_trace;
102       vec_reset_length (msg_copy);
103       this_trace = old_trace;
104     }
105
106   length = clib_net_to_host_u32 (header->data_len);
107
108   vec_validate (msg_copy, length - 1);
109   clib_memcpy_fast (msg_copy, msg, length);
110   *this_trace = msg_copy;
111 }
112
113 int
114 vl_msg_api_trace_onoff (api_main_t * am, vl_api_trace_which_t which,
115                         int onoff)
116 {
117   vl_api_trace_t *tp;
118   int rv;
119
120   switch (which)
121     {
122     case VL_API_TRACE_TX:
123       tp = am->tx_trace;
124       if (tp == 0)
125         {
126           vl_msg_api_trace_configure (am, which, 1024);
127           tp = am->tx_trace;
128         }
129       break;
130
131     case VL_API_TRACE_RX:
132       tp = am->rx_trace;
133       if (tp == 0)
134         {
135           vl_msg_api_trace_configure (am, which, 1024);
136           tp = am->rx_trace;
137         }
138       break;
139
140     default:
141       /* duh? */
142       return -1;
143     }
144
145   /* Configured? */
146   if (tp == 0 || tp->nitems == 0)
147     return -1;
148
149   rv = tp->enabled;
150   tp->enabled = onoff;
151
152   return rv;
153 }
154
155 int
156 vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which)
157 {
158   vl_api_trace_t *tp;
159   int i;
160
161   switch (which)
162     {
163     case VL_API_TRACE_TX:
164       tp = am->tx_trace;
165       break;
166
167     case VL_API_TRACE_RX:
168       tp = am->rx_trace;
169       break;
170
171     default:
172       /* duh? */
173       return -1;
174     }
175
176   /* Configured? */
177   if (!tp || tp->nitems == 0)
178     return -1;
179
180   tp->curindex = 0;
181   tp->wrapped = 0;
182
183   for (i = 0; i < vec_len (tp->traces); i++)
184     {
185       vec_free (tp->traces[i]);
186     }
187   vec_free (tp->traces);
188
189   return 0;
190 }
191
192 int
193 vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp)
194 {
195   vl_api_trace_t *tp;
196   vl_api_trace_file_header_t fh;
197   int i;
198   u8 *msg;
199
200   switch (which)
201     {
202     case VL_API_TRACE_TX:
203       tp = am->tx_trace;
204       break;
205
206     case VL_API_TRACE_RX:
207       tp = am->rx_trace;
208       break;
209
210     default:
211       /* duh? */
212       return -1;
213     }
214
215   /* Configured, data present? */
216   if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
217     return -1;
218
219   /* "Dare to be stupid" check */
220   if (fp == 0)
221     {
222       return -2;
223     }
224
225   /* Write the file header */
226   fh.nitems = vec_len (tp->traces);
227   fh.endian = tp->endian;
228   fh.wrapped = tp->wrapped;
229
230   if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
231     {
232       return (-10);
233     }
234
235   /* No-wrap case */
236   if (tp->wrapped == 0)
237     {
238       /*
239        * Note: vec_len return 0 when fed a NULL pointer.
240        * Unfortunately, the static analysis tool doesn't
241        * figure it out, hence the suppressed warnings.
242        * What a great use of my time.
243        */
244       for (i = 0; i < vec_len (tp->traces); i++)
245         {
246           u32 msg_length;
247           /*sa_ignore NO_NULL_CHK */
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           msg_length = clib_host_to_net_u32 (vec_len (msg));
257           if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
258               != sizeof (msg_length))
259             {
260               return (-14);
261             }
262           if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
263             {
264               return (-11);
265             }
266         }
267     }
268   else
269     {
270       /* Wrap case: write oldest -> end of buffer */
271       for (i = tp->curindex; i < vec_len (tp->traces); i++)
272         {
273           u32 msg_length;
274           msg = tp->traces[i];
275           /*
276            * This retarded check required to pass
277            * [sic] SA-checking
278            */
279           if (!msg)
280             continue;
281
282           msg_length = clib_host_to_net_u32 (vec_len (msg));
283           if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
284               != sizeof (msg_length))
285             {
286               return (-14);
287             }
288
289           if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
290             {
291               return (-12);
292             }
293         }
294       /* write beginning of buffer -> oldest-1 */
295       for (i = 0; i < tp->curindex; i++)
296         {
297           u32 msg_length;
298           /*sa_ignore NO_NULL_CHK */
299           msg = tp->traces[i];
300           /*
301            * This retarded check required to pass
302            * [sic] SA-checking
303            */
304           if (!msg)
305             continue;
306
307           msg_length = clib_host_to_net_u32 (vec_len (msg));
308           if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
309               != sizeof (msg_length))
310             {
311               return (-14);
312             }
313
314           if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
315             {
316               return (-13);
317             }
318         }
319     }
320   return 0;
321 }
322
323 int
324 vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
325                             u32 nitems)
326 {
327   vl_api_trace_t *tp;
328   int was_on = 0;
329
330   switch (which)
331     {
332     case VL_API_TRACE_TX:
333       tp = am->tx_trace;
334       if (tp == 0)
335         {
336           vec_validate (am->tx_trace, 0);
337           tp = am->tx_trace;
338         }
339       break;
340
341     case VL_API_TRACE_RX:
342       tp = am->rx_trace;
343       if (tp == 0)
344         {
345           vec_validate (am->rx_trace, 0);
346           tp = am->rx_trace;
347         }
348
349       break;
350
351     default:
352       return -1;
353
354     }
355
356   if (tp->enabled)
357     {
358       was_on = vl_msg_api_trace_onoff (am, which, 0);
359     }
360   if (tp->traces)
361     {
362       vl_msg_api_trace_free (am, which);
363     }
364
365   clib_memset (tp, 0, sizeof (*tp));
366
367   if (clib_arch_is_big_endian)
368     {
369       tp->endian = VL_API_BIG_ENDIAN;
370     }
371   else
372     {
373       tp->endian = VL_API_LITTLE_ENDIAN;
374     }
375
376   tp->nitems = nitems;
377   if (was_on)
378     {
379       (void) vl_msg_api_trace_onoff (am, which, was_on);
380     }
381   return 0;
382 }
383
384 void
385 vl_msg_api_barrier_sync (void)
386 {
387 }
388
389 void
390 vl_msg_api_barrier_release (void)
391 {
392 }
393
394 always_inline void
395 msg_handler_internal (api_main_t * am,
396                       void *the_msg, int trace_it, int do_it, int free_it)
397 {
398   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
399   u8 *(*print_fp) (void *, void *);
400
401   if (PREDICT_FALSE (am->elog_trace_api_messages))
402     {
403       /* *INDENT-OFF* */
404       ELOG_TYPE_DECLARE (e) =
405         {
406           .format = "api-msg: %s",
407           .format_args = "T4",
408         };
409       /* *INDENT-ON* */
410       struct
411       {
412         u32 c;
413       } *ed;
414       ed = ELOG_DATA (am->elog_main, e);
415       if (id < vec_len (am->msg_names))
416         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
417       else
418         ed->c = elog_string (am->elog_main, "BOGUS");
419     }
420
421   if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
422     {
423       if (trace_it)
424         vl_msg_api_trace (am, am->rx_trace, the_msg);
425
426       if (am->msg_print_flag)
427         {
428           fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
429           print_fp = (void *) am->msg_print_handlers[id];
430           if (print_fp == 0)
431             {
432               fformat (stdout, "  [no registered print fn]\n");
433             }
434           else
435             {
436               (*print_fp) (the_msg, stdout);
437             }
438         }
439
440       if (do_it)
441         {
442           if (!am->is_mp_safe[id])
443             {
444               vl_msg_api_barrier_trace_context (am->msg_names[id]);
445               vl_msg_api_barrier_sync ();
446             }
447           (*am->msg_handlers[id]) (the_msg);
448           if (!am->is_mp_safe[id])
449             vl_msg_api_barrier_release ();
450         }
451     }
452   else
453     {
454       clib_warning ("no handler for msg id %d", id);
455     }
456
457   if (free_it)
458     vl_msg_api_free (the_msg);
459
460   if (PREDICT_FALSE (am->elog_trace_api_messages))
461     {
462       /* *INDENT-OFF* */
463       ELOG_TYPE_DECLARE (e) =
464         {
465           .format = "api-msg-done(%s): %s",
466           .format_args = "t4T4",
467           .n_enum_strings = 2,
468           .enum_strings =
469           {
470             "barrier",
471             "mp-safe",
472           }
473         };
474       /* *INDENT-ON* */
475
476       struct
477       {
478         u32 barrier;
479         u32 c;
480       } *ed;
481       ed = ELOG_DATA (am->elog_main, e);
482       if (id < vec_len (am->msg_names))
483         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
484       else
485         ed->c = elog_string (am->elog_main, "BOGUS");
486       ed->barrier = !am->is_mp_safe[id];
487     }
488 }
489
490 /* This is only to be called from a vlib/vnet app */
491 void
492 vl_msg_api_handler_with_vm_node (api_main_t * am,
493                                  void *the_msg, vlib_main_t * vm,
494                                  vlib_node_runtime_t * node)
495 {
496   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
497   u8 *(*handler) (void *, void *, void *);
498   u8 *(*print_fp) (void *, void *);
499   int is_mp_safe = 1;
500
501   if (PREDICT_FALSE (am->elog_trace_api_messages))
502     {
503       /* *INDENT-OFF* */
504       ELOG_TYPE_DECLARE (e) =
505         {
506           .format = "api-msg: %s",
507           .format_args = "T4",
508         };
509       /* *INDENT-ON* */
510       struct
511       {
512         u32 c;
513       } *ed;
514       ed = ELOG_DATA (am->elog_main, e);
515       if (id < vec_len (am->msg_names))
516         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
517       else
518         ed->c = elog_string (am->elog_main, "BOGUS");
519     }
520
521   if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
522     {
523       handler = (void *) am->msg_handlers[id];
524
525       if (PREDICT_FALSE (am->rx_trace && am->rx_trace->enabled))
526         vl_msg_api_trace (am, am->rx_trace, the_msg);
527
528       if (PREDICT_FALSE (am->msg_print_flag))
529         {
530           fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
531           print_fp = (void *) am->msg_print_handlers[id];
532           if (print_fp == 0)
533             {
534               fformat (stdout, "  [no registered print fn for msg %d]\n", id);
535             }
536           else
537             {
538               (*print_fp) (the_msg, vm);
539             }
540         }
541       is_mp_safe = am->is_mp_safe[id];
542
543       if (!is_mp_safe)
544         {
545           vl_msg_api_barrier_trace_context (am->msg_names[id]);
546           vl_msg_api_barrier_sync ();
547         }
548       (*handler) (the_msg, vm, node);
549       if (!is_mp_safe)
550         vl_msg_api_barrier_release ();
551     }
552   else
553     {
554       clib_warning ("no handler for msg id %d", id);
555     }
556
557   /*
558    * Special-case, so we can e.g. bounce messages off the vnet
559    * main thread without copying them...
560    */
561   if (!(am->message_bounce[id]))
562     vl_msg_api_free (the_msg);
563
564   if (PREDICT_FALSE (am->elog_trace_api_messages))
565     {
566       /* *INDENT-OFF* */
567       ELOG_TYPE_DECLARE (e) =
568         {
569           .format = "api-msg-done(%s): %s",
570           .format_args = "t4T4",
571           .n_enum_strings = 2,
572           .enum_strings =
573           {
574             "barrier",
575             "mp-safe",
576           }
577         };
578       /* *INDENT-ON* */
579
580       struct
581       {
582         u32 barrier;
583         u32 c;
584       } *ed;
585       ed = ELOG_DATA (am->elog_main, e);
586       if (id < vec_len (am->msg_names))
587         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
588       else
589         ed->c = elog_string (am->elog_main, "BOGUS");
590       ed->barrier = is_mp_safe;
591     }
592 }
593
594 void
595 vl_msg_api_handler (void *the_msg)
596 {
597   api_main_t *am = &api_main;
598
599   msg_handler_internal (am, the_msg,
600                         (am->rx_trace
601                          && am->rx_trace->enabled) /* trace_it */ ,
602                         1 /* do_it */ , 1 /* free_it */ );
603 }
604
605 void
606 vl_msg_api_handler_no_free (void *the_msg)
607 {
608   api_main_t *am = &api_main;
609   msg_handler_internal (am, the_msg,
610                         (am->rx_trace
611                          && am->rx_trace->enabled) /* trace_it */ ,
612                         1 /* do_it */ , 0 /* free_it */ );
613 }
614
615 void
616 vl_msg_api_handler_no_trace_no_free (void *the_msg)
617 {
618   api_main_t *am = &api_main;
619   msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
620                         0 /* free_it */ );
621 }
622
623 /*
624  * Add a trace record to the API message trace buffer, if
625  * API message tracing is enabled. Handy for adding sufficient
626  * data to the trace to reproduce autonomous state, as opposed to
627  * state downloaded via control-plane API messages. Example: the NAT
628  * application creates database entries based on packet traffic, not
629  * control-plane messages.
630  *
631  */
632 void
633 vl_msg_api_trace_only (void *the_msg)
634 {
635   api_main_t *am = &api_main;
636
637   msg_handler_internal (am, the_msg,
638                         (am->rx_trace
639                          && am->rx_trace->enabled) /* trace_it */ ,
640                         0 /* do_it */ , 0 /* free_it */ );
641 }
642
643 void
644 vl_msg_api_cleanup_handler (void *the_msg)
645 {
646   api_main_t *am = &api_main;
647   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
648
649   if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
650     {
651       clib_warning ("_vl_msg_id too large: %d\n", id);
652       return;
653     }
654   if (am->msg_cleanup_handlers[id])
655     (*am->msg_cleanup_handlers[id]) (the_msg);
656
657   vl_msg_api_free (the_msg);
658 }
659
660 /*
661  * vl_msg_api_replay_handler
662  */
663 void
664 vl_msg_api_replay_handler (void *the_msg)
665 {
666   api_main_t *am = &api_main;
667
668   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
669
670   if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
671     {
672       clib_warning ("_vl_msg_id too large: %d\n", id);
673       return;
674     }
675   /* do NOT trace the message... */
676   if (am->msg_handlers[id])
677     (*am->msg_handlers[id]) (the_msg);
678   /* do NOT free the message buffer... */
679 }
680
681 u32
682 vl_msg_api_get_msg_length (void *msg_arg)
683 {
684   return vl_msg_api_get_msg_length_inline (msg_arg);
685 }
686
687 /*
688  * vl_msg_api_socket_handler
689  */
690 void
691 vl_msg_api_socket_handler (void *the_msg)
692 {
693   api_main_t *am = &api_main;
694
695   msg_handler_internal (am, the_msg,
696                         (am->rx_trace
697                          && am->rx_trace->enabled) /* trace_it */ ,
698                         1 /* do_it */ , 0 /* free_it */ );
699 }
700
701 #define foreach_msg_api_vector                  \
702 _(msg_names)                                    \
703 _(msg_handlers)                                 \
704 _(msg_cleanup_handlers)                         \
705 _(msg_endian_handlers)                          \
706 _(msg_print_handlers)                           \
707 _(api_trace_cfg)                                \
708 _(message_bounce)                               \
709 _(is_mp_safe)
710
711 void
712 vl_msg_api_config (vl_msg_api_msg_config_t * c)
713 {
714   api_main_t *am = &api_main;
715
716   /*
717    * This happens during the java core tests if the message
718    * dictionary is missing newly added xxx_reply_t messages.
719    * Should never happen, but since I shot myself in the foot once
720    * this way, I thought I'd make it easy to debug if I ever do
721    * it again... (;-)...
722    */
723   if (c->id == 0)
724     {
725       if (c->name)
726         clib_warning ("Trying to register %s with a NULL msg id!", c->name);
727       else
728         clib_warning ("Trying to register a NULL msg with a NULL msg id!");
729       clib_warning ("Did you forget to call setup_message_id_table?");
730       return;
731     }
732
733 #define _(a) vec_validate (am->a, c->id);
734   foreach_msg_api_vector;
735 #undef _
736
737   if (am->msg_handlers[c->id] && am->msg_handlers[c->id] != c->handler)
738     clib_warning
739       ("BUG: re-registering 'vl_api_%s_t_handler'."
740        "Handler was %llx, replaced by %llx",
741        c->name, am->msg_handlers[c->id], c->handler);
742
743   am->msg_names[c->id] = c->name;
744   am->msg_handlers[c->id] = c->handler;
745   am->msg_cleanup_handlers[c->id] = c->cleanup;
746   am->msg_endian_handlers[c->id] = c->endian;
747   am->msg_print_handlers[c->id] = c->print;
748   am->message_bounce[c->id] = c->message_bounce;
749   am->is_mp_safe[c->id] = c->is_mp_safe;
750
751   am->api_trace_cfg[c->id].size = c->size;
752   am->api_trace_cfg[c->id].trace_enable = c->traced;
753   am->api_trace_cfg[c->id].replay_enable = c->replay;
754 }
755
756 /*
757  * vl_msg_api_set_handlers
758  * preserve the old API for a while
759  */
760 void
761 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
762                          void *endian, void *print, int size, int traced)
763 {
764   vl_msg_api_msg_config_t cfg;
765   vl_msg_api_msg_config_t *c = &cfg;
766
767   clib_memset (c, 0, sizeof (*c));
768
769   c->id = id;
770   c->name = name;
771   c->handler = handler;
772   c->cleanup = cleanup;
773   c->endian = endian;
774   c->print = print;
775   c->traced = traced;
776   c->replay = 1;
777   c->message_bounce = 0;
778   c->is_mp_safe = 0;
779   vl_msg_api_config (c);
780 }
781
782 void
783 vl_msg_api_clean_handlers (int msg_id)
784 {
785   vl_msg_api_msg_config_t cfg;
786   vl_msg_api_msg_config_t *c = &cfg;
787
788   clib_memset (c, 0, sizeof (*c));
789
790   c->id = msg_id;
791   vl_msg_api_config (c);
792 }
793
794 void
795 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
796 {
797   api_main_t *am = &api_main;
798   ASSERT (msg_id > 0);
799
800   vec_validate (am->msg_cleanup_handlers, msg_id);
801   am->msg_cleanup_handlers[msg_id] = fp;
802 }
803
804 void
805 vl_msg_api_queue_handler (svm_queue_t * q)
806 {
807   uword msg;
808
809   while (!svm_queue_sub (q, (u8 *) & msg, SVM_Q_WAIT, 0))
810     vl_msg_api_handler ((void *) msg);
811 }
812
813 vl_api_trace_t *
814 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
815 {
816   switch (which)
817     {
818     case VL_API_TRACE_RX:
819       return am->rx_trace;
820     case VL_API_TRACE_TX:
821       return am->tx_trace;
822     default:
823       return 0;
824     }
825 }
826
827 void
828 vl_noop_handler (void *mp)
829 {
830 }
831
832
833 static u8 post_mortem_dump_enabled;
834
835 void
836 vl_msg_api_post_mortem_dump_enable_disable (int enable)
837 {
838   post_mortem_dump_enabled = enable;
839 }
840
841 void
842 vl_msg_api_post_mortem_dump (void)
843 {
844   api_main_t *am = &api_main;
845   FILE *fp;
846   char filename[64];
847   int rv;
848
849   if (post_mortem_dump_enabled == 0)
850     return;
851
852   snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
853             getpid ());
854
855   fp = fopen (filename, "w");
856   if (fp == NULL)
857     {
858       rv = write (2, "Couldn't create ", 16);
859       rv = write (2, filename, strlen (filename));
860       rv = write (2, "\n", 1);
861       return;
862     }
863   rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
864   fclose (fp);
865   if (rv < 0)
866     {
867       rv = write (2, "Failed to save post-mortem API trace to ", 40);
868       rv = write (2, filename, strlen (filename));
869       rv = write (2, "\n", 1);
870     }
871
872 }
873
874 /* Layered message handling support */
875
876 void
877 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
878 {
879   api_main_t *am = &api_main;
880
881   /* Mild idiot proofing */
882   if (msg_id_host_byte_order > 10000)
883     clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
884                   msg_id_host_byte_order,
885                   clib_net_to_host_u16 (msg_id_host_byte_order));
886   vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
887   am->pd_msg_handlers[msg_id_host_byte_order] = fp;
888 }
889
890 int
891 vl_msg_api_pd_handler (void *mp, int rv)
892 {
893   api_main_t *am = &api_main;
894   int (*fp) (void *, int);
895   u16 msg_id;
896
897   if (clib_arch_is_little_endian)
898     msg_id = clib_net_to_host_u16 (*((u16 *) mp));
899   else
900     msg_id = *((u16 *) mp);
901
902   if (msg_id >= vec_len (am->pd_msg_handlers)
903       || am->pd_msg_handlers[msg_id] == 0)
904     return rv;
905
906   fp = am->pd_msg_handlers[msg_id];
907   rv = (*fp) (mp, rv);
908   return rv;
909 }
910
911 void
912 vl_msg_api_set_first_available_msg_id (u16 first_avail)
913 {
914   api_main_t *am = &api_main;
915
916   am->first_available_msg_id = first_avail;
917 }
918
919 u16
920 vl_msg_api_get_msg_ids (const char *name, int n)
921 {
922   api_main_t *am = &api_main;
923   u8 *name_copy;
924   vl_api_msg_range_t *rp;
925   uword *p;
926   u16 rv;
927
928   if (am->msg_range_by_name == 0)
929     am->msg_range_by_name = hash_create_string (0, sizeof (uword));
930
931   name_copy = format (0, "%s%c", name, 0);
932
933   p = hash_get_mem (am->msg_range_by_name, name_copy);
934   if (p)
935     {
936       clib_warning ("WARNING: duplicate message range registration for '%s'",
937                     name_copy);
938       vec_free (name_copy);
939       return ((u16) ~ 0);
940     }
941
942   if (n < 0 || n > 1024)
943     {
944       clib_warning
945         ("WARNING: bad number of message-IDs (%d) requested by '%s'",
946          n, name_copy);
947       vec_free (name_copy);
948       return ((u16) ~ 0);
949     }
950
951   vec_add2 (am->msg_ranges, rp, 1);
952
953   rv = rp->first_msg_id = am->first_available_msg_id;
954   am->first_available_msg_id += n;
955   rp->last_msg_id = am->first_available_msg_id - 1;
956   rp->name = name_copy;
957
958   hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
959
960   return rv;
961 }
962
963 void
964 vl_msg_api_add_msg_name_crc (api_main_t * am, const char *string, u32 id)
965 {
966   uword *p;
967
968   if (am->msg_index_by_name_and_crc == 0)
969     am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
970
971   p = hash_get_mem (am->msg_index_by_name_and_crc, string);
972   if (p)
973     {
974       clib_warning ("attempt to redefine '%s' ignored...", string);
975       return;
976     }
977
978   hash_set_mem (am->msg_index_by_name_and_crc, string, id);
979 }
980
981 void
982 vl_msg_api_add_version (api_main_t * am, const char *string,
983                         u32 major, u32 minor, u32 patch)
984 {
985   api_version_t version = {.major = major,.minor = minor,.patch = patch };
986   ASSERT (strlen (string) < 64);
987   strncpy (version.name, string, 64 - 1);
988   vec_add1 (am->api_version_list, version);
989 }
990
991 u32
992 vl_msg_api_get_msg_index (u8 * name_and_crc)
993 {
994   api_main_t *am = &api_main;
995   uword *p;
996
997   if (am->msg_index_by_name_and_crc)
998     {
999       p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc);
1000       if (p)
1001         return p[0];
1002     }
1003   return ~0;
1004 }
1005
1006 void *
1007 vl_msg_push_heap (void)
1008 {
1009   api_main_t *am = &api_main;
1010   pthread_mutex_lock (&am->vlib_rp->mutex);
1011   return svm_push_data_heap (am->vlib_rp);
1012 }
1013
1014 void
1015 vl_msg_pop_heap (void *oldheap)
1016 {
1017   api_main_t *am = &api_main;
1018   svm_pop_heap (oldheap);
1019   pthread_mutex_unlock (&am->vlib_rp->mutex);
1020 }
1021
1022 int
1023 vl_api_to_api_string (u32 len, const char *buf, vl_api_string_t * str)
1024 {
1025   clib_memcpy_fast (str->buf, buf, len);
1026   str->length = htonl (len);
1027   return len + sizeof (u32);
1028 }
1029
1030 int
1031 vl_api_vec_to_api_string (const u8 * vec, vl_api_string_t * str)
1032 {
1033   u32 len = vec_len (vec);
1034   clib_memcpy (str->buf, vec, len);
1035   str->length = htonl (len);
1036   return len + sizeof (u32);
1037 }
1038
1039 /* Return a pointer to the API string (not nul terminated */
1040 u8 *
1041 vl_api_from_api_string (vl_api_string_t * astr)
1042 {
1043   return astr->buf;
1044 }
1045
1046 u32
1047 vl_api_string_len (vl_api_string_t * astr)
1048 {
1049   return clib_net_to_host_u32 (astr->length);
1050 }
1051
1052 /*
1053  * Returns a new vector. Remember to free it after use.
1054  */
1055 u8 *
1056 vl_api_from_api_to_vec (vl_api_string_t * astr)
1057 {
1058   u8 *v = 0;
1059   vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length));
1060   return v;
1061 }
1062
1063 void
1064 vl_api_set_elog_main (elog_main_t * m)
1065 {
1066   api_main_t *am = &api_main;
1067   am->elog_main = m;
1068 }
1069
1070 int
1071 vl_api_set_elog_trace_api_messages (int enable)
1072 {
1073   int rv;
1074   api_main_t *am = &api_main;
1075
1076   rv = am->elog_trace_api_messages;
1077   am->elog_trace_api_messages = enable;
1078   return rv;
1079 }
1080
1081 int
1082 vl_api_get_elog_trace_api_messages (void)
1083 {
1084   api_main_t *am = &api_main;
1085
1086   return am->elog_trace_api_messages;
1087 }
1088
1089 /*
1090  * fd.io coding-style-patch-verification: ON
1091  *
1092  * Local Variables:
1093  * eval: (c-set-style "gnu")
1094  * End:
1095  */