api: better segregate client and server code
[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 #include <vppinfra/callback.h>
34
35 /* *INDENT-OFF* */
36 static api_main_t api_global_main = {
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 static int
226 vl_msg_api_trace_write_one (api_main_t *am, u8 *msg, FILE *fp)
227 {
228   u8 *tmpmem = 0;
229   int tlen, slen;
230   cJSON *(*tojson_fn) (void *);
231
232   u32 msg_length = vec_len (msg);
233   vec_validate (tmpmem, msg_length - 1);
234   clib_memcpy_fast (tmpmem, msg, msg_length);
235   u16 id = clib_net_to_host_u16 (*((u16 *) msg));
236
237   void (*endian_fp) (void *);
238   endian_fp = am->msg_endian_handlers[id];
239   (*endian_fp) (tmpmem);
240
241   if (id < vec_len (am->msg_tojson_handlers) && am->msg_tojson_handlers[id])
242     {
243       tojson_fn = am->msg_tojson_handlers[id];
244       cJSON *o = tojson_fn (tmpmem);
245       char *s = cJSON_Print (o);
246       slen = strlen (s);
247       tlen = fwrite (s, 1, slen, fp);
248       cJSON_free (s);
249       cJSON_Delete (o);
250       vec_free (tmpmem);
251       if (tlen != slen)
252         {
253           fformat (stderr, "writing to file error\n");
254           return -11;
255         }
256     }
257   else
258     fformat (stderr, "  [no registered tojson fn]\n");
259
260   return 0;
261 }
262
263 #define vl_msg_fwrite(_s, _f) fwrite (_s, 1, sizeof (_s) - 1, _f)
264
265 typedef struct
266 {
267   FILE *fp;
268   u32 n_traces;
269   u32 i;
270 } vl_msg_write_json_args_t;
271
272 static int
273 vl_msg_write_json_fn (u8 *msg, void *ctx)
274 {
275   vl_msg_write_json_args_t *arg = ctx;
276   FILE *fp = arg->fp;
277   api_main_t *am = vlibapi_get_main ();
278   int rc = vl_msg_api_trace_write_one (am, msg, fp);
279   if (rc < 0)
280     return rc;
281
282   if (arg->i < arg->n_traces - 1)
283     vl_msg_fwrite (",\n", fp);
284   arg->i++;
285   return 0;
286 }
287
288 static int
289 vl_msg_api_trace_write_json (api_main_t *am, vl_api_trace_t *tp, FILE *fp)
290 {
291   vl_msg_write_json_args_t args;
292   clib_memset (&args, 0, sizeof (args));
293   args.fp = fp;
294   args.n_traces = vec_len (tp->traces);
295   vl_msg_fwrite ("[\n", fp);
296
297   int rv = vl_msg_traverse_trace (tp, vl_msg_write_json_fn, &args);
298   if (rv < 0)
299     return rv;
300
301   vl_msg_fwrite ("]", fp);
302   return 0;
303 }
304
305 int
306 vl_msg_traverse_trace (vl_api_trace_t *tp, vl_msg_traverse_trace_fn fn,
307                        void *ctx)
308 {
309   int i;
310   u8 *msg;
311   int rv = 0;
312
313   /* No-wrap case */
314   if (tp->wrapped == 0)
315     {
316       for (i = 0; i < vec_len (tp->traces); i++)
317         {
318           /*sa_ignore NO_NULL_CHK */
319           msg = tp->traces[i];
320           if (!msg)
321             continue;
322
323           rv = fn (msg, ctx);
324           if (rv < 0)
325             return rv;
326         }
327     }
328   else
329     {
330       /* Wrap case: write oldest -> end of buffer */
331       for (i = tp->curindex; i < vec_len (tp->traces); i++)
332         {
333           msg = tp->traces[i];
334           if (!msg)
335             continue;
336
337           rv = fn (msg, ctx);
338           if (rv < 0)
339             return rv;
340         }
341       /* write beginning of buffer -> oldest-1 */
342       for (i = 0; i < tp->curindex; i++)
343         {
344           /*sa_ignore NO_NULL_CHK */
345           msg = tp->traces[i];
346           if (!msg)
347             continue;
348
349           rv = fn (msg, ctx);
350           if (rv < 0)
351             return rv;
352         }
353     }
354   return 0;
355 }
356
357 static int
358 vl_api_msg_write_fn (u8 *msg, void *ctx)
359 {
360   FILE *fp = ctx;
361   u32 msg_length = clib_host_to_net_u32 (vec_len (msg));
362   if (fwrite (&msg_length, 1, sizeof (msg_length), fp) != sizeof (msg_length))
363     {
364       return (-14);
365     }
366   if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
367     {
368       return (-14);
369     }
370   return 0;
371 }
372
373 int
374 vl_msg_api_trace_save (api_main_t *am, vl_api_trace_which_t which, FILE *fp,
375                        u8 is_json)
376 {
377   vl_api_trace_t *tp;
378   vl_api_trace_file_header_t fh;
379
380   switch (which)
381     {
382     case VL_API_TRACE_TX:
383       tp = am->tx_trace;
384       break;
385
386     case VL_API_TRACE_RX:
387       tp = am->rx_trace;
388       break;
389
390     default:
391       /* duh? */
392       return -1;
393     }
394
395   /* Configured, data present? */
396   if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
397     return -1;
398
399   /* "Dare to be stupid" check */
400   if (fp == 0)
401     {
402       return -2;
403     }
404
405   if (is_json)
406     return vl_msg_api_trace_write_json (am, tp, fp);
407
408   /* Write the file header */
409   fh.wrapped = tp->wrapped;
410   fh.nitems = clib_host_to_net_u32 (vec_len (tp->traces));
411
412   u8 *m = vl_api_serialize_message_table (am, 0);
413   fh.msgtbl_size = clib_host_to_net_u32 (vec_len (m));
414
415   if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
416     {
417       return (-10);
418     }
419
420   /* Write the message table */
421   if (fwrite (m, vec_len (m), 1, fp) != 1)
422     {
423       return (-14);
424     }
425   vec_free (m);
426
427   return vl_msg_traverse_trace (tp, vl_api_msg_write_fn, fp);
428 }
429
430 int
431 vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
432                             u32 nitems)
433 {
434   vl_api_trace_t *tp;
435   int was_on = 0;
436
437   switch (which)
438     {
439     case VL_API_TRACE_TX:
440       tp = am->tx_trace;
441       if (tp == 0)
442         {
443           vec_validate (am->tx_trace, 0);
444           tp = am->tx_trace;
445         }
446       break;
447
448     case VL_API_TRACE_RX:
449       tp = am->rx_trace;
450       if (tp == 0)
451         {
452           vec_validate (am->rx_trace, 0);
453           tp = am->rx_trace;
454         }
455
456       break;
457
458     default:
459       return -1;
460
461     }
462
463   if (tp->enabled)
464     {
465       was_on = vl_msg_api_trace_onoff (am, which, 0);
466     }
467   if (tp->traces)
468     {
469       vl_msg_api_trace_free (am, which);
470     }
471
472   clib_memset (tp, 0, sizeof (*tp));
473
474   if (clib_arch_is_big_endian)
475     {
476       tp->endian = VL_API_BIG_ENDIAN;
477     }
478   else
479     {
480       tp->endian = VL_API_LITTLE_ENDIAN;
481     }
482
483   tp->nitems = nitems;
484   if (was_on)
485     {
486       (void) vl_msg_api_trace_onoff (am, which, was_on);
487     }
488   return 0;
489 }
490
491 void
492 vl_msg_api_barrier_sync (void)
493 {
494 }
495
496 void
497 vl_msg_api_barrier_release (void)
498 {
499 }
500
501 always_inline void
502 msg_handler_internal (api_main_t *am, void *the_msg, uword msg_len,
503                       int trace_it, int do_it, int free_it)
504 {
505   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
506   u8 *(*print_fp) (void *, void *);
507
508   if (PREDICT_FALSE (am->elog_trace_api_messages))
509     {
510       /* *INDENT-OFF* */
511       ELOG_TYPE_DECLARE (e) =
512         {
513           .format = "api-msg: %s",
514           .format_args = "T4",
515         };
516       /* *INDENT-ON* */
517       struct
518       {
519         u32 c;
520       } *ed;
521       ed = ELOG_DATA (am->elog_main, e);
522       if (id < vec_len (am->msg_names) && am->msg_names[id])
523         ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
524       else
525         ed->c = elog_string (am->elog_main, "BOGUS");
526     }
527
528   if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
529     {
530       if (trace_it)
531         vl_msg_api_trace (am, am->rx_trace, the_msg);
532
533       if (am->msg_print_flag)
534         {
535           fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
536           print_fp = (void *) am->msg_print_handlers[id];
537           if (print_fp == 0)
538             {
539               fformat (stdout, "  [no registered print fn]\n");
540             }
541           else
542             {
543               (*print_fp) (the_msg, stdout);
544             }
545         }
546
547       uword calc_size = 0;
548       uword (*calc_size_fp) (void *);
549       calc_size_fp = am->msg_calc_size_funcs[id];
550       ASSERT (NULL != calc_size_fp);
551       if (calc_size_fp)
552         {
553           calc_size = (*calc_size_fp) (the_msg);
554           ASSERT (calc_size <= msg_len);
555           if (calc_size > msg_len)
556             {
557               clib_warning (
558                 "Truncated message '%s' (id %u) received, calculated size "
559                 "%lu is bigger than actual size %llu, message dropped.",
560                 am->msg_names[id], id, calc_size, msg_len);
561             }
562         }
563       else
564         {
565           clib_warning ("Message '%s' (id %u) has NULL calc_size_func, cannot "
566                         "verify message size is correct",
567                         am->msg_names[id], id);
568         }
569
570       /* don't process message if it's truncated, otherwise byte swaps
571        * and stuff could corrupt memory even beyond message if it's malicious
572        * e.g. VLA length field set to 1M elements, but VLA empty */
573       if (do_it && calc_size <= msg_len)
574         {
575
576           if (!am->is_mp_safe[id])
577             {
578               vl_msg_api_barrier_trace_context (am->msg_names[id]);
579               vl_msg_api_barrier_sync ();
580             }
581
582           if (am->is_autoendian[id])
583             {
584               void (*endian_fp) (void *);
585               endian_fp = am->msg_endian_handlers[id];
586               (*endian_fp) (the_msg);
587             }
588
589           if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
590             clib_call_callbacks (am->perf_counter_cbs, am, id,
591                                  0 /* before */ );
592
593           (*am->msg_handlers[id]) (the_msg);
594
595           if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
596             clib_call_callbacks (am->perf_counter_cbs, am, id,
597                                  1 /* after */ );
598
599           if (!am->is_mp_safe[id])
600             vl_msg_api_barrier_release ();
601         }
602     }
603   else
604     {
605       clib_warning ("no handler for msg id %d", id);
606     }
607
608   if (free_it)
609     vl_msg_api_free (the_msg);
610
611   if (PREDICT_FALSE (am->elog_trace_api_messages))
612     {
613       /* *INDENT-OFF* */
614       ELOG_TYPE_DECLARE (e) =
615         {
616           .format = "api-msg-done(%s): %s",
617           .format_args = "t4T4",
618           .n_enum_strings = 2,
619           .enum_strings =
620           {
621             "barrier",
622             "mp-safe",
623           }
624         };
625       /* *INDENT-ON* */
626
627       struct
628       {
629         u32 barrier;
630         u32 c;
631       } *ed;
632       ed = ELOG_DATA (am->elog_main, e);
633       if (id < vec_len (am->msg_names) && am->msg_names[id])
634         {
635           ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
636           ed->barrier = !am->is_mp_safe[id];
637         }
638       else
639         {
640           ed->c = elog_string (am->elog_main, "BOGUS");
641           ed->barrier = 0;
642         }
643     }
644 }
645
646 void
647 vl_msg_api_handler (void *the_msg, uword msg_len)
648 {
649   api_main_t *am = vlibapi_get_main ();
650
651   msg_handler_internal (am, the_msg, msg_len,
652                         (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
653                         1 /* do_it */, 1 /* free_it */);
654 }
655
656 void
657 vl_msg_api_handler_no_free (void *the_msg, uword msg_len)
658 {
659   api_main_t *am = vlibapi_get_main ();
660   msg_handler_internal (am, the_msg, msg_len,
661                         (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
662                         1 /* do_it */, 0 /* free_it */);
663 }
664
665 void
666 vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len)
667 {
668   api_main_t *am = vlibapi_get_main ();
669   msg_handler_internal (am, the_msg, msg_len, 0 /* trace_it */, 1 /* do_it */,
670                         0 /* free_it */);
671 }
672
673 /*
674  * Add a trace record to the API message trace buffer, if
675  * API message tracing is enabled. Handy for adding sufficient
676  * data to the trace to reproduce autonomous state, as opposed to
677  * state downloaded via control-plane API messages. Example: the NAT
678  * application creates database entries based on packet traffic, not
679  * control-plane messages.
680  *
681  */
682 void
683 vl_msg_api_trace_only (void *the_msg, uword msg_len)
684 {
685   api_main_t *am = vlibapi_get_main ();
686
687   msg_handler_internal (am, the_msg, msg_len,
688                         (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
689                         0 /* do_it */, 0 /* free_it */);
690 }
691
692 void
693 vl_msg_api_cleanup_handler (void *the_msg)
694 {
695   api_main_t *am = vlibapi_get_main ();
696   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
697
698   if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
699     {
700       clib_warning ("_vl_msg_id too large: %d\n", id);
701       return;
702     }
703   if (am->msg_cleanup_handlers[id])
704     (*am->msg_cleanup_handlers[id]) (the_msg);
705
706   vl_msg_api_free (the_msg);
707 }
708
709 /*
710  * vl_msg_api_replay_handler
711  */
712 void
713 vl_msg_api_replay_handler (void *the_msg)
714 {
715   api_main_t *am = vlibapi_get_main ();
716
717   u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
718
719   if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
720     {
721       clib_warning ("_vl_msg_id too large: %d\n", id);
722       return;
723     }
724   /* do NOT trace the message... */
725   if (am->msg_handlers[id])
726     (*am->msg_handlers[id]) (the_msg);
727   /* do NOT free the message buffer... */
728 }
729
730 u32
731 vl_msg_api_get_msg_length (void *msg_arg)
732 {
733   return vl_msg_api_get_msg_length_inline (msg_arg);
734 }
735
736 /*
737  * vl_msg_api_socket_handler
738  */
739 void
740 vl_msg_api_socket_handler (void *the_msg, uword msg_len)
741 {
742   api_main_t *am = vlibapi_get_main ();
743
744   msg_handler_internal (am, the_msg, msg_len,
745                         (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
746                         1 /* do_it */, 0 /* free_it */);
747 }
748
749 #define foreach_msg_api_vector                                                \
750   _ (msg_names)                                                               \
751   _ (msg_handlers)                                                            \
752   _ (msg_cleanup_handlers)                                                    \
753   _ (msg_endian_handlers)                                                     \
754   _ (msg_print_handlers)                                                      \
755   _ (msg_print_json_handlers)                                                 \
756   _ (msg_tojson_handlers)                                                     \
757   _ (msg_fromjson_handlers)                                                   \
758   _ (msg_calc_size_funcs)                                                     \
759   _ (api_trace_cfg)                                                           \
760   _ (message_bounce)                                                          \
761   _ (is_mp_safe)                                                              \
762   _ (is_autoendian)
763
764 void
765 vl_msg_api_config (vl_msg_api_msg_config_t * c)
766 {
767   api_main_t *am = vlibapi_get_main ();
768
769   /*
770    * This happens during the java core tests if the message
771    * dictionary is missing newly added xxx_reply_t messages.
772    * Should never happen, but since I shot myself in the foot once
773    * this way, I thought I'd make it easy to debug if I ever do
774    * it again... (;-)...
775    */
776   if (c->id == 0)
777     {
778       if (c->name)
779         clib_warning ("Trying to register %s with a NULL msg id!", c->name);
780       else
781         clib_warning ("Trying to register a NULL msg with a NULL msg id!");
782       clib_warning ("Did you forget to call setup_message_id_table?");
783       return;
784     }
785
786 #define _(a) vec_validate (am->a, c->id);
787   foreach_msg_api_vector;
788 #undef _
789
790   if (am->msg_handlers[c->id] && am->msg_handlers[c->id] != c->handler)
791     clib_warning
792       ("BUG: re-registering 'vl_api_%s_t_handler'."
793        "Handler was %llx, replaced by %llx",
794        c->name, am->msg_handlers[c->id], c->handler);
795
796   am->msg_names[c->id] = c->name;
797   am->msg_handlers[c->id] = c->handler;
798   am->msg_cleanup_handlers[c->id] = c->cleanup;
799   am->msg_endian_handlers[c->id] = c->endian;
800   am->msg_print_handlers[c->id] = c->print;
801   am->msg_print_json_handlers[c->id] = c->print_json;
802   am->msg_tojson_handlers[c->id] = c->tojson;
803   am->msg_fromjson_handlers[c->id] = c->fromjson;
804   am->msg_calc_size_funcs[c->id] = c->calc_size;
805   am->message_bounce[c->id] = c->message_bounce;
806   am->is_mp_safe[c->id] = c->is_mp_safe;
807   am->is_autoendian[c->id] = c->is_autoendian;
808
809   am->api_trace_cfg[c->id].size = c->size;
810   am->api_trace_cfg[c->id].trace_enable = c->traced;
811   am->api_trace_cfg[c->id].replay_enable = c->replay;
812
813   if (!am->msg_id_by_name)
814     am->msg_id_by_name = hash_create_string (0, sizeof (uword));
815
816   hash_set_mem (am->msg_id_by_name, c->name, c->id);
817 }
818
819 /*
820  * vl_msg_api_set_handlers
821  * preserve the old API for a while
822  */
823 void
824 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
825                          void *endian, void *print, int size, int traced,
826                          void *print_json, void *tojson, void *fromjson,
827                          void *calc_size)
828 {
829   vl_msg_api_msg_config_t cfg;
830   vl_msg_api_msg_config_t *c = &cfg;
831
832   clib_memset (c, 0, sizeof (*c));
833
834   c->id = id;
835   c->name = name;
836   c->handler = handler;
837   c->cleanup = cleanup;
838   c->endian = endian;
839   c->print = print;
840   c->traced = traced;
841   c->replay = 1;
842   c->message_bounce = 0;
843   c->is_mp_safe = 0;
844   c->is_autoendian = 0;
845   c->tojson = tojson;
846   c->fromjson = fromjson;
847   c->print_json = print_json;
848   c->calc_size = calc_size;
849   vl_msg_api_config (c);
850 }
851
852 void
853 vl_msg_api_clean_handlers (int msg_id)
854 {
855   vl_msg_api_msg_config_t cfg;
856   vl_msg_api_msg_config_t *c = &cfg;
857
858   clib_memset (c, 0, sizeof (*c));
859
860   c->id = msg_id;
861   vl_msg_api_config (c);
862 }
863
864 void
865 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
866 {
867   api_main_t *am = vlibapi_get_main ();
868   ASSERT (msg_id > 0);
869
870   vec_validate (am->msg_cleanup_handlers, msg_id);
871   am->msg_cleanup_handlers[msg_id] = fp;
872 }
873
874 void
875 vl_msg_api_queue_handler (svm_queue_t * q)
876 {
877   uword msg;
878
879   while (!svm_queue_sub (q, (u8 *) &msg, SVM_Q_WAIT, 0))
880     {
881       msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) msg - offsetof (msgbuf_t, data));
882       vl_msg_api_handler ((void *) msg, ntohl (msgbuf->data_len));
883     }
884 }
885
886 u32
887 vl_msg_api_max_length (void *mp)
888 {
889   msgbuf_t *mb;
890   u32 data_len = ~0;
891
892   /* Work out the maximum sane message length, and return it */
893   if (PREDICT_TRUE (mp != 0))
894     {
895       mb = (msgbuf_t *) (((u8 *) mp) - offsetof (msgbuf_t, data));
896       data_len = clib_net_to_host_u32 (mb->data_len);
897     }
898   return data_len;
899 }
900
901 vl_api_trace_t *
902 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
903 {
904   switch (which)
905     {
906     case VL_API_TRACE_RX:
907       return am->rx_trace;
908     case VL_API_TRACE_TX:
909       return am->tx_trace;
910     default:
911       return 0;
912     }
913 }
914
915 void
916 vl_noop_handler (void *mp)
917 {
918 }
919
920
921 static u8 post_mortem_dump_enabled;
922
923 void
924 vl_msg_api_post_mortem_dump_enable_disable (int enable)
925 {
926   post_mortem_dump_enabled = enable;
927 }
928
929 void
930 vl_msg_api_post_mortem_dump (void)
931 {
932   api_main_t *am = vlibapi_get_main ();
933   FILE *fp;
934   char filename[64];
935   int rv;
936
937   if (post_mortem_dump_enabled == 0)
938     return;
939
940   snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
941             getpid ());
942
943   fp = fopen (filename, "w");
944   if (fp == NULL)
945     {
946       rv = write (2, "Couldn't create ", 16);
947       rv = write (2, filename, strlen (filename));
948       rv = write (2, "\n", 1);
949       return;
950     }
951   rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp, 0);
952   fclose (fp);
953   if (rv < 0)
954     {
955       rv = write (2, "Failed to save post-mortem API trace to ", 40);
956       rv = write (2, filename, strlen (filename));
957       rv = write (2, "\n", 1);
958     }
959
960 }
961
962 /* Layered message handling support */
963
964 void
965 vl_msg_api_set_first_available_msg_id (u16 first_avail)
966 {
967   api_main_t *am = vlibapi_get_main ();
968
969   am->first_available_msg_id = first_avail;
970 }
971
972 u16
973 vl_msg_api_get_msg_ids (const char *name, int n)
974 {
975   api_main_t *am = vlibapi_get_main ();
976   u8 *name_copy;
977   vl_api_msg_range_t *rp;
978   uword *p;
979   u16 rv;
980
981   if (am->msg_range_by_name == 0)
982     am->msg_range_by_name = hash_create_string (0, sizeof (uword));
983
984   name_copy = format (0, "%s%c", name, 0);
985
986   p = hash_get_mem (am->msg_range_by_name, name_copy);
987   if (p)
988     {
989       clib_warning ("WARNING: duplicate message range registration for '%s'",
990                     name_copy);
991       vec_free (name_copy);
992       return ((u16) ~ 0);
993     }
994
995   if (n < 0 || n > 1024)
996     {
997       clib_warning
998         ("WARNING: bad number of message-IDs (%d) requested by '%s'",
999          n, name_copy);
1000       vec_free (name_copy);
1001       return ((u16) ~ 0);
1002     }
1003
1004   vec_add2 (am->msg_ranges, rp, 1);
1005
1006   rv = rp->first_msg_id = am->first_available_msg_id;
1007   am->first_available_msg_id += n;
1008   rp->last_msg_id = am->first_available_msg_id - 1;
1009   rp->name = name_copy;
1010
1011   hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
1012
1013   return rv;
1014 }
1015
1016 void
1017 vl_msg_api_add_msg_name_crc (api_main_t * am, const char *string, u32 id)
1018 {
1019   uword *p;
1020
1021   if (am->msg_index_by_name_and_crc == 0)
1022     am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
1023
1024   p = hash_get_mem (am->msg_index_by_name_and_crc, string);
1025   if (p)
1026     {
1027       clib_warning ("attempt to redefine '%s' ignored...", string);
1028       return;
1029     }
1030
1031   hash_set_mem (am->msg_index_by_name_and_crc, string, id);
1032 }
1033
1034 void
1035 vl_msg_api_add_version (api_main_t * am, const char *string,
1036                         u32 major, u32 minor, u32 patch)
1037 {
1038   api_version_t version = {.major = major,.minor = minor,.patch = patch };
1039   ASSERT (strlen (string) < 64);
1040   strncpy (version.name, string, 64 - 1);
1041   vec_add1 (am->api_version_list, version);
1042 }
1043
1044 u32
1045 vl_msg_api_get_msg_index (u8 * name_and_crc)
1046 {
1047   api_main_t *am = vlibapi_get_main ();
1048   uword *p;
1049
1050   if (am->msg_index_by_name_and_crc)
1051     {
1052       p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc);
1053       if (p)
1054         return p[0];
1055     }
1056   return ~0;
1057 }
1058
1059 void *
1060 vl_msg_push_heap_w_region (svm_region_t * vlib_rp)
1061 {
1062   pthread_mutex_lock (&vlib_rp->mutex);
1063   return svm_push_data_heap (vlib_rp);
1064 }
1065
1066 void *
1067 vl_msg_push_heap (void)
1068 {
1069   api_main_t *am = vlibapi_get_main ();
1070   return vl_msg_push_heap_w_region (am->vlib_rp);
1071 }
1072
1073 void
1074 vl_msg_pop_heap_w_region (svm_region_t * vlib_rp, void *oldheap)
1075 {
1076   svm_pop_heap (oldheap);
1077   pthread_mutex_unlock (&vlib_rp->mutex);
1078 }
1079
1080 void
1081 vl_msg_pop_heap (void *oldheap)
1082 {
1083   api_main_t *am = vlibapi_get_main ();
1084   vl_msg_pop_heap_w_region (am->vlib_rp, oldheap);
1085 }
1086
1087 /* Must be nul terminated */
1088 int
1089 vl_api_c_string_to_api_string (const char *buf, vl_api_string_t * str)
1090 {
1091   /* copy without nul terminator */
1092   u32 len = strlen (buf);
1093   if (len > 0)
1094     clib_memcpy_fast (str->buf, buf, len);
1095   str->length = htonl (len);
1096   return len + sizeof (u32);
1097 }
1098
1099 /* Must NOT be nul terminated */
1100 int
1101 vl_api_vec_to_api_string (const u8 * vec, vl_api_string_t * str)
1102 {
1103   u32 len = vec_len (vec);
1104   clib_memcpy (str->buf, vec, len);
1105   str->length = htonl (len);
1106   return len + sizeof (u32);
1107 }
1108
1109 u32
1110 vl_api_string_len (vl_api_string_t * astr)
1111 {
1112   return clib_net_to_host_u32 (astr->length);
1113 }
1114
1115 u8 *
1116 vl_api_format_string (u8 * s, va_list * args)
1117 {
1118   vl_api_string_t *a = va_arg (*args, vl_api_string_t *);
1119   vec_add (s, a->buf, clib_net_to_host_u32 (a->length));
1120   return s;
1121 }
1122
1123 /*
1124  * Returns a new vector. Remember to free it after use.
1125  * NOT nul terminated.
1126  */
1127 u8 *
1128 vl_api_from_api_to_new_vec (void *mp, vl_api_string_t * astr)
1129 {
1130   u8 *v = 0;
1131
1132   if (vl_msg_api_max_length (mp) < clib_net_to_host_u32 (astr->length))
1133     return format (0, "insane astr->length %u%c",
1134                    clib_net_to_host_u32 (astr->length), 0);
1135   vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length));
1136   return v;
1137 }
1138
1139 /*
1140  * Returns a new vector. Remember to free it after use.
1141  * Nul terminated.
1142  */
1143 char *
1144 vl_api_from_api_to_new_c_string (vl_api_string_t * astr)
1145 {
1146   char *v = 0;
1147   if (clib_net_to_host_u32 (astr->length) > 0)
1148     {
1149       vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length));
1150       vec_add1 (v, 0);
1151     }
1152   return v;
1153 }
1154
1155 void
1156 vl_api_set_elog_main (elog_main_t * m)
1157 {
1158   api_main_t *am = vlibapi_get_main ();
1159   am->elog_main = m;
1160 }
1161
1162 int
1163 vl_api_set_elog_trace_api_messages (int enable)
1164 {
1165   int rv;
1166   api_main_t *am = vlibapi_get_main ();
1167
1168   rv = am->elog_trace_api_messages;
1169   am->elog_trace_api_messages = enable;
1170   return rv;
1171 }
1172
1173 int
1174 vl_api_get_elog_trace_api_messages (void)
1175 {
1176   api_main_t *am = vlibapi_get_main ();
1177
1178   return am->elog_trace_api_messages;
1179 }
1180
1181 /*
1182  * fd.io coding-style-patch-verification: ON
1183  *
1184  * Local Variables:
1185  * eval: (c-set-style "gnu")
1186  * End:
1187  */