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