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