blob: 0057c85adcf48858d0e29e2e9654443ff52eb8bf [file] [log] [blame]
Florin Corase86a8ed2018-01-05 03:20:25 -08001/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2018 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
16 */
17
18#include <fcntl.h>
19#include <unistd.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22
23#include <vlibapi/api.h>
24#include <vlibmemory/api.h>
25
26static clib_error_t *
27vl_api_show_histogram_command (vlib_main_t * vm,
28 unformat_input_t * input,
29 vlib_cli_command_t * cli_cmd)
30{
31 u64 total_counts = 0;
32 int i;
33
34 for (i = 0; i < SLEEP_N_BUCKETS; i++)
35 {
36 total_counts += vector_rate_histogram[i];
37 }
38
39 if (total_counts == 0)
40 {
41 vlib_cli_output (vm, "No control-plane activity.");
42 return 0;
43 }
44
45#define _(n) \
46 do { \
47 f64 percent; \
48 percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
49 / (f64) total_counts; \
50 percent *= 100.0; \
51 vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
52 vector_rate_histogram[SLEEP_##n##_US], \
53 percent); \
54 } while (0);
55 foreach_histogram_bucket;
56#undef _
57
58 return 0;
59}
60
61/*?
62 * Display the binary api sleep-time histogram
63?*/
64/* *INDENT-OFF* */
65VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
66{
67 .path = "show api histogram",
68 .short_help = "show api histogram",
69 .function = vl_api_show_histogram_command,
70};
71/* *INDENT-ON* */
72
73static clib_error_t *
74vl_api_clear_histogram_command (vlib_main_t * vm,
75 unformat_input_t * input,
76 vlib_cli_command_t * cli_cmd)
77{
78 int i;
79
80 for (i = 0; i < SLEEP_N_BUCKETS; i++)
81 vector_rate_histogram[i] = 0;
82 return 0;
83}
84
85/*?
86 * Clear the binary api sleep-time histogram
87?*/
88/* *INDENT-OFF* */
89VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
90{
91 .path = "clear api histogram",
92 .short_help = "clear api histogram",
93 .function = vl_api_clear_histogram_command,
94};
95/* *INDENT-ON* */
96
97static clib_error_t *
98vl_api_client_command (vlib_main_t * vm,
99 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
100{
101 vl_api_registration_t **regpp, *regp;
102 svm_queue_t *q;
103 char *health;
Dave Barach39d69112019-11-27 11:42:13 -0500104 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800105 u32 *confused_indices = 0;
106
107 if (!pool_elts (am->vl_clients))
108 goto socket_clients;
109 vlib_cli_output (vm, "Shared memory clients");
110 vlib_cli_output (vm, "%20s %8s %14s %18s %s",
111 "Name", "PID", "Queue Length", "Queue VA", "Health");
112
113 /* *INDENT-OFF* */
Damjan Marionb2c31b62020-12-13 21:47:40 +0100114 pool_foreach (regpp, am->vl_clients)
115 {
Florin Corase86a8ed2018-01-05 03:20:25 -0800116 regp = *regpp;
117
118 if (regp)
119 {
120 if (regp->unanswered_pings > 0)
121 health = "questionable";
122 else
123 health = "OK";
124
125 q = regp->vl_input_queue;
126
127 vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
128 regp->name, q->consumer_pid, q->cursize,
129 q, health);
130 }
131 else
132 {
133 clib_warning ("NULL client registration index %d",
134 regpp - am->vl_clients);
135 vec_add1 (confused_indices, regpp - am->vl_clients);
136 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100137 }
Florin Corase86a8ed2018-01-05 03:20:25 -0800138 /* *INDENT-ON* */
139
140 /* This should "never happen," but if it does, fix it... */
141 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
142 {
143 int i;
144 for (i = 0; i < vec_len (confused_indices); i++)
145 {
146 pool_put_index (am->vl_clients, confused_indices[i]);
147 }
148 }
149 vec_free (confused_indices);
150
151 if (am->missing_clients)
152 vlib_cli_output (vm, "%u messages with missing clients",
153 am->missing_clients);
154socket_clients:
155 vl_sock_api_dump_clients (vm, am);
156
157 return 0;
158}
159
160static clib_error_t *
161vl_api_status_command (vlib_main_t * vm,
162 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
163{
Dave Barach39d69112019-11-27 11:42:13 -0500164 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800165
166 /* check if rx_trace and tx_trace are not null pointers */
167 if (am->rx_trace == 0)
168 {
169 vlib_cli_output (vm, "RX Trace disabled\n");
170 }
171 else
172 {
173 if (am->rx_trace->enabled == 0)
174 vlib_cli_output (vm, "RX Trace disabled\n");
175 else
176 vlib_cli_output (vm, "RX Trace enabled\n");
177 }
178
179 if (am->tx_trace == 0)
180 {
181 vlib_cli_output (vm, "TX Trace disabled\n");
182 }
183 else
184 {
185 if (am->tx_trace->enabled == 0)
186 vlib_cli_output (vm, "TX Trace disabled\n");
187 else
188 vlib_cli_output (vm, "TX Trace enabled\n");
189 }
190
191 return 0;
192}
193
194/* *INDENT-OFF* */
195VLIB_CLI_COMMAND (cli_show_api_command, static) =
196{
197 .path = "show api",
198 .short_help = "Show API information",
199};
200/* *INDENT-ON* */
201
202/*?
203 * Display current api client connections
204?*/
205/* *INDENT-OFF* */
206VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
207{
208 .path = "show api clients",
209 .short_help = "Client information",
210 .function = vl_api_client_command,
211};
212/* *INDENT-ON* */
213
214/*?
215 * Display the current api message tracing status
216?*/
217/* *INDENT-OFF* */
218VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
219{
220 .path = "show api trace-status",
221 .short_help = "Display API trace status",
222 .function = vl_api_status_command,
223};
224/* *INDENT-ON* */
225
226static clib_error_t *
227vl_api_message_table_command (vlib_main_t * vm,
228 unformat_input_t * input,
229 vlib_cli_command_t * cli_cmd)
230{
Dave Barach39d69112019-11-27 11:42:13 -0500231 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800232 int i;
233 int verbose = 0;
234
235 if (unformat (input, "verbose"))
236 verbose = 1;
237
238
239 if (verbose == 0)
240 vlib_cli_output (vm, "%-4s %s", "ID", "Name");
241 else
242 vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
243 "MP-safe");
244
245 for (i = 1; i < vec_len (am->msg_names); i++)
246 {
247 if (verbose == 0)
248 {
249 vlib_cli_output (vm, "%-4d %s", i,
250 am->msg_names[i] ? am->msg_names[i] :
251 " [no handler]");
252 }
253 else
254 {
255 vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
256 am->msg_names[i] ? am->msg_names[i] :
257 " [no handler]", am->message_bounce[i],
258 am->is_mp_safe[i]);
259 }
260 }
261
262 return 0;
263}
264
265/*?
266 * Display the current api message decode tables
267?*/
268/* *INDENT-OFF* */
269VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
270{
271 .path = "show api message-table",
272 .short_help = "Message Table",
273 .function = vl_api_message_table_command,
274};
275/* *INDENT-ON* */
276
277static int
278range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
279{
280 int len0, len1, clen;
281
282 len0 = vec_len (a0->name);
283 len1 = vec_len (a1->name);
284 clen = len0 < len1 ? len0 : len1;
285 return (strncmp ((char *) a0->name, (char *) a1->name, clen));
286}
287
288static u8 *
289format_api_msg_range (u8 * s, va_list * args)
290{
291 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
292
293 if (rp == 0)
294 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
295 else
296 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
297 rp->last_msg_id);
298
299 return s;
300}
301
302static clib_error_t *
303vl_api_show_plugin_command (vlib_main_t * vm,
304 unformat_input_t * input,
305 vlib_cli_command_t * cli_cmd)
306{
Dave Barach39d69112019-11-27 11:42:13 -0500307 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800308 vl_api_msg_range_t *rp = 0;
309 int i;
310
311 if (vec_len (am->msg_ranges) == 0)
312 {
313 vlib_cli_output (vm, "No plugin API message ranges configured...");
314 return 0;
315 }
316
317 rp = vec_dup (am->msg_ranges);
318
319 vec_sort_with_function (rp, range_compare);
320
321 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
322 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
323
324 for (i = 0; i < vec_len (rp); i++)
325 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
326
327 vec_free (rp);
328
329 return 0;
330}
331
332/*?
333 * Display the plugin binary API message range table
334?*/
335/* *INDENT-OFF* */
336VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
337{
338 .path = "show api plugin",
339 .short_help = "show api plugin",
340 .function = vl_api_show_plugin_command,
341};
342/* *INDENT-ON* */
343
344typedef enum
345{
346 DUMP,
Florin Corase86a8ed2018-01-05 03:20:25 -0800347 REPLAY,
348 INITIALIZERS,
349} vl_api_replay_t;
350
351u8 *
352format_vl_msg_api_trace_status (u8 * s, va_list * args)
353{
354 api_main_t *am = va_arg (*args, api_main_t *);
355 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
356 vl_api_trace_t *tp;
357 char *trace_name;
358
359 switch (which)
360 {
361 case VL_API_TRACE_TX:
362 tp = am->tx_trace;
363 trace_name = "TX trace";
364 break;
365
366 case VL_API_TRACE_RX:
367 tp = am->rx_trace;
368 trace_name = "RX trace";
369 break;
370
371 default:
372 abort ();
373 }
374
375 if (tp == 0)
376 {
377 s = format (s, "%s: not yet configured.\n", trace_name);
378 return s;
379 }
380
381 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
382 trace_name, vec_len (tp->traces), tp->nitems,
383 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
384 return s;
385}
386
Florin Corase86a8ed2018-01-05 03:20:25 -0800387static void
388vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
389 u32 first_index, u32 last_index,
390 vl_api_replay_t which)
391{
392 vl_api_trace_file_header_t *hp;
393 int i, fd;
394 struct stat statb;
395 size_t file_size;
396 u8 *msg;
Dave Barach39d69112019-11-27 11:42:13 -0500397 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800398 u8 *tmpbuf = 0;
Ole Troanedfe2c02019-07-30 15:38:13 +0200399 u32 nitems, nitems_msgtbl;
Florin Corase86a8ed2018-01-05 03:20:25 -0800400
401 fd = open ((char *) filename, O_RDONLY);
402
403 if (fd < 0)
404 {
405 vlib_cli_output (vm, "Couldn't open %s\n", filename);
406 return;
407 }
408
409 if (fstat (fd, &statb) < 0)
410 {
411 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
412 close (fd);
413 return;
414 }
415
416 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
417 {
418 vlib_cli_output (vm, "File not plausible: %s\n", filename);
419 close (fd);
420 return;
421 }
422
423 file_size = statb.st_size;
Benoît Ganneaba49832020-01-21 18:35:49 +0100424 file_size = (file_size + 4095) & ~(4095);
Florin Corase86a8ed2018-01-05 03:20:25 -0800425
426 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
427
428 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
429 {
430 vlib_cli_output (vm, "mmap failed: %s\n", filename);
431 close (fd);
432 return;
433 }
434 close (fd);
435
Benoît Ganneb2f09142019-12-16 15:37:28 +0100436 CLIB_MEM_UNPOISON (hp, file_size);
437
Ole Troanedfe2c02019-07-30 15:38:13 +0200438 nitems = ntohl (hp->nitems);
Florin Corase86a8ed2018-01-05 03:20:25 -0800439
440 if (last_index == (u32) ~ 0)
441 {
442 last_index = nitems - 1;
443 }
444
445 if (first_index >= nitems || last_index >= nitems)
446 {
447 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
448 first_index, last_index, nitems - 1);
449 munmap (hp, file_size);
450 return;
451 }
452 if (hp->wrapped)
453 vlib_cli_output (vm,
454 "Note: wrapped/incomplete trace, results may vary\n");
455
Florin Corase86a8ed2018-01-05 03:20:25 -0800456 msg = (u8 *) (hp + 1);
457
Ole Troanedfe2c02019-07-30 15:38:13 +0200458 u16 *msgid_vec = 0;
459 serialize_main_t _sm, *sm = &_sm;
460 u32 msgtbl_size = ntohl (hp->msgtbl_size);
461 u8 *name_and_crc;
462
463 unserialize_open_data (sm, msg, msgtbl_size);
464 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
465
466 for (i = 0; i < nitems_msgtbl; i++)
467 {
468 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
469 unserialize_cstring (sm, (char **) &name_and_crc);
470 u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
471 vec_validate (msgid_vec, msg_index);
472 msgid_vec[msg_index] = msg_index2;
473 }
474
475 msg += msgtbl_size;
476
Florin Corase86a8ed2018-01-05 03:20:25 -0800477 for (i = 0; i < first_index; i++)
478 {
479 trace_cfg_t *cfgp;
480 int size;
481 u16 msg_id;
482
483 size = clib_host_to_net_u32 (*(u32 *) msg);
484 msg += sizeof (u32);
485
Ole Troanedfe2c02019-07-30 15:38:13 +0200486 msg_id = ntohs (*((u16 *) msg));
487 if (msg_id < vec_len (msgid_vec))
488 msg_id = msgid_vec[msg_id];
Florin Corase86a8ed2018-01-05 03:20:25 -0800489 cfgp = am->api_trace_cfg + msg_id;
490 if (!cfgp)
491 {
492 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
493 munmap (hp, file_size);
494 return;
495 }
496 msg += size;
497 }
498
499 if (which == REPLAY)
500 am->replay_in_progress = 1;
501
502 for (; i <= last_index; i++)
503 {
504 trace_cfg_t *cfgp;
Florin Corase86a8ed2018-01-05 03:20:25 -0800505 u16 msg_id;
506 int size;
507
508 if (which == DUMP)
509 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
510
511 size = clib_host_to_net_u32 (*(u32 *) msg);
512 msg += sizeof (u32);
513
Ole Troanedfe2c02019-07-30 15:38:13 +0200514 msg_id = ntohs (*((u16 *) msg));
515 if (msg_id < vec_len (msgid_vec))
516 {
517 msg_id = msgid_vec[msg_id];
518 }
Florin Corase86a8ed2018-01-05 03:20:25 -0800519
520 cfgp = am->api_trace_cfg + msg_id;
521 if (!cfgp)
522 {
523 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
524 munmap (hp, file_size);
525 vec_free (tmpbuf);
526 am->replay_in_progress = 0;
527 return;
528 }
529
530 /* Copy the buffer (from the read-only mmap'ed file) */
531 vec_validate (tmpbuf, size - 1 + sizeof (uword));
532 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
Dave Barachb7b92992018-10-17 10:38:51 -0400533 clib_memset (tmpbuf, 0xf, sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800534
535 /*
Ole Troanedfe2c02019-07-30 15:38:13 +0200536 * Endian swap if needed. All msg data is supposed to be in
537 * network byte order.
Florin Corase86a8ed2018-01-05 03:20:25 -0800538 */
Filip Tehlarc863a912021-06-15 10:29:54 +0000539 if (((which == DUMP) && clib_arch_is_little_endian))
Florin Corase86a8ed2018-01-05 03:20:25 -0800540 {
541 void (*endian_fp) (void *);
542 if (msg_id >= vec_len (am->msg_endian_handlers)
543 || (am->msg_endian_handlers[msg_id] == 0))
544 {
545 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
546 munmap (hp, file_size);
547 vec_free (tmpbuf);
548 am->replay_in_progress = 0;
549 return;
550 }
551 endian_fp = am->msg_endian_handlers[msg_id];
552 (*endian_fp) (tmpbuf + sizeof (uword));
553 }
554
555 /* msg_id always in network byte order */
556 if (clib_arch_is_little_endian)
557 {
Ole Troanedfe2c02019-07-30 15:38:13 +0200558 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800559 *msg_idp = msg_id;
560 }
561
562 switch (which)
563 {
Florin Corase86a8ed2018-01-05 03:20:25 -0800564 case DUMP:
565 if (msg_id < vec_len (am->msg_print_handlers) &&
566 am->msg_print_handlers[msg_id])
567 {
568 u8 *(*print_fp) (void *, void *);
569
570 print_fp = (void *) am->msg_print_handlers[msg_id];
571 (*print_fp) (tmpbuf + sizeof (uword), vm);
572 }
573 else
574 {
575 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
576 msg_id);
577 break;
578 }
579 break;
580
581 case INITIALIZERS:
582 if (msg_id < vec_len (am->msg_print_handlers) &&
583 am->msg_print_handlers[msg_id])
584 {
585 u8 *s;
586 int j;
587 u8 *(*print_fp) (void *, void *);
588
589 print_fp = (void *) am->msg_print_handlers[msg_id];
590
591 vlib_cli_output (vm, "/*");
592
593 (*print_fp) (tmpbuf + sizeof (uword), vm);
594 vlib_cli_output (vm, "*/\n");
595
596 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
597 am->msg_names[msg_id], i,
598 am->api_trace_cfg[msg_id].size);
599
600 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
601 {
602 if ((j & 7) == 0)
603 s = format (s, "\n ");
604 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
605 }
606 s = format (s, "\n};\n%c", 0);
607 vlib_cli_output (vm, (char *) s);
608 vec_free (s);
609 }
610 break;
611
612 case REPLAY:
613 if (msg_id < vec_len (am->msg_print_handlers) &&
614 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
615 {
John Loa56f2702018-06-25 20:38:35 -0400616 void (*handler) (void *, vlib_main_t *);
Florin Corase86a8ed2018-01-05 03:20:25 -0800617
618 handler = (void *) am->msg_handlers[msg_id];
619
620 if (!am->is_mp_safe[msg_id])
621 vl_msg_api_barrier_sync ();
John Loa56f2702018-06-25 20:38:35 -0400622 (*handler) (tmpbuf + sizeof (uword), vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800623 if (!am->is_mp_safe[msg_id])
624 vl_msg_api_barrier_release ();
625 }
626 else
627 {
628 if (cfgp->replay_enable)
629 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
630 msg_id);
631 break;
632 }
633 break;
634 }
635
636 _vec_len (tmpbuf) = 0;
637 msg += size;
638 }
639
Florin Corase86a8ed2018-01-05 03:20:25 -0800640 munmap (hp, file_size);
641 vec_free (tmpbuf);
642 am->replay_in_progress = 0;
643}
644
Dave Barachf66f8832020-01-23 08:44:40 -0500645/** api_trace_command_fn - control the binary API trace / replay feature
646
647 Note: this command MUST be marked thread-safe. Replay with
648 multiple worker threads depends in many cases on worker thread
649 graph replica maintenance. If we (implicitly) assert a worker
650 thread barrier at the debug CLI level, all graph replica changes
651 are deferred until the replay operation completes. If an interface
652 is deleted, the wheels fall off.
653 */
654
Florin Corase86a8ed2018-01-05 03:20:25 -0800655static clib_error_t *
656api_trace_command_fn (vlib_main_t * vm,
657 unformat_input_t * input, vlib_cli_command_t * cmd)
658{
Neale Rannsecff1cb2020-04-22 12:14:52 -0400659 unformat_input_t _line_input, *line_input = &_line_input;
Florin Corase86a8ed2018-01-05 03:20:25 -0800660 u32 nitems = 256 << 10;
Dave Barach39d69112019-11-27 11:42:13 -0500661 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800662 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barachf35a0722019-06-12 16:50:38 -0400663 u8 *filename = 0;
664 u8 *chroot_filename = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -0800665 u32 first = 0;
666 u32 last = (u32) ~ 0;
667 FILE *fp;
668 int rv;
669
Neale Rannsecff1cb2020-04-22 12:14:52 -0400670 /* Get a line of input. */
671 if (!unformat_user (input, unformat_line_input, line_input))
672 return 0;
673
674 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Florin Corase86a8ed2018-01-05 03:20:25 -0800675 {
Neale Rannsecff1cb2020-04-22 12:14:52 -0400676 if (unformat (line_input, "on") || unformat (line_input, "enable"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800677 {
Neale Rannsecff1cb2020-04-22 12:14:52 -0400678 if (unformat (line_input, "nitems %d", &nitems))
Florin Corase86a8ed2018-01-05 03:20:25 -0800679 ;
Dave Barachf66f8832020-01-23 08:44:40 -0500680 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800681 vl_msg_api_trace_configure (am, which, nitems);
682 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
Dave Barachf66f8832020-01-23 08:44:40 -0500683 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800684 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400685 else if (unformat (line_input, "off"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800686 {
Dave Barachf66f8832020-01-23 08:44:40 -0500687 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800688 vl_msg_api_trace_onoff (am, which, 0);
Dave Barachf66f8832020-01-23 08:44:40 -0500689 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800690 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400691 else if (unformat (line_input, "save %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -0800692 {
Florin Corase86a8ed2018-01-05 03:20:25 -0800693 if (strstr ((char *) filename, "..")
694 || index ((char *) filename, '/'))
695 {
696 vlib_cli_output (vm, "illegal characters in filename '%s'",
697 filename);
Dave Barachf35a0722019-06-12 16:50:38 -0400698 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -0800699 }
700
701 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
702
703 vec_free (filename);
704
705 fp = fopen ((char *) chroot_filename, "w");
706 if (fp == NULL)
707 {
708 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
Dave Barachf35a0722019-06-12 16:50:38 -0400709 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -0800710 }
Dave Barachf66f8832020-01-23 08:44:40 -0500711 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800712 rv = vl_msg_api_trace_save (am, which, fp);
Dave Barachf66f8832020-01-23 08:44:40 -0500713 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800714 fclose (fp);
715 if (rv == -1)
716 vlib_cli_output (vm, "API Trace data not present\n");
717 else if (rv == -2)
718 vlib_cli_output (vm, "File for writing is closed\n");
719 else if (rv == -10)
720 vlib_cli_output (vm, "Error while writing header to file\n");
721 else if (rv == -11)
722 vlib_cli_output (vm, "Error while writing trace to file\n");
723 else if (rv == -12)
724 vlib_cli_output (vm,
725 "Error while writing end of buffer trace to file\n");
726 else if (rv == -13)
727 vlib_cli_output (vm,
728 "Error while writing start of buffer trace to file\n");
729 else if (rv < 0)
Andrey "Zed" Zaikin701625b2018-04-18 17:07:07 +0300730 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
Florin Corase86a8ed2018-01-05 03:20:25 -0800731 else
732 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
Dave Barachf35a0722019-06-12 16:50:38 -0400733 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -0800734 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400735 else if (unformat (line_input, "dump %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -0800736 {
737 vl_msg_api_process_file (vm, filename, first, last, DUMP);
738 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400739 else if (unformat (line_input, "replay %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -0800740 {
741 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
742 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400743 else if (unformat (line_input, "initializers %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -0800744 {
745 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
746 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400747 else if (unformat (line_input, "tx"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800748 {
749 which = VL_API_TRACE_TX;
750 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400751 else if (unformat (line_input, "first %d", &first))
Florin Corase86a8ed2018-01-05 03:20:25 -0800752 {
753 ;
754 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400755 else if (unformat (line_input, "last %d", &last))
Florin Corase86a8ed2018-01-05 03:20:25 -0800756 {
757 ;
758 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400759 else if (unformat (line_input, "status"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800760 {
761 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
762 am, which);
763 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400764 else if (unformat (line_input, "free"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800765 {
Dave Barachf66f8832020-01-23 08:44:40 -0500766 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800767 vl_msg_api_trace_onoff (am, which, 0);
768 vl_msg_api_trace_free (am, which);
Dave Barachf66f8832020-01-23 08:44:40 -0500769 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800770 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400771 else if (unformat (line_input, "post-mortem-on"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800772 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
Neale Rannsecff1cb2020-04-22 12:14:52 -0400773 else if (unformat (line_input, "post-mortem-off"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800774 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
775 else
776 return clib_error_return (0, "unknown input `%U'",
777 format_unformat_error, input);
778 }
Dave Barachf35a0722019-06-12 16:50:38 -0400779out:
780 vec_free (filename);
781 vec_free (chroot_filename);
Neale Rannsecff1cb2020-04-22 12:14:52 -0400782 unformat_free (line_input);
Florin Corase86a8ed2018-01-05 03:20:25 -0800783 return 0;
784}
785
786/*?
787 * Display, replay, or save a binary API trace
788?*/
789
790/* *INDENT-OFF* */
Filip Tehlarc863a912021-06-15 10:29:54 +0000791VLIB_CLI_COMMAND (api_trace_command, static) = {
Florin Corase86a8ed2018-01-05 03:20:25 -0800792 .path = "api trace",
793 .short_help = "api trace [on|off][first <n>][last <n>][status][free]"
Filip Tehlarc863a912021-06-15 10:29:54 +0000794 "[post-mortem-on][dump|save|replay <file>]",
Florin Corase86a8ed2018-01-05 03:20:25 -0800795 .function = api_trace_command_fn,
Dave Barachf66f8832020-01-23 08:44:40 -0500796 .is_mp_safe = 1,
Florin Corase86a8ed2018-01-05 03:20:25 -0800797};
798/* *INDENT-ON* */
799
800static clib_error_t *
801vl_api_trace_command (vlib_main_t * vm,
802 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
803{
804 u32 nitems = 1024;
805 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barach39d69112019-11-27 11:42:13 -0500806 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800807
808 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
809 {
810 if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
811 goto configure;
812 else if (unformat (input, "tx nitems %u", &nitems)
813 || unformat (input, "tx"))
814 {
815 which = VL_API_TRACE_RX;
816 goto configure;
817 }
818 else if (unformat (input, "on rx"))
819 {
820 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
821 }
822 else if (unformat (input, "on tx"))
823 {
824 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
825 }
826 else if (unformat (input, "on"))
827 {
828 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
829 }
830 else if (unformat (input, "off"))
831 {
832 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
833 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
834 }
835 else if (unformat (input, "free"))
836 {
837 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
838 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
839 vl_msg_api_trace_free (am, VL_API_TRACE_RX);
840 vl_msg_api_trace_free (am, VL_API_TRACE_TX);
841 }
842 else if (unformat (input, "debug on"))
843 {
844 am->msg_print_flag = 1;
845 }
846 else if (unformat (input, "debug off"))
847 {
848 am->msg_print_flag = 0;
849 }
850 else
851 return clib_error_return (0, "unknown input `%U'",
852 format_unformat_error, input);
853 }
854 return 0;
855
856configure:
857 if (vl_msg_api_trace_configure (am, which, nitems))
858 {
859 vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
860 which, nitems);
861 }
862
863 return 0;
864}
865
866/*?
867 * Control the binary API trace mechanism
868?*/
869/* *INDENT-OFF* */
870VLIB_CLI_COMMAND (trace, static) =
871{
ezkexmabcee60d2019-03-20 12:02:33 -0400872 .path = "set api-trace",
873 .short_help = "API trace [on][on tx][on rx][off][free][debug on][debug off]",
Florin Corase86a8ed2018-01-05 03:20:25 -0800874 .function = vl_api_trace_command,
875};
876/* *INDENT-ON* */
877
878static clib_error_t *
879api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
880{
881 u32 nitems = 256 << 10;
882 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barach39d69112019-11-27 11:42:13 -0500883 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800884
885 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
886 {
887 if (unformat (input, "on") || unformat (input, "enable"))
888 {
889 if (unformat (input, "nitems %d", &nitems))
890 ;
891 vl_msg_api_trace_configure (am, which, nitems);
892 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
893 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
894 }
895 else if (unformat (input, "save-api-table %s",
896 &am->save_msg_table_filename))
897 ;
898 else
899 return clib_error_return (0, "unknown input `%U'",
900 format_unformat_error, input);
901 }
902 return 0;
903}
904
905/*?
906 * This module has three configuration parameters:
907 * "on" or "enable" - enables binary api tracing
908 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
909 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
910?*/
911VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
912
913static clib_error_t *
914api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
915{
Dave Barach39d69112019-11-27 11:42:13 -0500916 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800917 u32 nitems;
918
919 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
920 {
921 if (unformat (input, "length %d", &nitems) ||
922 (unformat (input, "len %d", &nitems)))
923 {
924 if (nitems >= 1024)
925 am->vlib_input_queue_length = nitems;
926 else
927 clib_warning ("vlib input queue length %d too small, ignored",
928 nitems);
929 }
930 else
931 return clib_error_return (0, "unknown input `%U'",
932 format_unformat_error, input);
933 }
934 return 0;
935}
936
937VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
938
939static u8 *
940extract_name (u8 * s)
941{
942 u8 *rv;
943
944 rv = vec_dup (s);
945
946 while (vec_len (rv) && rv[vec_len (rv)] != '_')
947 _vec_len (rv)--;
948
949 rv[vec_len (rv)] = 0;
950
951 return rv;
952}
953
954static u8 *
955extract_crc (u8 * s)
956{
957 int i;
958 u8 *rv;
959
960 rv = vec_dup (s);
961
962 for (i = vec_len (rv) - 1; i >= 0; i--)
963 {
964 if (rv[i] == '_')
965 {
966 vec_delete (rv, i + 1, 0);
967 break;
968 }
969 }
970 return rv;
971}
972
973typedef struct
974{
975 u8 *name_and_crc;
976 u8 *name;
977 u8 *crc;
978 u32 msg_index;
979 int which;
980} msg_table_unserialize_t;
981
982static int
983table_id_cmp (void *a1, void *a2)
984{
985 msg_table_unserialize_t *n1 = a1;
986 msg_table_unserialize_t *n2 = a2;
987
988 return (n1->msg_index - n2->msg_index);
989}
990
991static int
992table_name_and_crc_cmp (void *a1, void *a2)
993{
994 msg_table_unserialize_t *n1 = a1;
995 msg_table_unserialize_t *n2 = a2;
996
997 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
998}
999
1000static clib_error_t *
1001dump_api_table_file_command_fn (vlib_main_t * vm,
1002 unformat_input_t * input,
1003 vlib_cli_command_t * cmd)
1004{
1005 u8 *filename = 0;
Dave Barach39d69112019-11-27 11:42:13 -05001006 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001007 serialize_main_t _sm, *sm = &_sm;
1008 clib_error_t *error;
1009 u32 nmsgs;
1010 u32 msg_index;
1011 u8 *name_and_crc;
1012 int compare_current = 0;
1013 int numeric_sort = 0;
1014 msg_table_unserialize_t *table = 0, *item;
1015 u32 i;
1016 u32 ndifferences = 0;
1017
1018 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1019 {
1020 if (unformat (input, "file %s", &filename))
1021 ;
1022 else if (unformat (input, "compare-current")
1023 || unformat (input, "compare"))
1024 compare_current = 1;
1025 else if (unformat (input, "numeric"))
1026 numeric_sort = 1;
1027 else
1028 return clib_error_return (0, "unknown input `%U'",
1029 format_unformat_error, input);
1030 }
1031
1032 if (numeric_sort && compare_current)
1033 return clib_error_return
1034 (0, "Comparison and numeric sorting are incompatible");
1035
1036 if (filename == 0)
1037 return clib_error_return (0, "File not specified");
1038
1039 /* Load the serialized message table from the table dump */
1040
1041 error = unserialize_open_clib_file (sm, (char *) filename);
1042
1043 if (error)
1044 return error;
1045
1046 unserialize_integer (sm, &nmsgs, sizeof (u32));
1047
1048 for (i = 0; i < nmsgs; i++)
1049 {
1050 msg_index = unserialize_likely_small_unsigned_integer (sm);
1051 unserialize_cstring (sm, (char **) &name_and_crc);
1052 vec_add2 (table, item, 1);
1053 item->msg_index = msg_index;
1054 item->name_and_crc = name_and_crc;
1055 item->name = extract_name (name_and_crc);
1056 item->crc = extract_crc (name_and_crc);
1057 item->which = 0; /* file */
1058 }
Ole Troanedfe2c02019-07-30 15:38:13 +02001059 unserialize_close (sm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001060
1061 /* Compare with the current image? */
1062 if (compare_current)
1063 {
1064 /* Append the current message table */
1065 u8 *tblv = vl_api_serialize_message_table (am, 0);
1066
1067 serialize_open_vector (sm, tblv);
1068 unserialize_integer (sm, &nmsgs, sizeof (u32));
1069
1070 for (i = 0; i < nmsgs; i++)
1071 {
1072 msg_index = unserialize_likely_small_unsigned_integer (sm);
1073 unserialize_cstring (sm, (char **) &name_and_crc);
1074
1075 vec_add2 (table, item, 1);
1076 item->msg_index = msg_index;
1077 item->name_and_crc = name_and_crc;
1078 item->name = extract_name (name_and_crc);
1079 item->crc = extract_crc (name_and_crc);
1080 item->which = 1; /* current_image */
1081 }
1082 vec_free (tblv);
1083 }
1084
1085 /* Sort the table. */
1086 if (numeric_sort)
1087 vec_sort_with_function (table, table_id_cmp);
1088 else
1089 vec_sort_with_function (table, table_name_and_crc_cmp);
1090
1091 if (compare_current)
1092 {
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001093 u8 *dashes = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -08001094 ndifferences = 0;
1095
1096 /*
1097 * In this case, the recovered table will have two entries per
1098 * API message. So, if entries i and i+1 match, the message definitions
1099 * are identical. Otherwise, the crc is different, or a message is
1100 * present in only one of the tables.
1101 */
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001102 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1103 vec_validate_init_empty (dashes, 60, '-');
1104 vec_terminate_c_string (dashes);
1105 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1106 vec_free (dashes);
Florin Corase86a8ed2018-01-05 03:20:25 -08001107 for (i = 0; i < vec_len (table);)
1108 {
1109 /* Last message lonely? */
1110 if (i == vec_len (table) - 1)
1111 {
1112 ndifferences++;
1113 goto last_unique;
1114 }
1115
1116 /* Identical pair? */
1117 if (!strncmp
1118 ((char *) table[i].name_and_crc,
1119 (char *) table[i + 1].name_and_crc,
1120 vec_len (table[i].name_and_crc)))
1121 {
1122 i += 2;
1123 continue;
1124 }
1125
1126 ndifferences++;
1127
1128 /* Only in one of two tables? */
Andrew Yourtchenkoae605b82019-01-21 16:39:33 +01001129 if (i + 1 == vec_len (table)
1130 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
Florin Corase86a8ed2018-01-05 03:20:25 -08001131 {
1132 last_unique:
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001133 vlib_cli_output (vm, "%-60s | only in %s",
Florin Corase86a8ed2018-01-05 03:20:25 -08001134 table[i].name, table[i].which ?
1135 "image" : "file");
1136 i++;
1137 continue;
1138 }
1139 /* In both tables, but with different signatures */
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001140 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
Florin Corase86a8ed2018-01-05 03:20:25 -08001141 i += 2;
1142 }
1143 if (ndifferences == 0)
1144 vlib_cli_output (vm, "No api message signature differences found.");
1145 else
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001146 vlib_cli_output (vm, "\nFound %u api message signature differences",
Florin Corase86a8ed2018-01-05 03:20:25 -08001147 ndifferences);
1148 goto cleanup;
1149 }
1150
1151 /* Dump the table, sorted as shown above */
1152 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1153
1154 for (i = 0; i < vec_len (table); i++)
1155 {
1156 item = table + i;
1157 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1158 item->msg_index, item->crc);
1159 }
1160
1161cleanup:
1162 for (i = 0; i < vec_len (table); i++)
1163 {
1164 vec_free (table[i].name_and_crc);
1165 vec_free (table[i].name);
1166 vec_free (table[i].crc);
1167 }
1168
1169 vec_free (table);
1170
1171 return 0;
1172}
1173
1174/*?
1175 * Displays a serialized API message decode table, sorted by message name
1176 *
1177 * @cliexpar
1178 * @cliexstart{show api dump file <filename>}
1179 * Message name MsgID CRC
1180 * accept_session 407 8e2a127e
1181 * accept_session_reply 408 67d8c22a
1182 * add_node_next 549 e4202993
1183 * add_node_next_reply 550 e89d6eed
1184 * etc.
1185 * @cliexend
1186?*/
1187
1188/*?
1189 * Compares a serialized API message decode table with the current image
1190 *
1191 * @cliexpar
1192 * @cliexstart{show api dump file <filename> compare}
1193 * ip_add_del_route definition changed
1194 * ip_table_add_del definition changed
1195 * l2_macs_event only in image
1196 * vnet_ip4_fib_counters only in file
1197 * vnet_ip4_nbr_counters only in file
1198 * @cliexend
1199?*/
1200
1201/*?
1202 * Display a serialized API message decode table, compare a saved
1203 * decode table with the current image, to establish API differences.
1204 *
1205?*/
1206/* *INDENT-OFF* */
1207VLIB_CLI_COMMAND (dump_api_table_file, static) =
1208{
1209 .path = "show api dump",
1210 .short_help = "show api dump file <filename> [numeric | compare-current]",
1211 .function = dump_api_table_file_command_fn,
1212};
1213
1214/* *INDENT-ON* */
1215/*
1216 * fd.io coding-style-patch-verification: ON
1217 *
1218 * Local Variables:
1219 * eval: (c-set-style "gnu")
1220 * End:
1221 */