blob: c62ac5b18a58abef7b4ad9d812b1115e91aef366 [file] [log] [blame]
Dave Barach371e4e12016-07-08 09:38:52 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
3 * api_shared.c - API message handling, common code for both clients
4 * and the vlib process itself.
Dave Barach371e4e12016-07-08 09:38:52 -04005 *
Ed Warnickecb9cada2015-12-08 15:45:58 -07006 *
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 <string.h>
25#include <sys/types.h>
26#include <sys/mman.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <vppinfra/format.h>
31#include <vppinfra/byte_order.h>
32#include <vppinfra/error.h>
33#include <vlib/vlib.h>
34#include <vlib/unix/unix.h>
35#include <vlibapi/api.h>
36#include <vppinfra/elog.h>
37
38api_main_t api_main;
39
Dave Barach371e4e12016-07-08 09:38:52 -040040void vl_msg_api_barrier_sync (void) __attribute__ ((weak));
41void
42vl_msg_api_barrier_sync (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070043{
Ed Warnickecb9cada2015-12-08 15:45:58 -070044}
45
Dave Barach371e4e12016-07-08 09:38:52 -040046void vl_msg_api_barrier_release (void) __attribute__ ((weak));
47void
48vl_msg_api_barrier_release (void)
49{
50}
51
52void
53vl_msg_api_increment_missing_client_counter (void)
54{
55 api_main_t *am = &api_main;
56 am->missing_clients++;
57}
58
59typedef enum
60{
61 DUMP,
62 CUSTOM_DUMP,
63 REPLAY,
64 INITIALIZERS,
Ed Warnickecb9cada2015-12-08 15:45:58 -070065} vl_api_replay_t;
66
Dave Barach371e4e12016-07-08 09:38:52 -040067int
68vl_msg_api_rx_trace_enabled (api_main_t * am)
Ed Warnickecb9cada2015-12-08 15:45:58 -070069{
Dave Barach371e4e12016-07-08 09:38:52 -040070 return (am->rx_trace && am->rx_trace->enabled);
Ed Warnickecb9cada2015-12-08 15:45:58 -070071}
72
Dave Barach371e4e12016-07-08 09:38:52 -040073int
74vl_msg_api_tx_trace_enabled (api_main_t * am)
Ed Warnickecb9cada2015-12-08 15:45:58 -070075{
Dave Barach371e4e12016-07-08 09:38:52 -040076 return (am->tx_trace && am->tx_trace->enabled);
Ed Warnickecb9cada2015-12-08 15:45:58 -070077}
78
79/*
80 * vl_msg_api_trace
81 */
Dave Barach371e4e12016-07-08 09:38:52 -040082void
83vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -070084{
Dave Barach371e4e12016-07-08 09:38:52 -040085 u8 **this_trace;
86 u8 **old_trace;
87 u8 *msg_copy;
88 trace_cfg_t *cfgp;
89 u16 msg_id = ntohs (*((u16 *) msg));
Ed Warnickecb9cada2015-12-08 15:45:58 -070090
Dave Barach371e4e12016-07-08 09:38:52 -040091 cfgp = am->api_trace_cfg + msg_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -070092
Dave Barach371e4e12016-07-08 09:38:52 -040093 if (!cfgp || !cfgp->trace_enable)
94 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
Dave Barach371e4e12016-07-08 09:38:52 -040096 msg_copy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
Dave Barach371e4e12016-07-08 09:38:52 -040098 if (tp->nitems == 0)
99 {
100 clib_warning ("tp->nitems is 0");
101 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102 }
103
Dave Barach371e4e12016-07-08 09:38:52 -0400104 if (vec_len (tp->traces) < tp->nitems)
105 {
106 vec_add1 (tp->traces, 0);
107 this_trace = tp->traces + vec_len (tp->traces) - 1;
108 }
109 else
110 {
111 tp->wrapped = 1;
112 old_trace = tp->traces + tp->curindex++;
113 if (tp->curindex == tp->nitems)
114 tp->curindex = 0;
115 vec_free (*old_trace);
116 this_trace = old_trace;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700117 }
118
Dave Barach371e4e12016-07-08 09:38:52 -0400119 vec_validate (msg_copy, cfgp->size - 1);
120 clib_memcpy (msg_copy, msg, cfgp->size);
121 *this_trace = msg_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122}
123
Dave Barach371e4e12016-07-08 09:38:52 -0400124int
125vl_msg_api_trace_onoff (api_main_t * am, vl_api_trace_which_t which,
126 int onoff)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127{
Dave Barach371e4e12016-07-08 09:38:52 -0400128 vl_api_trace_t *tp;
129 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barach371e4e12016-07-08 09:38:52 -0400131 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 {
133 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400134 tp = am->tx_trace;
135 if (tp == 0)
136 {
137 vl_msg_api_trace_configure (am, which, 1024);
138 tp = am->tx_trace;
139 }
140 break;
141
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400143 tp = am->rx_trace;
144 if (tp == 0)
145 {
146 vl_msg_api_trace_configure (am, which, 1024);
147 tp = am->rx_trace;
148 }
149 break;
150
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400152 /* duh? */
153 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 }
155
Dave Barach371e4e12016-07-08 09:38:52 -0400156 /* Configured? */
157 if (tp == 0 || tp->nitems == 0)
158 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159
Dave Barach371e4e12016-07-08 09:38:52 -0400160 rv = tp->enabled;
161 tp->enabled = onoff;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162
Dave Barach371e4e12016-07-08 09:38:52 -0400163 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164}
165
Dave Barach371e4e12016-07-08 09:38:52 -0400166int
167vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168{
Dave Barach371e4e12016-07-08 09:38:52 -0400169 vl_api_trace_t *tp;
170 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
Dave Barach371e4e12016-07-08 09:38:52 -0400172 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173 {
174 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400175 tp = am->tx_trace;
176 break;
177
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400179 tp = am->rx_trace;
180 break;
181
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400183 /* duh? */
184 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185 }
186
Dave Barach371e4e12016-07-08 09:38:52 -0400187 /* Configured? */
188 if (!tp || tp->nitems == 0)
189 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190
Dave Barach371e4e12016-07-08 09:38:52 -0400191 tp->curindex = 0;
192 tp->wrapped = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193
Dave Barach371e4e12016-07-08 09:38:52 -0400194 for (i = 0; i < vec_len (tp->traces); i++)
195 {
196 vec_free (tp->traces[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 }
Dave Barach371e4e12016-07-08 09:38:52 -0400198 vec_free (tp->traces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199
Dave Barach371e4e12016-07-08 09:38:52 -0400200 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201}
202
Dave Barach371e4e12016-07-08 09:38:52 -0400203int
204vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205{
Dave Barach371e4e12016-07-08 09:38:52 -0400206 vl_api_trace_t *tp;
207 vl_api_trace_file_header_t fh;
208 int i;
209 u8 *msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
Dave Barach371e4e12016-07-08 09:38:52 -0400211 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 {
213 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400214 tp = am->tx_trace;
215 break;
216
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400218 tp = am->rx_trace;
219 break;
220
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400222 /* duh? */
223 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 }
225
Dave Barach371e4e12016-07-08 09:38:52 -0400226 /* Configured, data present? */
227 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
228 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
Dave Barach371e4e12016-07-08 09:38:52 -0400230 /* "Dare to be stupid" check */
231 if (fp == 0)
232 {
233 return -2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 }
235
Dave Barach371e4e12016-07-08 09:38:52 -0400236 /* Write the file header */
237 fh.nitems = vec_len (tp->traces);
238 fh.endian = tp->endian;
239 fh.wrapped = tp->wrapped;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240
Dave Barach371e4e12016-07-08 09:38:52 -0400241 if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
242 {
243 return (-10);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 }
245
Dave Barach371e4e12016-07-08 09:38:52 -0400246 /* No-wrap case */
247 if (tp->wrapped == 0)
248 {
249 /*
250 * Note: vec_len return 0 when fed a NULL pointer.
251 * Unfortunately, the static analysis tool doesn't
252 * figure it out, hence the suppressed warnings.
253 * What a great use of my time.
254 */
255 for (i = 0; i < vec_len (tp->traces); i++)
256 {
257 /*sa_ignore NO_NULL_CHK */
258 msg = tp->traces[i];
259 /*
260 * This retarded check required to pass
261 * [sic] SA-checking.
262 */
263 if (!msg)
264 continue;
265 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
266 {
267 return (-11);
268 }
269 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 }
Dave Barach371e4e12016-07-08 09:38:52 -0400271 else
272 {
273 /* Wrap case: write oldest -> end of buffer */
274 for (i = tp->curindex; i < vec_len (tp->traces); i++)
275 {
276 msg = tp->traces[i];
277 /*
278 * This retarded check required to pass
279 * [sic] SA-checking
280 */
281 if (!msg)
282 continue;
283
284 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
285 {
286 return (-12);
287 }
288 }
289 /* write beginning of buffer -> oldest-1 */
290 for (i = 0; i < tp->curindex; i++)
291 {
292 /*sa_ignore NO_NULL_CHK */
293 msg = tp->traces[i];
294 /*
295 * This retarded check required to pass
296 * [sic] SA-checking
297 */
298 if (!msg)
299 continue;
300
301 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
302 {
303 return (-13);
304 }
305 }
306 }
307 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308}
309
Dave Barach371e4e12016-07-08 09:38:52 -0400310int
311vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
312 u32 nitems)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313{
Dave Barach371e4e12016-07-08 09:38:52 -0400314 vl_api_trace_t *tp;
315 int was_on = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316
Dave Barach371e4e12016-07-08 09:38:52 -0400317 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 {
319 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400320 tp = am->tx_trace;
321 if (tp == 0)
322 {
323 vec_validate (am->tx_trace, 0);
324 tp = am->tx_trace;
325 }
326 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327
Dave Barach371e4e12016-07-08 09:38:52 -0400328 case VL_API_TRACE_RX:
329 tp = am->rx_trace;
330 if (tp == 0)
331 {
332 vec_validate (am->rx_trace, 0);
333 tp = am->rx_trace;
334 }
335
336 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337
338 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400339 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
341 }
342
Dave Barach371e4e12016-07-08 09:38:52 -0400343 if (tp->enabled)
344 {
345 was_on = vl_msg_api_trace_onoff (am, which, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346 }
Dave Barach371e4e12016-07-08 09:38:52 -0400347 if (tp->traces)
348 {
349 vl_msg_api_trace_free (am, which);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350 }
351
Dave Barach371e4e12016-07-08 09:38:52 -0400352 memset (tp, 0, sizeof (*tp));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700353
Dave Barach371e4e12016-07-08 09:38:52 -0400354 if (clib_arch_is_big_endian)
355 {
356 tp->endian = VL_API_BIG_ENDIAN;
357 }
358 else
359 {
360 tp->endian = VL_API_LITTLE_ENDIAN;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361 }
362
Dave Barach371e4e12016-07-08 09:38:52 -0400363 tp->nitems = nitems;
364 if (was_on)
365 {
366 (void) vl_msg_api_trace_onoff (am, which, was_on);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367 }
Dave Barach371e4e12016-07-08 09:38:52 -0400368 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369}
370
Dave Barach371e4e12016-07-08 09:38:52 -0400371always_inline void
372msg_handler_internal (api_main_t * am,
373 void *the_msg, int trace_it, int do_it, int free_it)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374{
Dave Barach371e4e12016-07-08 09:38:52 -0400375 u16 id = ntohs (*((u16 *) the_msg));
376 u8 *(*print_fp) (void *, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377
Dave Barach371e4e12016-07-08 09:38:52 -0400378 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
379 {
380 if (trace_it)
381 vl_msg_api_trace (am, am->rx_trace, the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Dave Barach371e4e12016-07-08 09:38:52 -0400383 if (am->msg_print_flag)
384 {
385 fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
386 print_fp = (void *) am->msg_print_handlers[id];
387 if (print_fp == 0)
388 {
389 fformat (stdout, " [no registered print fn]\n");
390 }
391 else
392 {
393 (*print_fp) (the_msg, stdout);
394 }
395 }
396
397 if (do_it)
398 {
399 if (!am->is_mp_safe[id])
400 vl_msg_api_barrier_sync ();
401 (*am->msg_handlers[id]) (the_msg);
402 if (!am->is_mp_safe[id])
403 vl_msg_api_barrier_release ();
404 }
405 }
406 else
407 {
408 clib_warning ("no handler for msg id %d", id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 }
410
Dave Barach371e4e12016-07-08 09:38:52 -0400411 if (free_it)
412 vl_msg_api_free (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413}
414
415/* set to 1 if you want before/after message handler event logging */
416#define ELOG_API_MESSAGE_HANDLERS 0
417
418#if ELOG_API_MESSAGE_HANDLERS > 0
Dave Barach371e4e12016-07-08 09:38:52 -0400419static u32
420elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421{
Dave Barach371e4e12016-07-08 09:38:52 -0400422 uword *p, r;
423 static uword *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 u8 *name_copy;
425
Dave Barach371e4e12016-07-08 09:38:52 -0400426 if (!h)
427 h = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428
429 p = hash_get_mem (h, msg_name);
430 if (p)
431 return p[0];
432 r = elog_string (&vm->elog_main, "%s", msg_name);
433
434 name_copy = format (0, "%s%c", msg_name, 0);
435
436 hash_set_mem (h, name_copy, r);
437
438 return r;
439}
440#endif
441
442/* This is only to be called from a vlib/vnet app */
Dave Barach371e4e12016-07-08 09:38:52 -0400443void
444vl_msg_api_handler_with_vm_node (api_main_t * am,
445 void *the_msg, vlib_main_t * vm,
446 vlib_node_runtime_t * node)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447{
Dave Barach371e4e12016-07-08 09:38:52 -0400448 u16 id = ntohs (*((u16 *) the_msg));
449 u8 *(*handler) (void *, void *, void *);
450
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451#if ELOG_API_MESSAGE_HANDLERS > 0
Dave Barach371e4e12016-07-08 09:38:52 -0400452 {
453 /* *INDENT-OFF* */
454 ELOG_TYPE_DECLARE (e) =
455 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456 .format = "api-msg: %s",
457 .format_args = "T4",
458 };
Dave Barach371e4e12016-07-08 09:38:52 -0400459 /* *INDENT-ON* */
460 struct
461 {
462 u32 c;
463 } *ed;
464 ed = ELOG_DATA (&vm->elog_main, e);
465 if (id < vec_len (am->msg_names))
466 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
467 else
468 ed->c = elog_id_for_msg_name (vm, "BOGUS");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 }
Dave Barach371e4e12016-07-08 09:38:52 -0400470#endif
471
472 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
473 {
474 handler = (void *) am->msg_handlers[id];
475
476 if (am->rx_trace && am->rx_trace->enabled)
477 vl_msg_api_trace (am, am->rx_trace, the_msg);
478
479 if (!am->is_mp_safe[id])
480 vl_msg_api_barrier_sync ();
481 (*handler) (the_msg, vm, node);
482 if (!am->is_mp_safe[id])
483 vl_msg_api_barrier_release ();
484 }
485 else
486 {
487 clib_warning ("no hander for msg id %d", id);
488 }
489
490 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 * Special-case, so we can e.g. bounce messages off the vnet
492 * main thread without copying them...
493 */
494 if (!(am->message_bounce[id]))
Dave Barach371e4e12016-07-08 09:38:52 -0400495 vl_msg_api_free (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496
497#if ELOG_API_MESSAGE_HANDLERS > 0
Dave Barach371e4e12016-07-08 09:38:52 -0400498 {
499 /* *INDENT-OFF* */
500 ELOG_TYPE_DECLARE (e) = {
501 .format = "api-msg-done: %s",
502 .format_args = "T4",
503 };
504 /* *INDENT-ON* */
505
506 struct
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507 {
Dave Barach371e4e12016-07-08 09:38:52 -0400508 u32 c;
509 } *ed;
510 ed = ELOG_DATA (&vm->elog_main, e);
511 if (id < vec_len (am->msg_names))
512 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
513 else
514 ed->c = elog_id_for_msg_name (vm, "BOGUS");
515 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700516#endif
517}
518
Dave Barach371e4e12016-07-08 09:38:52 -0400519void
520vl_msg_api_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521{
Dave Barach371e4e12016-07-08 09:38:52 -0400522 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523
Dave Barach371e4e12016-07-08 09:38:52 -0400524 msg_handler_internal (am, the_msg,
525 (am->rx_trace
526 && am->rx_trace->enabled) /* trace_it */ ,
527 1 /* do_it */ , 1 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528}
529
Dave Barach371e4e12016-07-08 09:38:52 -0400530void
531vl_msg_api_handler_no_free (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532{
Dave Barach371e4e12016-07-08 09:38:52 -0400533 api_main_t *am = &api_main;
534 msg_handler_internal (am, the_msg,
535 (am->rx_trace
536 && am->rx_trace->enabled) /* trace_it */ ,
537 1 /* do_it */ , 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700538}
539
Dave Barach371e4e12016-07-08 09:38:52 -0400540void
541vl_msg_api_handler_no_trace_no_free (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542{
Dave Barach371e4e12016-07-08 09:38:52 -0400543 api_main_t *am = &api_main;
544 msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
545 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700546}
547
548/*
549 * Add a trace record to the API message trace buffer, if
550 * API message tracing is enabled. Handy for adding sufficient
551 * data to the trace to reproduce autonomous state, as opposed to
Dave Barach371e4e12016-07-08 09:38:52 -0400552 * state downloaded via control-plane API messages. Example: the NAT
Ed Warnickecb9cada2015-12-08 15:45:58 -0700553 * application creates database entries based on packet traffic, not
554 * control-plane messages.
555 *
556 */
Dave Barach371e4e12016-07-08 09:38:52 -0400557void
558vl_msg_api_trace_only (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559{
Dave Barach371e4e12016-07-08 09:38:52 -0400560 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561
Dave Barach371e4e12016-07-08 09:38:52 -0400562 msg_handler_internal (am, the_msg,
563 (am->rx_trace
564 && am->rx_trace->enabled) /* trace_it */ ,
565 0 /* do_it */ , 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566}
567
Dave Barach371e4e12016-07-08 09:38:52 -0400568void
569vl_msg_api_cleanup_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700570{
Dave Barach371e4e12016-07-08 09:38:52 -0400571 api_main_t *am = &api_main;
572 u16 id = ntohs (*((u16 *) the_msg));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573
Dave Barach371e4e12016-07-08 09:38:52 -0400574 if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
575 {
576 clib_warning ("_vl_msg_id too large: %d\n", id);
577 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700578 }
Dave Barach371e4e12016-07-08 09:38:52 -0400579 if (am->msg_cleanup_handlers[id])
580 (*am->msg_cleanup_handlers[id]) (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
Dave Barach371e4e12016-07-08 09:38:52 -0400582 vl_msg_api_free (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583}
584
585/*
586 * vl_msg_api_replay_handler
587 */
Dave Barach371e4e12016-07-08 09:38:52 -0400588void
589vl_msg_api_replay_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590{
Dave Barach371e4e12016-07-08 09:38:52 -0400591 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592
Dave Barach371e4e12016-07-08 09:38:52 -0400593 u16 id = ntohs (*((u16 *) the_msg));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700594
Dave Barach371e4e12016-07-08 09:38:52 -0400595 if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
596 {
597 clib_warning ("_vl_msg_id too large: %d\n", id);
598 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599 }
Dave Barach371e4e12016-07-08 09:38:52 -0400600 /* do NOT trace the message... */
601 if (am->msg_handlers[id])
602 (*am->msg_handlers[id]) (the_msg);
603 /* do NOT free the message buffer... */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604}
Dave Barach371e4e12016-07-08 09:38:52 -0400605
Ed Warnickecb9cada2015-12-08 15:45:58 -0700606/*
607 * vl_msg_api_socket_handler
608 */
Dave Barach371e4e12016-07-08 09:38:52 -0400609void
610vl_msg_api_socket_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700611{
Dave Barach371e4e12016-07-08 09:38:52 -0400612 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700613
Dave Barach371e4e12016-07-08 09:38:52 -0400614 msg_handler_internal (am, the_msg,
615 (am->rx_trace
616 && am->rx_trace->enabled) /* trace_it */ ,
617 1 /* do_it */ , 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618}
619
620#define foreach_msg_api_vector \
621_(msg_names) \
622_(msg_handlers) \
623_(msg_cleanup_handlers) \
624_(msg_endian_handlers) \
625_(msg_print_handlers) \
626_(api_trace_cfg) \
627_(message_bounce) \
628_(is_mp_safe)
629
Dave Barach371e4e12016-07-08 09:38:52 -0400630void
631vl_msg_api_config (vl_msg_api_msg_config_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632{
Dave Barach371e4e12016-07-08 09:38:52 -0400633 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
Dave Barach371e4e12016-07-08 09:38:52 -0400635 ASSERT (c->id > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636
637#define _(a) vec_validate (am->a, c->id);
Dave Barach371e4e12016-07-08 09:38:52 -0400638 foreach_msg_api_vector;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639#undef _
640
Dave Barach371e4e12016-07-08 09:38:52 -0400641 am->msg_names[c->id] = c->name;
642 am->msg_handlers[c->id] = c->handler;
643 am->msg_cleanup_handlers[c->id] = c->cleanup;
644 am->msg_endian_handlers[c->id] = c->endian;
645 am->msg_print_handlers[c->id] = c->print;
646 am->message_bounce[c->id] = c->message_bounce;
647 am->is_mp_safe[c->id] = c->is_mp_safe;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648
Dave Barach371e4e12016-07-08 09:38:52 -0400649 am->api_trace_cfg[c->id].size = c->size;
650 am->api_trace_cfg[c->id].trace_enable = c->traced;
651 am->api_trace_cfg[c->id].replay_enable = c->replay;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652}
653
Dave Barach371e4e12016-07-08 09:38:52 -0400654/*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655 * vl_msg_api_set_handlers
656 * preserve the old API for a while
657 */
Dave Barach371e4e12016-07-08 09:38:52 -0400658void
659vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
660 void *endian, void *print, int size, int traced)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661{
Dave Barach371e4e12016-07-08 09:38:52 -0400662 vl_msg_api_msg_config_t cfg;
663 vl_msg_api_msg_config_t *c = &cfg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664
Dave Barach371e4e12016-07-08 09:38:52 -0400665 c->id = id;
666 c->name = name;
667 c->handler = handler;
668 c->cleanup = cleanup;
669 c->endian = endian;
670 c->print = print;
671 c->size = size;
672 c->traced = traced;
673 c->replay = 1;
674 c->message_bounce = 0;
675 c->is_mp_safe = 0;
676 vl_msg_api_config (c);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677}
678
Dave Barach371e4e12016-07-08 09:38:52 -0400679void
680vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681{
Dave Barach371e4e12016-07-08 09:38:52 -0400682 api_main_t *am = &api_main;
683 ASSERT (msg_id > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684
Dave Barach371e4e12016-07-08 09:38:52 -0400685 vec_validate (am->msg_cleanup_handlers, msg_id);
686 am->msg_cleanup_handlers[msg_id] = fp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687}
688
Dave Barach371e4e12016-07-08 09:38:52 -0400689void
690vl_msg_api_queue_handler (unix_shared_memory_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700691{
Dave Barach371e4e12016-07-08 09:38:52 -0400692 uword msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693
Dave Barach371e4e12016-07-08 09:38:52 -0400694 while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
695 vl_msg_api_handler ((void *) msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696}
697
Dave Barach371e4e12016-07-08 09:38:52 -0400698vl_api_trace_t *
699vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700{
Dave Barach371e4e12016-07-08 09:38:52 -0400701 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700702 {
703 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400704 return am->rx_trace;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400706 return am->tx_trace;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400708 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700709 }
710}
711
Dave Barach371e4e12016-07-08 09:38:52 -0400712void
713vl_noop_handler (void *mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700715}
716
Dave Barach371e4e12016-07-08 09:38:52 -0400717clib_error_t *
718vl_api_init (vlib_main_t * vm)
719{
720 static u8 once;
721 api_main_t *am = &api_main;
722
723 if (once)
724 return 0;
725
726 once = 1;
727
728 am->region_name = "/unset";
729 /*
730 * Eventually passed to fchown, -1 => "current user"
731 * instead of 0 => "root". A very fine disctinction at best.
732 */
733 if (am->api_uid == 0)
734 am->api_uid = -1;
735 if (am->api_gid == 0)
736 am->api_gid = -1;
737
738 return (0);
739}
740
741void vl_msg_api_custom_dump_configure (api_main_t * am)
742 __attribute__ ((weak));
743void
744vl_msg_api_custom_dump_configure (api_main_t * am)
745{
746}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747
748VLIB_INIT_FUNCTION (vl_api_init);
749
Dave Barach371e4e12016-07-08 09:38:52 -0400750static void
751vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
752 u32 first_index, u32 last_index,
753 vl_api_replay_t which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754{
Dave Barach371e4e12016-07-08 09:38:52 -0400755 vl_api_trace_file_header_t *hp;
756 int i, fd;
757 struct stat statb;
758 size_t file_size;
759 u8 *msg;
760 u8 endian_swap_needed = 0;
761 api_main_t *am = &api_main;
762 static u8 *tmpbuf;
763 u32 nitems;
764 void **saved_print_handlers = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765
Dave Barach371e4e12016-07-08 09:38:52 -0400766 fd = open ((char *) filename, O_RDONLY);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767
Dave Barach371e4e12016-07-08 09:38:52 -0400768 if (fd < 0)
769 {
770 vlib_cli_output (vm, "Couldn't open %s\n", filename);
771 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700772 }
773
Dave Barach371e4e12016-07-08 09:38:52 -0400774 if (fstat (fd, &statb) < 0)
775 {
776 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
Dave Barachb2a6e252016-07-27 10:00:58 -0400777 close (fd);
Dave Barach371e4e12016-07-08 09:38:52 -0400778 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700779 }
780
Dave Barach371e4e12016-07-08 09:38:52 -0400781 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
782 {
783 vlib_cli_output (vm, "File not plausible: %s\n", filename);
Ed Warnicke853e7202016-08-12 11:42:26 -0700784 close (fd);
Dave Barach371e4e12016-07-08 09:38:52 -0400785 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786 }
787
Dave Barach371e4e12016-07-08 09:38:52 -0400788 file_size = statb.st_size;
789 file_size = (file_size + 4095) & ~(4096);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790
Dave Barach371e4e12016-07-08 09:38:52 -0400791 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792
Dave Barach371e4e12016-07-08 09:38:52 -0400793 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
794 {
795 vlib_cli_output (vm, "mmap failed: %s\n", filename);
796 close (fd);
797 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798 }
Dave Barach371e4e12016-07-08 09:38:52 -0400799 close (fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800
Dave Barach371e4e12016-07-08 09:38:52 -0400801 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
802 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
803 endian_swap_needed = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804
Dave Barach371e4e12016-07-08 09:38:52 -0400805 if (endian_swap_needed)
806 nitems = ntohl (hp->nitems);
807 else
808 nitems = hp->nitems;
809
810 if (last_index == (u32) ~ 0)
811 {
812 last_index = nitems - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813 }
Dave Barach371e4e12016-07-08 09:38:52 -0400814
815 if (first_index >= nitems || last_index >= nitems)
816 {
817 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
818 first_index, last_index, nitems - 1);
Dave Barachac0798d2016-07-26 10:30:50 -0400819 munmap (hp, file_size);
Dave Barach371e4e12016-07-08 09:38:52 -0400820 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821 }
Dave Barach371e4e12016-07-08 09:38:52 -0400822 if (hp->wrapped)
823 vlib_cli_output (vm,
824 "Note: wrapped/incomplete trace, results may vary\n");
825
826 if (which == CUSTOM_DUMP)
827 {
828 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
829 vl_msg_api_custom_dump_configure (am);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830 }
831
832
Dave Barach371e4e12016-07-08 09:38:52 -0400833 msg = (u8 *) (hp + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
Dave Barach371e4e12016-07-08 09:38:52 -0400835 for (i = 0; i < first_index; i++)
836 {
837 trace_cfg_t *cfgp;
838 int size;
839 u16 msg_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840
Dave Barach371e4e12016-07-08 09:38:52 -0400841 if (clib_arch_is_little_endian)
842 msg_id = ntohs (*((u16 *) msg));
843 else
844 msg_id = *((u16 *) msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700845
Dave Barach371e4e12016-07-08 09:38:52 -0400846 cfgp = am->api_trace_cfg + msg_id;
847 if (!cfgp)
848 {
849 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
850 return;
851 }
852 size = cfgp->size;
853 msg += size;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854 }
855
Dave Barach371e4e12016-07-08 09:38:52 -0400856 for (; i <= last_index; i++)
857 {
858 trace_cfg_t *cfgp;
859 u16 *msg_idp;
860 u16 msg_id;
861 int size;
862
863 if (which == DUMP)
864 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
865
866 if (clib_arch_is_little_endian)
867 msg_id = ntohs (*((u16 *) msg));
868 else
869 msg_id = *((u16 *) msg);
870
871 cfgp = am->api_trace_cfg + msg_id;
872 if (!cfgp)
873 {
874 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
875 return;
876 }
877 size = cfgp->size;
878
879 /* Copy the buffer (from the read-only mmap'ed file) */
880 vec_validate (tmpbuf, size - 1 + sizeof (uword));
881 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
882 memset (tmpbuf, 0xf, sizeof (uword));
883
884 /*
885 * Endian swap if needed. All msg data is supposed to be
886 * in network byte order. All msg handlers are supposed to
887 * know that. The generic message dumpers don't know that.
888 * One could fix apigen, I suppose.
889 */
890 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
891 {
892 void (*endian_fp) (void *);
893 if (msg_id >= vec_len (am->msg_endian_handlers)
894 || (am->msg_endian_handlers[msg_id] == 0))
895 {
896 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
897 return;
898 }
899 endian_fp = am->msg_endian_handlers[msg_id];
900 (*endian_fp) (tmpbuf + sizeof (uword));
901 }
902
903 /* msg_id always in network byte order */
904 if (clib_arch_is_little_endian)
905 {
906 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
907 *msg_idp = msg_id;
908 }
909
910 switch (which)
911 {
912 case CUSTOM_DUMP:
913 case DUMP:
914 if (msg_id < vec_len (am->msg_print_handlers) &&
915 am->msg_print_handlers[msg_id])
916 {
917 u8 *(*print_fp) (void *, void *);
918
919 print_fp = (void *) am->msg_print_handlers[msg_id];
920 (*print_fp) (tmpbuf + sizeof (uword), vm);
921 }
922 else
923 {
924 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
925 msg_id);
926 break;
927 }
928 break;
929
930 case INITIALIZERS:
931 if (msg_id < vec_len (am->msg_print_handlers) &&
932 am->msg_print_handlers[msg_id])
933 {
934 u8 *s;
935 int j;
936 u8 *(*print_fp) (void *, void *);
937
938 print_fp = (void *) am->msg_print_handlers[msg_id];
939
940 vlib_cli_output (vm, "/*");
941
942 (*print_fp) (tmpbuf + sizeof (uword), vm);
943 vlib_cli_output (vm, "*/\n");
944
945 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
946 am->msg_names[msg_id], i,
947 am->api_trace_cfg[msg_id].size);
948
949 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
950 {
951 if ((j & 7) == 0)
952 s = format (s, "\n ");
953 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
954 }
955 s = format (s, "\n};\n%c", 0);
956 vlib_cli_output (vm, (char *) s);
957 vec_free (s);
958 }
959 break;
960
961 case REPLAY:
962 if (msg_id < vec_len (am->msg_print_handlers) &&
963 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
964 {
965 void (*handler) (void *);
966
967 handler = (void *) am->msg_handlers[msg_id];
968
969 if (!am->is_mp_safe[msg_id])
970 vl_msg_api_barrier_sync ();
971 (*handler) (tmpbuf + sizeof (uword));
972 if (!am->is_mp_safe[msg_id])
973 vl_msg_api_barrier_release ();
974 }
975 else
976 {
977 if (cfgp->replay_enable)
978 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
979 msg_id);
980 break;
981 }
982 break;
983 }
984
985 _vec_len (tmpbuf) = 0;
986 msg += size;
987 }
988
989 if (saved_print_handlers)
990 {
991 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
992 vec_len (am->msg_print_handlers) * sizeof (void *));
993 vec_free (saved_print_handlers);
994 }
995
996 munmap (hp, file_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997}
998
Dave Barach371e4e12016-07-08 09:38:52 -0400999u8 *
1000format_vl_msg_api_trace_status (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001{
Dave Barach371e4e12016-07-08 09:38:52 -04001002 api_main_t *am = va_arg (*args, api_main_t *);
1003 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1004 vl_api_trace_t *tp;
1005 char *trace_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006
Dave Barach371e4e12016-07-08 09:38:52 -04001007 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008 {
1009 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -04001010 tp = am->tx_trace;
1011 trace_name = "TX trace";
1012 break;
1013
Ed Warnickecb9cada2015-12-08 15:45:58 -07001014 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -04001015 tp = am->rx_trace;
1016 trace_name = "RX trace";
1017 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001018
1019 default:
Dave Barach371e4e12016-07-08 09:38:52 -04001020 abort ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 }
1022
Dave Barach371e4e12016-07-08 09:38:52 -04001023 if (tp == 0)
1024 {
1025 s = format (s, "%s: not yet configured.\n", trace_name);
1026 return s;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001027 }
1028
Dave Barach371e4e12016-07-08 09:38:52 -04001029 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1030 trace_name, vec_len (tp->traces), tp->nitems,
1031 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1032 return s;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033}
1034
1035static u8 post_mortem_dump_enabled;
1036
1037static clib_error_t *
1038api_trace_command_fn (vlib_main_t * vm,
Dave Barach371e4e12016-07-08 09:38:52 -04001039 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040{
Dave Barach371e4e12016-07-08 09:38:52 -04001041 u32 nitems = 256 << 10;
1042 api_main_t *am = &api_main;
1043 vl_api_trace_which_t which = VL_API_TRACE_RX;
1044 u8 *filename;
1045 u32 first = 0;
1046 u32 last = (u32) ~ 0;
1047 FILE *fp;
1048 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049
Dave Barach371e4e12016-07-08 09:38:52 -04001050 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1051 {
1052 if (unformat (input, "on") || unformat (input, "enable"))
1053 {
1054 if (unformat (input, "nitems %d", &nitems))
1055 ;
1056 vl_msg_api_trace_configure (am, which, nitems);
1057 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1058 }
1059 else if (unformat (input, "off"))
1060 {
1061 vl_msg_api_trace_onoff (am, which, 0);
1062 }
1063 else if (unformat (input, "save %s", &filename))
1064 {
1065 u8 *chroot_filename;
1066 if (strstr ((char *) filename, "..")
1067 || index ((char *) filename, '/'))
1068 {
1069 vlib_cli_output (vm, "illegal characters in filename '%s'",
1070 filename);
1071 return 0;
1072 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073
Dave Barach371e4e12016-07-08 09:38:52 -04001074 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075
Dave Barach371e4e12016-07-08 09:38:52 -04001076 vec_free (filename);
1077
1078 fp = fopen ((char *) chroot_filename, "w");
1079 if (fp == NULL)
1080 {
1081 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1082 return 0;
1083 }
1084 rv = vl_msg_api_trace_save (am, which, fp);
1085 fclose (fp);
rootdd9f1332016-07-27 08:01:31 -07001086 if (rv == -1)
Ed Warnicke853e7202016-08-12 11:42:26 -07001087 vlib_cli_output (vm, "API Trace data not present\n");
rootdd9f1332016-07-27 08:01:31 -07001088 else if (rv == -2)
Ed Warnicke853e7202016-08-12 11:42:26 -07001089 vlib_cli_output (vm, "File for writing is closed\n");
rootdd9f1332016-07-27 08:01:31 -07001090 else if (rv == -10)
Ed Warnicke853e7202016-08-12 11:42:26 -07001091 vlib_cli_output (vm, "Error while writing header to file\n");
rootdd9f1332016-07-27 08:01:31 -07001092 else if (rv == -11)
Ed Warnicke853e7202016-08-12 11:42:26 -07001093 vlib_cli_output (vm, "Error while writing trace to file\n");
rootdd9f1332016-07-27 08:01:31 -07001094 else if (rv == -12)
Ed Warnicke853e7202016-08-12 11:42:26 -07001095 vlib_cli_output (vm,
1096 "Error while writing end of buffer trace to file\n");
rootdd9f1332016-07-27 08:01:31 -07001097 else if (rv == -13)
Ed Warnicke853e7202016-08-12 11:42:26 -07001098 vlib_cli_output (vm,
1099 "Error while writing start of buffer trace to file\n");
rootdd9f1332016-07-27 08:01:31 -07001100 else if (rv < 0)
1101 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
Dave Barach371e4e12016-07-08 09:38:52 -04001102 else
1103 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1104 vec_free (chroot_filename);
1105 }
1106 else if (unformat (input, "dump %s", &filename))
1107 {
1108 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1109 }
1110 else if (unformat (input, "custom-dump %s", &filename))
1111 {
1112 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1113 }
1114 else if (unformat (input, "replay %s", &filename))
1115 {
1116 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1117 }
1118 else if (unformat (input, "initializers %s", &filename))
1119 {
1120 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1121 }
1122 else if (unformat (input, "tx"))
1123 {
1124 which = VL_API_TRACE_TX;
1125 }
1126 else if (unformat (input, "first %d", &first))
1127 {
1128 ;
1129 }
1130 else if (unformat (input, "last %d", &last))
1131 {
1132 ;
1133 }
1134 else if (unformat (input, "status"))
1135 {
1136 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1137 am, which);
1138 }
1139 else if (unformat (input, "free"))
1140 {
1141 vl_msg_api_trace_onoff (am, which, 0);
1142 vl_msg_api_trace_free (am, which);
1143 }
1144 else if (unformat (input, "post-mortem-on"))
1145 post_mortem_dump_enabled = 1;
1146 else if (unformat (input, "post-mortem-off"))
1147 post_mortem_dump_enabled = 0;
1148 else
1149 return clib_error_return (0, "unknown input `%U'",
1150 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151 }
Dave Barach371e4e12016-07-08 09:38:52 -04001152 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153}
1154
Dave Barach371e4e12016-07-08 09:38:52 -04001155/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156VLIB_CLI_COMMAND (api_trace_command, static) = {
1157 .path = "api trace",
Dave Barach371e4e12016-07-08 09:38:52 -04001158 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001159 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1160 .function = api_trace_command_fn,
1161};
Dave Barach371e4e12016-07-08 09:38:52 -04001162/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163
1164static clib_error_t *
1165api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1166{
Dave Barach371e4e12016-07-08 09:38:52 -04001167 u32 nitems = 256 << 10;
1168 vl_api_trace_which_t which = VL_API_TRACE_RX;
1169 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170
Dave Barach371e4e12016-07-08 09:38:52 -04001171 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1172 {
1173 if (unformat (input, "on") || unformat (input, "enable"))
1174 {
1175 if (unformat (input, "nitems %d", &nitems))
1176 ;
1177 vl_msg_api_trace_configure (am, which, nitems);
1178 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1179 post_mortem_dump_enabled = 1;
1180 }
1181 else
1182 return clib_error_return (0, "unknown input `%U'",
1183 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184 }
Dave Barach371e4e12016-07-08 09:38:52 -04001185 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186}
1187
1188VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1189
Dave Barach371e4e12016-07-08 09:38:52 -04001190void
1191vl_msg_api_post_mortem_dump (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192{
Dave Barach371e4e12016-07-08 09:38:52 -04001193 api_main_t *am = &api_main;
1194 FILE *fp;
1195 char filename[64];
1196 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001197
Dave Barach371e4e12016-07-08 09:38:52 -04001198 if (post_mortem_dump_enabled == 0)
1199 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001200
Dave Barach371e4e12016-07-08 09:38:52 -04001201 snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1202 getpid ());
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203
Dave Barach371e4e12016-07-08 09:38:52 -04001204 fp = fopen (filename, "w");
1205 if (fp == NULL)
1206 {
1207 rv = write (2, "Couldn't create ", 16);
1208 rv = write (2, filename, strlen (filename));
1209 rv = write (2, "\n", 1);
1210 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001211 }
Dave Barach371e4e12016-07-08 09:38:52 -04001212 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1213 fclose (fp);
1214 if (rv < 0)
1215 {
1216 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1217 rv = write (2, filename, strlen (filename));
1218 rv = write (2, "\n", 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001219 }
Dave Barach371e4e12016-07-08 09:38:52 -04001220
Ed Warnickecb9cada2015-12-08 15:45:58 -07001221}
1222
1223/* Layered message handling support */
1224
Dave Barach371e4e12016-07-08 09:38:52 -04001225void
1226vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227{
Dave Barach371e4e12016-07-08 09:38:52 -04001228 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001229
Dave Barach371e4e12016-07-08 09:38:52 -04001230 /* Mild idiot proofing */
1231 if (msg_id_host_byte_order > 10000)
1232 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1233 msg_id_host_byte_order,
1234 clib_net_to_host_u16 (msg_id_host_byte_order));
1235 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1236 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237}
1238
Dave Barach371e4e12016-07-08 09:38:52 -04001239int
1240vl_msg_api_pd_handler (void *mp, int rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241{
Dave Barach371e4e12016-07-08 09:38:52 -04001242 api_main_t *am = &api_main;
1243 int (*fp) (void *, int);
1244 u16 msg_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245
Dave Barach371e4e12016-07-08 09:38:52 -04001246 if (clib_arch_is_little_endian)
1247 msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1248 else
1249 msg_id = *((u16 *) mp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001250
Dave Barach371e4e12016-07-08 09:38:52 -04001251 if (msg_id >= vec_len (am->pd_msg_handlers)
1252 || am->pd_msg_handlers[msg_id] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001253 return rv;
Dave Barach371e4e12016-07-08 09:38:52 -04001254
1255 fp = am->pd_msg_handlers[msg_id];
1256 rv = (*fp) (mp, rv);
1257 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258}
1259
Dave Barach371e4e12016-07-08 09:38:52 -04001260void
1261vl_msg_api_set_first_available_msg_id (u16 first_avail)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001262{
Dave Barach371e4e12016-07-08 09:38:52 -04001263 api_main_t *am = &api_main;
1264
1265 am->first_available_msg_id = first_avail;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266}
1267
Dave Barach371e4e12016-07-08 09:38:52 -04001268u16
1269vl_msg_api_get_msg_ids (char *name, int n)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001270{
Dave Barach371e4e12016-07-08 09:38:52 -04001271 api_main_t *am = &api_main;
1272 u8 *name_copy;
1273 vl_api_msg_range_t *rp;
1274 uword *p;
1275 u16 rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001276
Dave Barach371e4e12016-07-08 09:38:52 -04001277 if (am->msg_range_by_name == 0)
1278 am->msg_range_by_name = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279
Dave Barach371e4e12016-07-08 09:38:52 -04001280 name_copy = format (0, "%s%c", name, 0);
1281
1282 p = hash_get_mem (am->msg_range_by_name, name_copy);
1283 if (p)
1284 {
1285 clib_warning ("WARNING: duplicate message range registration for '%s'",
1286 name_copy);
1287 vec_free (name_copy);
1288 return ((u16) ~ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289 }
1290
Dave Barach371e4e12016-07-08 09:38:52 -04001291 if (n < 0 || n > 1024)
1292 {
1293 clib_warning
1294 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1295 n, name_copy);
1296 vec_free (name_copy);
1297 return ((u16) ~ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298 }
1299
Dave Barach371e4e12016-07-08 09:38:52 -04001300 vec_add2 (am->msg_ranges, rp, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001301
Dave Barach371e4e12016-07-08 09:38:52 -04001302 rv = rp->first_msg_id = am->first_available_msg_id;
1303 am->first_available_msg_id += n;
1304 rp->last_msg_id = am->first_available_msg_id - 1;
1305 rp->name = name_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306
Dave Barach371e4e12016-07-08 09:38:52 -04001307 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308
Dave Barach371e4e12016-07-08 09:38:52 -04001309 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001310}
Dave Barach371e4e12016-07-08 09:38:52 -04001311
1312/*
1313 * fd.io coding-style-patch-verification: ON
1314 *
1315 * Local Variables:
1316 * eval: (c-set-style "gnu")
1317 * End:
1318 */