api: Remove the inlines file and replace with library functions
[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   int is_mp_safe = 1;
473
474   if (PREDICT_FALSE (vm->elog_trace_api_messages))
475     {
476       /* *INDENT-OFF* */
477       ELOG_TYPE_DECLARE (e) =
478         {
479           .format = "api-msg: %s",
480           .format_args = "T4",
481         };
482       /* *INDENT-ON* */
483       struct
484       {
485         u32 c;
486       } *ed;
487       ed = ELOG_DATA (&vm->elog_main, e);
488       if (id < vec_len (am->msg_names))
489         ed->c = elog_id_for_msg_name (vm, (const char *) am->msg_names[id]);
490       else
491         ed->c = elog_id_for_msg_name (vm, "BOGUS");
492     }
493
494   if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
495     {
496       handler = (void *) am->msg_handlers[id];
497
498       if (PREDICT_FALSE (am->rx_trace && am->rx_trace->enabled))
499         vl_msg_api_trace (am, am->rx_trace, the_msg);
500
501       if (PREDICT_FALSE (am->msg_print_flag))
502         {
503           fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
504           print_fp = (void *) am->msg_print_handlers[id];
505           if (print_fp == 0)
506             {
507               fformat (stdout, "  [no registered print fn for msg %d]\n", id);
508             }
509           else
510             {
511               (*print_fp) (the_msg, vm);
512             }
513         }
514       is_mp_safe = am->is_mp_safe[id];
515
516       if (!is_mp_safe)
517         {
518           vl_msg_api_barrier_trace_context (am->msg_names[id]);
519           vl_msg_api_barrier_sync ();
520         }
521       (*handler) (the_msg, vm, node);
522       if (!is_mp_safe)
523         vl_msg_api_barrier_release ();
524     }
525   else
526     {
527       clib_warning ("no handler for msg id %d", id);
528     }
529
530   /*
531    * Special-case, so we can e.g. bounce messages off the vnet
532    * main thread without copying them...
533    */
534   if (!(am->message_bounce[id]))
535     vl_msg_api_free (the_msg);
536
537   if (PREDICT_FALSE (vm->elog_trace_api_messages))
538     {
539       /* *INDENT-OFF* */
540       ELOG_TYPE_DECLARE (e) =
541         {
542           .format = "api-msg-done(%s): %s",
543           .format_args = "t4T4",
544           .n_enum_strings = 2,
545           .enum_strings =
546           {
547             "barrier",
548             "mp-safe",
549           }
550         };
551       /* *INDENT-ON* */
552
553       struct
554       {
555         u32 barrier;
556         u32 c;
557       } *ed;
558       ed = ELOG_DATA (&vm->elog_main, e);
559       if (id < vec_len (am->msg_names))
560         ed->c = elog_id_for_msg_name (vm, (const char *) am->msg_names[id]);
561       else
562         ed->c = elog_id_for_msg_name (vm, "BOGUS");
563       ed->barrier = is_mp_safe;
564     }
565 }
566
567 void
568 vl_msg_api_handler (void *the_msg)
569 {
570   api_main_t *am = &api_main;
571
572   msg_handler_internal (am, the_msg,
573                         (am->rx_trace
574                          && am->rx_trace->enabled) /* trace_it */ ,
575                         1 /* do_it */ , 1 /* free_it */ );
576 }
577
578 void
579 vl_msg_api_handler_no_free (void *the_msg)
580 {
581   api_main_t *am = &api_main;
582   msg_handler_internal (am, the_msg,
583                         (am->rx_trace
584                          && am->rx_trace->enabled) /* trace_it */ ,
585                         1 /* do_it */ , 0 /* free_it */ );
586 }
587
588 void
589 vl_msg_api_handler_no_trace_no_free (void *the_msg)
590 {
591   api_main_t *am = &api_main;
592   msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
593                         0 /* free_it */ );
594 }
595
596 /*
597  * Add a trace record to the API message trace buffer, if
598  * API message tracing is enabled. Handy for adding sufficient
599  * data to the trace to reproduce autonomous state, as opposed to
600  * state downloaded via control-plane API messages. Example: the NAT
601  * application creates database entries based on packet traffic, not
602  * control-plane messages.
603  *
604  */
605 void
606 vl_msg_api_trace_only (void *the_msg)
607 {
608   api_main_t *am = &api_main;
609
610   msg_handler_internal (am, the_msg,
611                         (am->rx_trace
612                          && am->rx_trace->enabled) /* trace_it */ ,
613                         0 /* do_it */ , 0 /* free_it */ );
614 }
615
616 void
617 vl_msg_api_cleanup_handler (void *the_msg)
618 {
619   api_main_t *am = &api_main;
620   u16 id = ntohs (*((u16 *) the_msg));
621
622   if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
623     {
624       clib_warning ("_vl_msg_id too large: %d\n", id);
625       return;
626     }
627   if (am->msg_cleanup_handlers[id])
628     (*am->msg_cleanup_handlers[id]) (the_msg);
629
630   vl_msg_api_free (the_msg);
631 }
632
633 /*
634  * vl_msg_api_replay_handler
635  */
636 void
637 vl_msg_api_replay_handler (void *the_msg)
638 {
639   api_main_t *am = &api_main;
640
641   u16 id = ntohs (*((u16 *) the_msg));
642
643   if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
644     {
645       clib_warning ("_vl_msg_id too large: %d\n", id);
646       return;
647     }
648   /* do NOT trace the message... */
649   if (am->msg_handlers[id])
650     (*am->msg_handlers[id]) (the_msg);
651   /* do NOT free the message buffer... */
652 }
653
654 u32
655 vl_msg_api_get_msg_length (void *msg_arg)
656 {
657   return vl_msg_api_get_msg_length_inline (msg_arg);
658 }
659
660 /*
661  * vl_msg_api_socket_handler
662  */
663 void
664 vl_msg_api_socket_handler (void *the_msg)
665 {
666   api_main_t *am = &api_main;
667
668   msg_handler_internal (am, the_msg,
669                         (am->rx_trace
670                          && am->rx_trace->enabled) /* trace_it */ ,
671                         1 /* do_it */ , 0 /* free_it */ );
672 }
673
674 #define foreach_msg_api_vector                  \
675 _(msg_names)                                    \
676 _(msg_handlers)                                 \
677 _(msg_cleanup_handlers)                         \
678 _(msg_endian_handlers)                          \
679 _(msg_print_handlers)                           \
680 _(api_trace_cfg)                                \
681 _(message_bounce)                               \
682 _(is_mp_safe)
683
684 void
685 vl_msg_api_config (vl_msg_api_msg_config_t * c)
686 {
687   api_main_t *am = &api_main;
688
689   /*
690    * This happens during the java core tests if the message
691    * dictionary is missing newly added xxx_reply_t messages.
692    * Should never happen, but since I shot myself in the foot once
693    * this way, I thought I'd make it easy to debug if I ever do
694    * it again... (;-)...
695    */
696   if (c->id == 0)
697     {
698       if (c->name)
699         clib_warning ("Trying to register %s with a NULL msg id!", c->name);
700       else
701         clib_warning ("Trying to register a NULL msg with a NULL msg id!");
702       clib_warning ("Did you forget to call setup_message_id_table?");
703       return;
704     }
705
706 #define _(a) vec_validate (am->a, c->id);
707   foreach_msg_api_vector;
708 #undef _
709
710   if (am->msg_handlers[c->id] && am->msg_handlers[c->id] != c->handler)
711     clib_warning
712       ("BUG: re-registering 'vl_api_%s_t_handler'."
713        "Handler was %llx, replaced by %llx",
714        c->name, am->msg_handlers[c->id], c->handler);
715
716   am->msg_names[c->id] = c->name;
717   am->msg_handlers[c->id] = c->handler;
718   am->msg_cleanup_handlers[c->id] = c->cleanup;
719   am->msg_endian_handlers[c->id] = c->endian;
720   am->msg_print_handlers[c->id] = c->print;
721   am->message_bounce[c->id] = c->message_bounce;
722   am->is_mp_safe[c->id] = c->is_mp_safe;
723
724   am->api_trace_cfg[c->id].size = c->size;
725   am->api_trace_cfg[c->id].trace_enable = c->traced;
726   am->api_trace_cfg[c->id].replay_enable = c->replay;
727 }
728
729 /*
730  * vl_msg_api_set_handlers
731  * preserve the old API for a while
732  */
733 void
734 vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
735                          void *endian, void *print, int size, int traced)
736 {
737   vl_msg_api_msg_config_t cfg;
738   vl_msg_api_msg_config_t *c = &cfg;
739
740   clib_memset (c, 0, sizeof (*c));
741
742   c->id = id;
743   c->name = name;
744   c->handler = handler;
745   c->cleanup = cleanup;
746   c->endian = endian;
747   c->print = print;
748   c->traced = traced;
749   c->replay = 1;
750   c->message_bounce = 0;
751   c->is_mp_safe = 0;
752   vl_msg_api_config (c);
753 }
754
755 void
756 vl_msg_api_clean_handlers (int msg_id)
757 {
758   vl_msg_api_msg_config_t cfg;
759   vl_msg_api_msg_config_t *c = &cfg;
760
761   clib_memset (c, 0, sizeof (*c));
762
763   c->id = msg_id;
764   vl_msg_api_config (c);
765 }
766
767 void
768 vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
769 {
770   api_main_t *am = &api_main;
771   ASSERT (msg_id > 0);
772
773   vec_validate (am->msg_cleanup_handlers, msg_id);
774   am->msg_cleanup_handlers[msg_id] = fp;
775 }
776
777 void
778 vl_msg_api_queue_handler (svm_queue_t * q)
779 {
780   uword msg;
781
782   while (!svm_queue_sub (q, (u8 *) & msg, SVM_Q_WAIT, 0))
783     vl_msg_api_handler ((void *) msg);
784 }
785
786 vl_api_trace_t *
787 vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
788 {
789   switch (which)
790     {
791     case VL_API_TRACE_RX:
792       return am->rx_trace;
793     case VL_API_TRACE_TX:
794       return am->tx_trace;
795     default:
796       return 0;
797     }
798 }
799
800 void
801 vl_noop_handler (void *mp)
802 {
803 }
804
805
806 static u8 post_mortem_dump_enabled;
807
808 void
809 vl_msg_api_post_mortem_dump_enable_disable (int enable)
810 {
811   post_mortem_dump_enabled = enable;
812 }
813
814 void
815 vl_msg_api_post_mortem_dump (void)
816 {
817   api_main_t *am = &api_main;
818   FILE *fp;
819   char filename[64];
820   int rv;
821
822   if (post_mortem_dump_enabled == 0)
823     return;
824
825   snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
826             getpid ());
827
828   fp = fopen (filename, "w");
829   if (fp == NULL)
830     {
831       rv = write (2, "Couldn't create ", 16);
832       rv = write (2, filename, strlen (filename));
833       rv = write (2, "\n", 1);
834       return;
835     }
836   rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
837   fclose (fp);
838   if (rv < 0)
839     {
840       rv = write (2, "Failed to save post-mortem API trace to ", 40);
841       rv = write (2, filename, strlen (filename));
842       rv = write (2, "\n", 1);
843     }
844
845 }
846
847 /* Layered message handling support */
848
849 void
850 vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
851 {
852   api_main_t *am = &api_main;
853
854   /* Mild idiot proofing */
855   if (msg_id_host_byte_order > 10000)
856     clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
857                   msg_id_host_byte_order,
858                   clib_net_to_host_u16 (msg_id_host_byte_order));
859   vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
860   am->pd_msg_handlers[msg_id_host_byte_order] = fp;
861 }
862
863 int
864 vl_msg_api_pd_handler (void *mp, int rv)
865 {
866   api_main_t *am = &api_main;
867   int (*fp) (void *, int);
868   u16 msg_id;
869
870   if (clib_arch_is_little_endian)
871     msg_id = clib_net_to_host_u16 (*((u16 *) mp));
872   else
873     msg_id = *((u16 *) mp);
874
875   if (msg_id >= vec_len (am->pd_msg_handlers)
876       || am->pd_msg_handlers[msg_id] == 0)
877     return rv;
878
879   fp = am->pd_msg_handlers[msg_id];
880   rv = (*fp) (mp, rv);
881   return rv;
882 }
883
884 void
885 vl_msg_api_set_first_available_msg_id (u16 first_avail)
886 {
887   api_main_t *am = &api_main;
888
889   am->first_available_msg_id = first_avail;
890 }
891
892 u16
893 vl_msg_api_get_msg_ids (const char *name, int n)
894 {
895   api_main_t *am = &api_main;
896   u8 *name_copy;
897   vl_api_msg_range_t *rp;
898   uword *p;
899   u16 rv;
900
901   if (am->msg_range_by_name == 0)
902     am->msg_range_by_name = hash_create_string (0, sizeof (uword));
903
904   name_copy = format (0, "%s%c", name, 0);
905
906   p = hash_get_mem (am->msg_range_by_name, name_copy);
907   if (p)
908     {
909       clib_warning ("WARNING: duplicate message range registration for '%s'",
910                     name_copy);
911       vec_free (name_copy);
912       return ((u16) ~ 0);
913     }
914
915   if (n < 0 || n > 1024)
916     {
917       clib_warning
918         ("WARNING: bad number of message-IDs (%d) requested by '%s'",
919          n, name_copy);
920       vec_free (name_copy);
921       return ((u16) ~ 0);
922     }
923
924   vec_add2 (am->msg_ranges, rp, 1);
925
926   rv = rp->first_msg_id = am->first_available_msg_id;
927   am->first_available_msg_id += n;
928   rp->last_msg_id = am->first_available_msg_id - 1;
929   rp->name = name_copy;
930
931   hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
932
933   return rv;
934 }
935
936 void
937 vl_msg_api_add_msg_name_crc (api_main_t * am, const char *string, u32 id)
938 {
939   uword *p;
940
941   if (am->msg_index_by_name_and_crc == 0)
942     am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
943
944   p = hash_get_mem (am->msg_index_by_name_and_crc, string);
945   if (p)
946     {
947       clib_warning ("attempt to redefine '%s' ignored...", string);
948       return;
949     }
950
951   hash_set_mem (am->msg_index_by_name_and_crc, string, id);
952 }
953
954 void
955 vl_msg_api_add_version (api_main_t * am, const char *string,
956                         u32 major, u32 minor, u32 patch)
957 {
958   api_version_t version = {.major = major,.minor = minor,.patch = patch };
959   ASSERT (strlen (string) < 64);
960   strncpy (version.name, string, 64 - 1);
961   vec_add1 (am->api_version_list, version);
962 }
963
964 u32
965 vl_msg_api_get_msg_index (u8 * name_and_crc)
966 {
967   api_main_t *am = &api_main;
968   uword *p;
969
970   if (am->msg_index_by_name_and_crc)
971     {
972       p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc);
973       if (p)
974         return p[0];
975     }
976   return ~0;
977 }
978
979 void *
980 vl_msg_push_heap (void)
981 {
982   api_main_t *am = &api_main;
983   pthread_mutex_lock (&am->vlib_rp->mutex);
984   return svm_push_data_heap (am->vlib_rp);
985 }
986
987 void
988 vl_msg_pop_heap (void *oldheap)
989 {
990   api_main_t *am = &api_main;
991   svm_pop_heap (oldheap);
992   pthread_mutex_unlock (&am->vlib_rp->mutex);
993 }
994
995 int
996 vl_api_to_api_string (u32 len, const char *buf, vl_api_string_t * str)
997 {
998   clib_memcpy_fast (str->buf, buf, len);
999   str->length = htonl (len);
1000   return len + sizeof (u32);
1001 }
1002
1003 int
1004 vl_api_vec_to_api_string (const u8 * vec, vl_api_string_t * str)
1005 {
1006   u32 len = vec_len (vec);
1007   clib_memcpy (str->buf, vec, len);
1008   str->length = htonl (len);
1009   return len + sizeof (u32);
1010 }
1011
1012 /* Return a pointer to the API string (not nul terminated */
1013 u8 *
1014 vl_api_from_api_string (vl_api_string_t * astr)
1015 {
1016   return astr->buf;
1017 }
1018
1019 u32
1020 vl_api_string_len (vl_api_string_t * astr)
1021 {
1022   return ntohl (astr->length);
1023 }
1024
1025 /*
1026  * Returns a new vector. Remember to free it after use.
1027  */
1028 u8 *
1029 vl_api_from_api_to_vec (vl_api_string_t * astr)
1030 {
1031   u8 *v = 0;
1032   vec_add (v, astr->buf, ntohl (astr->length));
1033   return v;
1034 }
1035
1036 /*
1037  * fd.io coding-style-patch-verification: ON
1038  *
1039  * Local Variables:
1040  * eval: (c-set-style "gnu")
1041  * End:
1042  */