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