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