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