api: fix coverity warning
[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         {
484           ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
485           ed->barrier = !am->is_mp_safe[id];
486         }
487       else
488         {
489           ed->c = elog_string (am->elog_main, "BOGUS");
490           ed->barrier = 0;
491         }
492     }
493 }
494
495 /* This is only to be called from a vlib/vnet app */
496 void
497 vl_msg_api_handler_with_vm_node (api_main_t * am,
498                                  void *the_msg, vlib_main_t * vm,
499                                  vlib_node_runtime_t * node)
500 {
501   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
502   u8 *(*handler) (void *, void *, void *);
503   u8 *(*print_fp) (void *, void *);
504   int is_mp_safe = 1;
505
506   if (PREDICT_FALSE (am->elog_trace_api_messages))
507     {
508       /* *INDENT-OFF* */
509       ELOG_TYPE_DECLARE (e) =
510         {
511           .format = "api-msg: %s",
512           .format_args = "T4",
513         };
514       /* *INDENT-ON* */
515       struct
516       {
517         u32 c;
518       } *ed;
519       ed = ELOG_DATA (am->elog_main, e);
520       if (id < vec_len (am->msg_names))
521         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
522       else
523         ed->c = elog_string (am->elog_main, "BOGUS");
524     }
525
526   if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
527     {
528       handler = (void *) am->msg_handlers[id];
529
530       if (PREDICT_FALSE (am->rx_trace && am->rx_trace->enabled))
531         vl_msg_api_trace (am, am->rx_trace, the_msg);
532
533       if (PREDICT_FALSE (am->msg_print_flag))
534         {
535           fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
536           print_fp = (void *) am->msg_print_handlers[id];
537           if (print_fp == 0)
538             {
539               fformat (stdout, "  [no registered print fn for msg %d]\n", id);
540             }
541           else
542             {
543               (*print_fp) (the_msg, vm);
544             }
545         }
546       is_mp_safe = am->is_mp_safe[id];
547
548       if (!is_mp_safe)
549         {
550           vl_msg_api_barrier_trace_context (am->msg_names[id]);
551           vl_msg_api_barrier_sync ();
552         }
553       (*handler) (the_msg, vm, node);
554       if (!is_mp_safe)
555         vl_msg_api_barrier_release ();
556     }
557   else
558     {
559       clib_warning ("no handler for msg id %d", id);
560     }
561
562   /*
563    * Special-case, so we can e.g. bounce messages off the vnet
564    * main thread without copying them...
565    */
566   if (!(am->message_bounce[id]))
567     vl_msg_api_free (the_msg);
568
569   if (PREDICT_FALSE (am->elog_trace_api_messages))
570     {
571       /* *INDENT-OFF* */
572       ELOG_TYPE_DECLARE (e) =
573         {
574           .format = "api-msg-done(%s): %s",
575           .format_args = "t4T4",
576           .n_enum_strings = 2,
577           .enum_strings =
578           {
579             "barrier",
580             "mp-safe",
581           }
582         };
583       /* *INDENT-ON* */
584
585       struct
586       {
587         u32 barrier;
588         u32 c;
589       } *ed;
590       ed = ELOG_DATA (am->elog_main, e);
591       if (id < vec_len (am->msg_names))
592         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
593       else
594         ed->c = elog_string (am->elog_main, "BOGUS");
595       ed->barrier = is_mp_safe;
596     }
597 }
598
599 void
600 vl_msg_api_handler (void *the_msg)
601 {
602   api_main_t *am = &api_main;
603
604   msg_handler_internal (am, the_msg,
605                         (am->rx_trace
606                          && am->rx_trace->enabled) /* trace_it */ ,
607                         1 /* do_it */ , 1 /* free_it */ );
608 }
609
610 void
611 vl_msg_api_handler_no_free (void *the_msg)
612 {
613   api_main_t *am = &api_main;
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 void
621 vl_msg_api_handler_no_trace_no_free (void *the_msg)
622 {
623   api_main_t *am = &api_main;
624   msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
625                         0 /* free_it */ );
626 }
627
628 /*
629  * Add a trace record to the API message trace buffer, if
630  * API message tracing is enabled. Handy for adding sufficient
631  * data to the trace to reproduce autonomous state, as opposed to
632  * state downloaded via control-plane API messages. Example: the NAT
633  * application creates database entries based on packet traffic, not
634  * control-plane messages.
635  *
636  */
637 void
638 vl_msg_api_trace_only (void *the_msg)
639 {
640   api_main_t *am = &api_main;
641
642   msg_handler_internal (am, the_msg,
643                         (am->rx_trace
644                          && am->rx_trace->enabled) /* trace_it */ ,
645                         0 /* do_it */ , 0 /* free_it */ );
646 }
647
648 void
649 vl_msg_api_cleanup_handler (void *the_msg)
650 {
651   api_main_t *am = &api_main;
652   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
653
654   if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
655     {
656       clib_warning ("_vl_msg_id too large: %d\n", id);
657       return;
658     }
659   if (am->msg_cleanup_handlers[id])
660     (*am->msg_cleanup_handlers[id]) (the_msg);
661
662   vl_msg_api_free (the_msg);
663 }
664
665 /*
666  * vl_msg_api_replay_handler
667  */
668 void
669 vl_msg_api_replay_handler (void *the_msg)
670 {
671   api_main_t *am = &api_main;
672
673   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
674
675   if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
676     {
677       clib_warning ("_vl_msg_id too large: %d\n", id);
678       return;
679     }
680   /* do NOT trace the message... */
681   if (am->msg_handlers[id])
682     (*am->msg_handlers[id]) (the_msg);
683   /* do NOT free the message buffer... */
684 }
685
686 u32
687 vl_msg_api_get_msg_length (void *msg_arg)
688 {
689   return vl_msg_api_get_msg_length_inline (msg_arg);
690 }
691
692 /*
693  * vl_msg_api_socket_handler
694  */
695 void
696 vl_msg_api_socket_handler (void *the_msg)
697 {
698   api_main_t *am = &api_main;
699
700   msg_handler_internal (am, the_msg,
701                         (am->rx_trace
702                          && am->rx_trace->enabled) /* trace_it */ ,
703                         1 /* do_it */ , 0 /* free_it */ );
704 }
705
706 #define foreach_msg_api_vector                  \
707 _(msg_names)                                    \
708 _(msg_handlers)                                 \
709 _(msg_cleanup_handlers)                         \
710 _(msg_endian_handlers)                          \
711 _(msg_print_handlers)                           \
712 _(api_trace_cfg)                                \
713 _(message_bounce)                               \
714 _(is_mp_safe)
715
716 void
717 vl_msg_api_config (vl_msg_api_msg_config_t * c)
718 {
719   api_main_t *am = &api_main;
720
721   /*
722    * This happens during the java core tests if the message
723    * dictionary is missing newly added xxx_reply_t messages.
724    * Should never happen, but since I shot myself in the foot once
725    * this way, I thought I'd make it easy to debug if I ever do
726    * it again... (;-)...
727    */
728   if (c->id == 0)
729     {
730       if (c->name)
731         clib_warning ("Trying to register %s with a NULL msg id!", c->name);
732       else
733         clib_warning ("Trying to register a NULL msg with a NULL msg id!");
734       clib_warning ("Did you forget to call setup_message_id_table?");
735       return;
736     }
737
738 #define _(a) vec_validate (am->a, c->id);
739   foreach_msg_api_vector;
740 #undef _
741
742   if (am->msg_handlers[c->id] && am->msg_handlers[c->id] != c->handler)
743     clib_warning
744       ("BUG: re-registering 'vl_api_%s_t_handler'."
745        "Handler was %llx, replaced by %llx",
746        c->name, am->msg_handlers[c->id], c->handler);
747
748   am->msg_names[c->id] = c->name;
749   am->msg_handlers[c->id] = c->handler;
750   am->msg_cleanup_handlers[c->id] = c->cleanup;
751   am->msg_endian_handlers[c->id] = c->endian;
752   am->msg_print_handlers[c->id] = c->print;
753   am->message_bounce[c->id] = c->message_bounce;
754   am->is_mp_safe[c->id] = c->is_mp_safe;
755
756   am->api_trace_cfg[c->id].size = c->size;
757   am->api_trace_cfg[c->id].trace_enable = c->traced;
758   am->api_trace_cfg[c->id].replay_enable = c->replay;
759 }
760
761 /*
762  * vl_msg_api_set_handlers
763  * preserve the old API for a while
764  */
765 void
766 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
767                          void *endian, void *print, int size, int traced)
768 {
769   vl_msg_api_msg_config_t cfg;
770   vl_msg_api_msg_config_t *c = &cfg;
771
772   clib_memset (c, 0, sizeof (*c));
773
774   c->id = id;
775   c->name = name;
776   c->handler = handler;
777   c->cleanup = cleanup;
778   c->endian = endian;
779   c->print = print;
780   c->traced = traced;
781   c->replay = 1;
782   c->message_bounce = 0;
783   c->is_mp_safe = 0;
784   vl_msg_api_config (c);
785 }
786
787 void
788 vl_msg_api_clean_handlers (int msg_id)
789 {
790   vl_msg_api_msg_config_t cfg;
791   vl_msg_api_msg_config_t *c = &cfg;
792
793   clib_memset (c, 0, sizeof (*c));
794
795   c->id = msg_id;
796   vl_msg_api_config (c);
797 }
798
799 void
800 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
801 {
802   api_main_t *am = &api_main;
803   ASSERT (msg_id > 0);
804
805   vec_validate (am->msg_cleanup_handlers, msg_id);
806   am->msg_cleanup_handlers[msg_id] = fp;
807 }
808
809 void
810 vl_msg_api_queue_handler (svm_queue_t * q)
811 {
812   uword msg;
813
814   while (!svm_queue_sub (q, (u8 *) & msg, SVM_Q_WAIT, 0))
815     vl_msg_api_handler ((void *) msg);
816 }
817
818 vl_api_trace_t *
819 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
820 {
821   switch (which)
822     {
823     case VL_API_TRACE_RX:
824       return am->rx_trace;
825     case VL_API_TRACE_TX:
826       return am->tx_trace;
827     default:
828       return 0;
829     }
830 }
831
832 void
833 vl_noop_handler (void *mp)
834 {
835 }
836
837
838 static u8 post_mortem_dump_enabled;
839
840 void
841 vl_msg_api_post_mortem_dump_enable_disable (int enable)
842 {
843   post_mortem_dump_enabled = enable;
844 }
845
846 void
847 vl_msg_api_post_mortem_dump (void)
848 {
849   api_main_t *am = &api_main;
850   FILE *fp;
851   char filename[64];
852   int rv;
853
854   if (post_mortem_dump_enabled == 0)
855     return;
856
857   snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
858             getpid ());
859
860   fp = fopen (filename, "w");
861   if (fp == NULL)
862     {
863       rv = write (2, "Couldn't create ", 16);
864       rv = write (2, filename, strlen (filename));
865       rv = write (2, "\n", 1);
866       return;
867     }
868   rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
869   fclose (fp);
870   if (rv < 0)
871     {
872       rv = write (2, "Failed to save post-mortem API trace to ", 40);
873       rv = write (2, filename, strlen (filename));
874       rv = write (2, "\n", 1);
875     }
876
877 }
878
879 /* Layered message handling support */
880
881 void
882 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
883 {
884   api_main_t *am = &api_main;
885
886   /* Mild idiot proofing */
887   if (msg_id_host_byte_order > 10000)
888     clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
889                   msg_id_host_byte_order,
890                   clib_net_to_host_u16 (msg_id_host_byte_order));
891   vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
892   am->pd_msg_handlers[msg_id_host_byte_order] = fp;
893 }
894
895 int
896 vl_msg_api_pd_handler (void *mp, int rv)
897 {
898   api_main_t *am = &api_main;
899   int (*fp) (void *, int);
900   u16 msg_id;
901
902   if (clib_arch_is_little_endian)
903     msg_id = clib_net_to_host_u16 (*((u16 *) mp));
904   else
905     msg_id = *((u16 *) mp);
906
907   if (msg_id >= vec_len (am->pd_msg_handlers)
908       || am->pd_msg_handlers[msg_id] == 0)
909     return rv;
910
911   fp = am->pd_msg_handlers[msg_id];
912   rv = (*fp) (mp, rv);
913   return rv;
914 }
915
916 void
917 vl_msg_api_set_first_available_msg_id (u16 first_avail)
918 {
919   api_main_t *am = &api_main;
920
921   am->first_available_msg_id = first_avail;
922 }
923
924 u16
925 vl_msg_api_get_msg_ids (const char *name, int n)
926 {
927   api_main_t *am = &api_main;
928   u8 *name_copy;
929   vl_api_msg_range_t *rp;
930   uword *p;
931   u16 rv;
932
933   if (am->msg_range_by_name == 0)
934     am->msg_range_by_name = hash_create_string (0, sizeof (uword));
935
936   name_copy = format (0, "%s%c", name, 0);
937
938   p = hash_get_mem (am->msg_range_by_name, name_copy);
939   if (p)
940     {
941       clib_warning ("WARNING: duplicate message range registration for '%s'",
942                     name_copy);
943       vec_free (name_copy);
944       return ((u16) ~ 0);
945     }
946
947   if (n < 0 || n > 1024)
948     {
949       clib_warning
950         ("WARNING: bad number of message-IDs (%d) requested by '%s'",
951          n, name_copy);
952       vec_free (name_copy);
953       return ((u16) ~ 0);
954     }
955
956   vec_add2 (am->msg_ranges, rp, 1);
957
958   rv = rp->first_msg_id = am->first_available_msg_id;
959   am->first_available_msg_id += n;
960   rp->last_msg_id = am->first_available_msg_id - 1;
961   rp->name = name_copy;
962
963   hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
964
965   return rv;
966 }
967
968 void
969 vl_msg_api_add_msg_name_crc (api_main_t * am, const char *string, u32 id)
970 {
971   uword *p;
972
973   if (am->msg_index_by_name_and_crc == 0)
974     am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
975
976   p = hash_get_mem (am->msg_index_by_name_and_crc, string);
977   if (p)
978     {
979       clib_warning ("attempt to redefine '%s' ignored...", string);
980       return;
981     }
982
983   hash_set_mem (am->msg_index_by_name_and_crc, string, id);
984 }
985
986 void
987 vl_msg_api_add_version (api_main_t * am, const char *string,
988                         u32 major, u32 minor, u32 patch)
989 {
990   api_version_t version = {.major = major,.minor = minor,.patch = patch };
991   ASSERT (strlen (string) < 64);
992   strncpy (version.name, string, 64 - 1);
993   vec_add1 (am->api_version_list, version);
994 }
995
996 u32
997 vl_msg_api_get_msg_index (u8 * name_and_crc)
998 {
999   api_main_t *am = &api_main;
1000   uword *p;
1001
1002   if (am->msg_index_by_name_and_crc)
1003     {
1004       p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc);
1005       if (p)
1006         return p[0];
1007     }
1008   return ~0;
1009 }
1010
1011 void *
1012 vl_msg_push_heap (void)
1013 {
1014   api_main_t *am = &api_main;
1015   pthread_mutex_lock (&am->vlib_rp->mutex);
1016   return svm_push_data_heap (am->vlib_rp);
1017 }
1018
1019 void
1020 vl_msg_pop_heap (void *oldheap)
1021 {
1022   api_main_t *am = &api_main;
1023   svm_pop_heap (oldheap);
1024   pthread_mutex_unlock (&am->vlib_rp->mutex);
1025 }
1026
1027 int
1028 vl_api_to_api_string (u32 len, const char *buf, vl_api_string_t * str)
1029 {
1030   clib_memcpy_fast (str->buf, buf, len);
1031   str->length = htonl (len);
1032   return len + sizeof (u32);
1033 }
1034
1035 int
1036 vl_api_vec_to_api_string (const u8 * vec, vl_api_string_t * str)
1037 {
1038   u32 len = vec_len (vec);
1039   clib_memcpy (str->buf, vec, len);
1040   str->length = htonl (len);
1041   return len + sizeof (u32);
1042 }
1043
1044 /* Return a pointer to the API string (not nul terminated */
1045 u8 *
1046 vl_api_from_api_string (vl_api_string_t * astr)
1047 {
1048   return astr->buf;
1049 }
1050
1051 u32
1052 vl_api_string_len (vl_api_string_t * astr)
1053 {
1054   return clib_net_to_host_u32 (astr->length);
1055 }
1056
1057 /*
1058  * Returns a new vector. Remember to free it after use.
1059  */
1060 u8 *
1061 vl_api_from_api_to_vec (vl_api_string_t * astr)
1062 {
1063   u8 *v = 0;
1064   vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length));
1065   return v;
1066 }
1067
1068 void
1069 vl_api_set_elog_main (elog_main_t * m)
1070 {
1071   api_main_t *am = &api_main;
1072   am->elog_main = m;
1073 }
1074
1075 int
1076 vl_api_set_elog_trace_api_messages (int enable)
1077 {
1078   int rv;
1079   api_main_t *am = &api_main;
1080
1081   rv = am->elog_trace_api_messages;
1082   am->elog_trace_api_messages = enable;
1083   return rv;
1084 }
1085
1086 int
1087 vl_api_get_elog_trace_api_messages (void)
1088 {
1089   api_main_t *am = &api_main;
1090
1091   return am->elog_trace_api_messages;
1092 }
1093
1094 /*
1095  * fd.io coding-style-patch-verification: ON
1096  *
1097  * Local Variables:
1098  * eval: (c-set-style "gnu")
1099  * End:
1100  */