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