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