blob: afd145fe620f355b396ff83f38f1727f43e62bd7 [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,
Filip Tehlar36217e32021-07-23 08:51:10 +0000347 DUMP_JSON,
Florin Corase86a8ed2018-01-05 03:20:25 -0800348 REPLAY,
349 INITIALIZERS,
350} vl_api_replay_t;
351
352u8 *
353format_vl_msg_api_trace_status (u8 * s, va_list * args)
354{
355 api_main_t *am = va_arg (*args, api_main_t *);
356 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
357 vl_api_trace_t *tp;
358 char *trace_name;
359
360 switch (which)
361 {
362 case VL_API_TRACE_TX:
363 tp = am->tx_trace;
364 trace_name = "TX trace";
365 break;
366
367 case VL_API_TRACE_RX:
368 tp = am->rx_trace;
369 trace_name = "RX trace";
370 break;
371
372 default:
373 abort ();
374 }
375
376 if (tp == 0)
377 {
378 s = format (s, "%s: not yet configured.\n", trace_name);
379 return s;
380 }
381
382 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
383 trace_name, vec_len (tp->traces), tp->nitems,
384 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
385 return s;
386}
387
Florin Corase86a8ed2018-01-05 03:20:25 -0800388static void
389vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
390 u32 first_index, u32 last_index,
391 vl_api_replay_t which)
392{
393 vl_api_trace_file_header_t *hp;
394 int i, fd;
Filip Tehlar36217e32021-07-23 08:51:10 +0000395 u16 *msgid_vec = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -0800396 struct stat statb;
397 size_t file_size;
398 u8 *msg;
Dave Barach39d69112019-11-27 11:42:13 -0500399 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800400 u8 *tmpbuf = 0;
Ole Troanedfe2c02019-07-30 15:38:13 +0200401 u32 nitems, nitems_msgtbl;
Florin Corase86a8ed2018-01-05 03:20:25 -0800402
403 fd = open ((char *) filename, O_RDONLY);
404
405 if (fd < 0)
406 {
407 vlib_cli_output (vm, "Couldn't open %s\n", filename);
408 return;
409 }
410
411 if (fstat (fd, &statb) < 0)
412 {
413 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
414 close (fd);
415 return;
416 }
417
418 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
419 {
420 vlib_cli_output (vm, "File not plausible: %s\n", filename);
421 close (fd);
422 return;
423 }
424
425 file_size = statb.st_size;
Benoît Ganneaba49832020-01-21 18:35:49 +0100426 file_size = (file_size + 4095) & ~(4095);
Florin Corase86a8ed2018-01-05 03:20:25 -0800427
428 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
429
430 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
431 {
432 vlib_cli_output (vm, "mmap failed: %s\n", filename);
433 close (fd);
434 return;
435 }
436 close (fd);
437
Benoît Ganneb2f09142019-12-16 15:37:28 +0100438 CLIB_MEM_UNPOISON (hp, file_size);
439
Ole Troanedfe2c02019-07-30 15:38:13 +0200440 nitems = ntohl (hp->nitems);
Florin Corase86a8ed2018-01-05 03:20:25 -0800441
442 if (last_index == (u32) ~ 0)
443 {
444 last_index = nitems - 1;
445 }
446
447 if (first_index >= nitems || last_index >= nitems)
448 {
449 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
450 first_index, last_index, nitems - 1);
451 munmap (hp, file_size);
452 return;
453 }
454 if (hp->wrapped)
455 vlib_cli_output (vm,
456 "Note: wrapped/incomplete trace, results may vary\n");
457
Filip Tehlar36217e32021-07-23 08:51:10 +0000458 size_t file_size_left = file_size;
459
460#define assert_size(size_left, s) \
461 do \
462 { \
463 if ((s) >= size_left) \
464 { \
465 vlib_cli_output (vm, "corrupted file"); \
466 munmap (hp, file_size); \
467 vec_free (msgid_vec); \
468 return; \
469 } \
470 size_left -= s; \
471 } \
472 while (0);
473
474 assert_size (file_size_left, sizeof (hp[0]));
Florin Corase86a8ed2018-01-05 03:20:25 -0800475 msg = (u8 *) (hp + 1);
476
Ole Troanedfe2c02019-07-30 15:38:13 +0200477 serialize_main_t _sm, *sm = &_sm;
478 u32 msgtbl_size = ntohl (hp->msgtbl_size);
479 u8 *name_and_crc;
480
Filip Tehlar36217e32021-07-23 08:51:10 +0000481 assert_size (file_size_left, msgtbl_size);
482
Ole Troanedfe2c02019-07-30 15:38:13 +0200483 unserialize_open_data (sm, msg, msgtbl_size);
484 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
485
486 for (i = 0; i < nitems_msgtbl; i++)
487 {
488 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
489 unserialize_cstring (sm, (char **) &name_and_crc);
490 u16 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
491 vec_validate (msgid_vec, msg_index);
492 msgid_vec[msg_index] = msg_index2;
493 }
494
495 msg += msgtbl_size;
496
Florin Corase86a8ed2018-01-05 03:20:25 -0800497 for (i = 0; i < first_index; i++)
498 {
499 trace_cfg_t *cfgp;
500 int size;
501 u16 msg_id;
502
Filip Tehlar36217e32021-07-23 08:51:10 +0000503 assert_size (file_size_left, sizeof (u32));
Florin Corase86a8ed2018-01-05 03:20:25 -0800504 size = clib_host_to_net_u32 (*(u32 *) msg);
505 msg += sizeof (u32);
506
Filip Tehlar36217e32021-07-23 08:51:10 +0000507 assert_size (file_size_left, size);
Ole Troanedfe2c02019-07-30 15:38:13 +0200508 msg_id = ntohs (*((u16 *) msg));
509 if (msg_id < vec_len (msgid_vec))
510 msg_id = msgid_vec[msg_id];
Florin Corase86a8ed2018-01-05 03:20:25 -0800511 cfgp = am->api_trace_cfg + msg_id;
512 if (!cfgp)
513 {
514 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
515 munmap (hp, file_size);
Filip Tehlar36217e32021-07-23 08:51:10 +0000516 vec_free (msgid_vec);
Florin Corase86a8ed2018-01-05 03:20:25 -0800517 return;
518 }
519 msg += size;
520 }
521
522 if (which == REPLAY)
523 am->replay_in_progress = 1;
524
525 for (; i <= last_index; i++)
526 {
527 trace_cfg_t *cfgp;
Florin Corase86a8ed2018-01-05 03:20:25 -0800528 u16 msg_id;
529 int size;
530
531 if (which == DUMP)
532 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
533
534 size = clib_host_to_net_u32 (*(u32 *) msg);
535 msg += sizeof (u32);
536
Ole Troanedfe2c02019-07-30 15:38:13 +0200537 msg_id = ntohs (*((u16 *) msg));
538 if (msg_id < vec_len (msgid_vec))
539 {
540 msg_id = msgid_vec[msg_id];
541 }
Florin Corase86a8ed2018-01-05 03:20:25 -0800542
543 cfgp = am->api_trace_cfg + msg_id;
544 if (!cfgp)
545 {
546 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
547 munmap (hp, file_size);
548 vec_free (tmpbuf);
549 am->replay_in_progress = 0;
550 return;
551 }
552
553 /* Copy the buffer (from the read-only mmap'ed file) */
554 vec_validate (tmpbuf, size - 1 + sizeof (uword));
555 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
Dave Barachb7b92992018-10-17 10:38:51 -0400556 clib_memset (tmpbuf, 0xf, sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800557
558 /*
Ole Troanedfe2c02019-07-30 15:38:13 +0200559 * Endian swap if needed. All msg data is supposed to be in
560 * network byte order.
Florin Corase86a8ed2018-01-05 03:20:25 -0800561 */
Filip Tehlar36217e32021-07-23 08:51:10 +0000562 if (((which == DUMP || which == DUMP_JSON) &&
563 clib_arch_is_little_endian))
Florin Corase86a8ed2018-01-05 03:20:25 -0800564 {
565 void (*endian_fp) (void *);
566 if (msg_id >= vec_len (am->msg_endian_handlers)
567 || (am->msg_endian_handlers[msg_id] == 0))
568 {
569 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
570 munmap (hp, file_size);
571 vec_free (tmpbuf);
572 am->replay_in_progress = 0;
573 return;
574 }
575 endian_fp = am->msg_endian_handlers[msg_id];
576 (*endian_fp) (tmpbuf + sizeof (uword));
577 }
578
579 /* msg_id always in network byte order */
580 if (clib_arch_is_little_endian)
581 {
Ole Troanedfe2c02019-07-30 15:38:13 +0200582 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800583 *msg_idp = msg_id;
584 }
585
586 switch (which)
587 {
Filip Tehlar36217e32021-07-23 08:51:10 +0000588 case DUMP_JSON:
589 if (msg_id < vec_len (am->msg_print_json_handlers) &&
590 am->msg_print_json_handlers[msg_id])
591 {
592 u8 *(*print_fp) (void *, void *);
593
594 print_fp = (void *) am->msg_print_json_handlers[msg_id];
595 (*print_fp) (tmpbuf + sizeof (uword), vm);
596 }
597 else
598 {
599 vlib_cli_output (vm, "Skipping msg id %d: no JSON print fcn\n",
600 msg_id);
601 break;
602 }
603 break;
604
Florin Corase86a8ed2018-01-05 03:20:25 -0800605 case DUMP:
606 if (msg_id < vec_len (am->msg_print_handlers) &&
607 am->msg_print_handlers[msg_id])
608 {
609 u8 *(*print_fp) (void *, void *);
610
611 print_fp = (void *) am->msg_print_handlers[msg_id];
612 (*print_fp) (tmpbuf + sizeof (uword), vm);
613 }
614 else
615 {
616 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
617 msg_id);
618 break;
619 }
620 break;
621
622 case INITIALIZERS:
623 if (msg_id < vec_len (am->msg_print_handlers) &&
624 am->msg_print_handlers[msg_id])
625 {
626 u8 *s;
627 int j;
628 u8 *(*print_fp) (void *, void *);
629
630 print_fp = (void *) am->msg_print_handlers[msg_id];
631
632 vlib_cli_output (vm, "/*");
633
634 (*print_fp) (tmpbuf + sizeof (uword), vm);
635 vlib_cli_output (vm, "*/\n");
636
637 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
638 am->msg_names[msg_id], i,
639 am->api_trace_cfg[msg_id].size);
640
641 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
642 {
643 if ((j & 7) == 0)
644 s = format (s, "\n ");
645 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
646 }
647 s = format (s, "\n};\n%c", 0);
648 vlib_cli_output (vm, (char *) s);
649 vec_free (s);
650 }
651 break;
652
653 case REPLAY:
654 if (msg_id < vec_len (am->msg_print_handlers) &&
655 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
656 {
John Loa56f2702018-06-25 20:38:35 -0400657 void (*handler) (void *, vlib_main_t *);
Florin Corase86a8ed2018-01-05 03:20:25 -0800658
659 handler = (void *) am->msg_handlers[msg_id];
660
661 if (!am->is_mp_safe[msg_id])
662 vl_msg_api_barrier_sync ();
John Loa56f2702018-06-25 20:38:35 -0400663 (*handler) (tmpbuf + sizeof (uword), vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800664 if (!am->is_mp_safe[msg_id])
665 vl_msg_api_barrier_release ();
666 }
667 else
668 {
669 if (cfgp->replay_enable)
670 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
671 msg_id);
672 break;
673 }
674 break;
675 }
676
677 _vec_len (tmpbuf) = 0;
678 msg += size;
679 }
680
Florin Corase86a8ed2018-01-05 03:20:25 -0800681 munmap (hp, file_size);
682 vec_free (tmpbuf);
Filip Tehlar36217e32021-07-23 08:51:10 +0000683 vec_free (msgid_vec);
Florin Corase86a8ed2018-01-05 03:20:25 -0800684 am->replay_in_progress = 0;
685}
686
Filip Tehlar36217e32021-07-23 08:51:10 +0000687static int
688file_exists (u8 *fname)
689{
690 FILE *fp = 0;
691 fp = fopen ((char *) fname, "r");
692 if (fp)
693 {
694 fclose (fp);
695 return 1;
696 }
697 return 0;
698}
699
700typedef struct
701{
702 vlib_main_t *vm;
703 u8 is_json;
704} vl_msg_print_args;
705
706static int
707vl_msg_print_trace (u8 *msg, void *ctx)
708{
709 vl_msg_print_args *a = ctx;
710 api_main_t *am = vlibapi_get_main ();
711 u16 msg_id = ntohs (*((u16 *) msg));
712 void (*print_fp) (void *, void *);
713 void (**handlers) (void *, void *);
714 u8 is_json = a->is_json;
715 u8 *tmpbuf = 0;
716
717 if (clib_arch_is_little_endian)
718 {
719 u32 msg_length = vec_len (msg);
720 vec_validate (tmpbuf, msg_length - 1);
721 clib_memcpy_fast (tmpbuf, msg, msg_length);
722 msg = tmpbuf;
723
724 void (*endian_fp) (void *);
725 endian_fp = am->msg_endian_handlers[msg_id];
726 (*endian_fp) (tmpbuf);
727 }
728
729 if (is_json)
730 handlers = am->msg_print_json_handlers;
731 else
732 handlers = am->msg_print_handlers;
733
734 if (msg_id < vec_len (handlers) && handlers[msg_id])
735 {
736 print_fp = (void *) handlers[msg_id];
737 (*print_fp) (msg, a->vm);
738 }
739 else
740 {
741 vlib_cli_output (a->vm, "Skipping msg id %d: no print fcn\n", msg_id);
742 }
743
744 vec_free (tmpbuf);
745 return 0;
746}
747
748static int
749vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
750{
751 api_main_t *am = vlibapi_get_main ();
752 vl_api_trace_t *tp;
753
754 switch (which)
755 {
756 case VL_API_TRACE_TX:
757 tp = am->tx_trace;
758 break;
759 case VL_API_TRACE_RX:
760 tp = am->rx_trace;
761 break;
762 default:
763 return -1;
764 }
765
766 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
767 return -1;
768
769 vl_msg_print_args args;
770 clib_memset (&args, 0, sizeof (args));
771 args.is_json = is_json;
772 args.vm = vm;
773 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
774
775 return 0;
776}
777
778static char *
779vl_msg_read_file (FILE *f)
780{
781 const size_t bufsize = 1024;
782 char *buf[bufsize], *v = 0;
783 size_t n;
784
785 while ((n = fread (buf, 1, bufsize, f)))
786 vec_add (v, buf, n);
787
Benoît Ganne2b9a4bf2021-10-11 13:49:59 +0200788 /* most callers expect a NULL-terminated C-string */
789 if (v)
790 vec_add1 (v, 0);
791
Filip Tehlar36217e32021-07-23 08:51:10 +0000792 return v;
793}
794
795static u16
796vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
797{
798 uword *p;
799 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
800 if (!p)
801 return (u16) ~0;
802
803 return p[0];
804}
805
806static u16
807vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
808{
809 uword *p;
810
811 if (!am->msg_id_by_name)
812 {
813 vlib_cli_output (vm, "message id table not yet initialized!\n");
814 return (u16) ~0;
815 }
816
817 p = hash_get_mem (am->msg_id_by_name, name);
818 if (!p)
819 return (u16) ~0;
820
821 return p[0];
822}
823
824static int
825vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
826{
827 api_main_t *am = vlibapi_get_main ();
828 u16 msg_id;
829 void *(*fromjson) (cJSON *, int *);
830 int len = 0, rv = -1;
831 trace_cfg_t *cfgp;
832 u8 *msg = 0;
833
834 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
835 if (!msg_id_obj)
836 {
837 vlib_cli_output (vm, "Missing '_msgname' element!\n");
838 return rv;
839 }
840 char *name = cJSON_GetStringValue (msg_id_obj);
841
842 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
Florin Corasf6e6da92021-10-12 08:41:09 -0700843 if (!crc_obj)
Filip Tehlar36217e32021-07-23 08:51:10 +0000844 {
845 vlib_cli_output (vm, "Missing '_crc' element!\n");
846 return rv;
847 }
848 char *crc = cJSON_GetStringValue (crc_obj);
849 u8 proc_warning = 0;
850
851 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
852 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
853 if (msg_id == (u16) ~0)
854 {
855 msg_id = vl_msg_find_id_by_name (vm, am, name);
856 if (msg_id == (u16) ~0)
857 {
858 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
859 vec_free (name_crc);
860 return rv;
861 }
862 proc_warning = 1;
863 }
864 vec_free (name_crc);
865
866 cfgp = am->api_trace_cfg + msg_id;
Florin Corasf6e6da92021-10-12 08:41:09 -0700867 if (!am->api_trace_cfg)
Filip Tehlar36217e32021-07-23 08:51:10 +0000868 {
869 vlib_cli_output (vm, "msg id %d no trace config\n", msg_id);
870 return rv;
871 }
872
873 if (cfgp->replay_enable)
874 {
875
876 if (proc_warning)
877 vlib_cli_output (vm, "warning: msg %d has different signature\n");
878
879 fromjson = am->msg_fromjson_handlers[msg_id];
880 if (!fromjson)
881 {
882 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
883 msg_id);
884 return rv;
885 }
886
887 msg = (u8 *) fromjson (o, &len);
888 if (!msg)
889 {
890 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
891 msg_id);
892 return rv;
893 }
894
895 if (clib_arch_is_little_endian)
896 {
897 void (*endian_fp) (void *);
898 endian_fp = am->msg_endian_handlers[msg_id];
899 (*endian_fp) (msg);
900 }
901
902 void (*handler) (void *, vlib_main_t *);
903 handler = (void *) am->msg_handlers[msg_id];
904 if (!handler)
905 {
906 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
907 goto end;
908 }
909
910 if (!am->is_mp_safe[msg_id])
911 vl_msg_api_barrier_sync ();
912 (*handler) (msg, vm);
913 if (!am->is_mp_safe[msg_id])
914 vl_msg_api_barrier_release ();
915 }
916
917 rv = 0;
918end:
919 if (msg)
920 cJSON_free (msg);
921 return rv;
922}
923
924static void
925vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
926{
927 api_main_t *am = vlibapi_get_main ();
928 cJSON *o = 0;
929 int rv = 0;
930 FILE *f = fopen ((char *) filename, "r");
931
932 if (!f)
933 {
934 vlib_cli_output (vm, "failed to open %s!\n", filename);
935 return;
936 }
937
938 char *buf = vl_msg_read_file (f);
939 fclose (f);
940
941 o = cJSON_Parse (buf);
942 vec_free (buf);
943 if (!o)
944 {
945 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
946 cJSON_GetErrorPtr ());
947 return;
948 }
949
950 if (cJSON_IsArray (o))
951 {
952 am->replay_in_progress = 1;
953 size_t size = cJSON_GetArraySize (o);
954 for (int i = 0; i < size; i++)
955 {
956 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
957 if (rv < 0)
958 {
959 am->replay_in_progress = 0;
960 break;
961 }
962 }
963 }
964 else
965 {
966 rv = vl_msg_exec_json_command (vm, o);
967 }
968
969 if (rv < 0)
970 vlib_cli_output (vm, "error during replaying API trace");
971
972 cJSON_Delete (o);
973}
974
975static void
976vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
977{
978 FILE *f = fopen ((char *) filename, "r");
979 char *buf;
980
981 if (!f)
982 {
983 vlib_cli_output (vm, "failed to open %s!\n", filename);
984 return;
985 }
986
987 buf = vl_msg_read_file (f);
988 fclose (f);
989
990 if (!buf)
991 {
992 vlib_cli_output (vm, "no content in %s!\n", filename);
993 return;
994 }
995
996 vlib_cli_output (vm, buf);
997 vec_free (buf);
998}
999
Dave Barachf66f8832020-01-23 08:44:40 -05001000/** api_trace_command_fn - control the binary API trace / replay feature
1001
1002 Note: this command MUST be marked thread-safe. Replay with
1003 multiple worker threads depends in many cases on worker thread
1004 graph replica maintenance. If we (implicitly) assert a worker
1005 thread barrier at the debug CLI level, all graph replica changes
1006 are deferred until the replay operation completes. If an interface
1007 is deleted, the wheels fall off.
1008 */
1009
Florin Corase86a8ed2018-01-05 03:20:25 -08001010static clib_error_t *
1011api_trace_command_fn (vlib_main_t * vm,
1012 unformat_input_t * input, vlib_cli_command_t * cmd)
1013{
Neale Rannsecff1cb2020-04-22 12:14:52 -04001014 unformat_input_t _line_input, *line_input = &_line_input;
Florin Corase86a8ed2018-01-05 03:20:25 -08001015 u32 nitems = 256 << 10;
Dave Barach39d69112019-11-27 11:42:13 -05001016 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001017 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barachf35a0722019-06-12 16:50:38 -04001018 u8 *filename = 0;
1019 u8 *chroot_filename = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -08001020 u32 first = 0;
1021 u32 last = (u32) ~ 0;
1022 FILE *fp;
1023 int rv;
1024
Neale Rannsecff1cb2020-04-22 12:14:52 -04001025 /* Get a line of input. */
1026 if (!unformat_user (input, unformat_line_input, line_input))
1027 return 0;
1028
1029 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Florin Corase86a8ed2018-01-05 03:20:25 -08001030 {
Neale Rannsecff1cb2020-04-22 12:14:52 -04001031 if (unformat (line_input, "on") || unformat (line_input, "enable"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001032 {
Neale Rannsecff1cb2020-04-22 12:14:52 -04001033 if (unformat (line_input, "nitems %d", &nitems))
Florin Corase86a8ed2018-01-05 03:20:25 -08001034 ;
Dave Barachf66f8832020-01-23 08:44:40 -05001035 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001036 vl_msg_api_trace_configure (am, which, nitems);
1037 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
Dave Barachf66f8832020-01-23 08:44:40 -05001038 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001039 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001040 else if (unformat (line_input, "off"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001041 {
Dave Barachf66f8832020-01-23 08:44:40 -05001042 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001043 vl_msg_api_trace_onoff (am, which, 0);
Dave Barachf66f8832020-01-23 08:44:40 -05001044 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001045 }
Filip Tehlar36217e32021-07-23 08:51:10 +00001046 else if (unformat (line_input, "save-json %s", &filename))
1047 {
1048 if (strstr ((char *) filename, "..") ||
1049 index ((char *) filename, '/'))
1050 {
1051 vlib_cli_output (vm, "illegal characters in filename '%s'",
1052 filename);
1053 goto out;
1054 }
1055
1056 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1057
1058 vec_free (filename);
1059
1060 if (file_exists (chroot_filename))
1061 {
1062 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1063 goto out;
1064 }
1065
1066 fp = fopen ((char *) chroot_filename, "w");
1067 if (fp == NULL)
1068 {
1069 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1070 goto out;
1071 }
1072 vlib_worker_thread_barrier_sync (vm);
1073 rv = vl_msg_api_trace_save (am, which, fp, 1);
1074 if (rv == -1)
1075 vlib_cli_output (vm, "API Trace data not present\n");
1076 else if (rv < 0)
1077 vlib_cli_output (vm, "failed to save api trace\n");
1078 else
1079 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1080 vlib_worker_thread_barrier_release (vm);
1081 fclose (fp);
1082 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001083 else if (unformat (line_input, "save %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001084 {
Florin Corase86a8ed2018-01-05 03:20:25 -08001085 if (strstr ((char *) filename, "..")
1086 || index ((char *) filename, '/'))
1087 {
1088 vlib_cli_output (vm, "illegal characters in filename '%s'",
1089 filename);
Dave Barachf35a0722019-06-12 16:50:38 -04001090 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -08001091 }
1092
1093 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1094
1095 vec_free (filename);
1096
Filip Tehlar36217e32021-07-23 08:51:10 +00001097 if (file_exists (chroot_filename))
1098 {
1099 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1100 goto out;
1101 }
1102
Florin Corase86a8ed2018-01-05 03:20:25 -08001103 fp = fopen ((char *) chroot_filename, "w");
1104 if (fp == NULL)
1105 {
1106 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
Dave Barachf35a0722019-06-12 16:50:38 -04001107 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -08001108 }
Dave Barachf66f8832020-01-23 08:44:40 -05001109 vlib_worker_thread_barrier_sync (vm);
Filip Tehlar36217e32021-07-23 08:51:10 +00001110 rv = vl_msg_api_trace_save (am, which, fp, 0);
Dave Barachf66f8832020-01-23 08:44:40 -05001111 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001112 fclose (fp);
1113 if (rv == -1)
1114 vlib_cli_output (vm, "API Trace data not present\n");
1115 else if (rv == -2)
1116 vlib_cli_output (vm, "File for writing is closed\n");
1117 else if (rv == -10)
1118 vlib_cli_output (vm, "Error while writing header to file\n");
1119 else if (rv == -11)
1120 vlib_cli_output (vm, "Error while writing trace to file\n");
1121 else if (rv == -12)
1122 vlib_cli_output (vm,
1123 "Error while writing end of buffer trace to file\n");
1124 else if (rv == -13)
1125 vlib_cli_output (vm,
1126 "Error while writing start of buffer trace to file\n");
1127 else if (rv < 0)
Andrey "Zed" Zaikin701625b2018-04-18 17:07:07 +03001128 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
Florin Corase86a8ed2018-01-05 03:20:25 -08001129 else
1130 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
Dave Barachf35a0722019-06-12 16:50:38 -04001131 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -08001132 }
Filip Tehlar36217e32021-07-23 08:51:10 +00001133 else if (unformat (line_input, "tojson %s", &filename))
1134 {
1135 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1136 }
1137 else if (unformat (line_input, "dump-file-json %s", &filename))
1138 {
1139 vl_msg_dump_file_json (vm, filename);
1140 }
1141 else if (unformat (line_input, "dump-file %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001142 {
1143 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1144 }
Filip Tehlar36217e32021-07-23 08:51:10 +00001145 else if (unformat (line_input, "dump-json"))
1146 {
1147 vl_msg_api_dump_trace (vm, which, 1);
1148 }
1149 else if (unformat (line_input, "dump"))
1150 {
1151 vl_msg_api_dump_trace (vm, which, 0);
1152 }
1153 else if (unformat (line_input, "replay-json %s", &filename))
1154 {
1155 vl_msg_replay_json (vm, filename);
1156 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001157 else if (unformat (line_input, "replay %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001158 {
1159 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1160 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001161 else if (unformat (line_input, "initializers %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001162 {
1163 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1164 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001165 else if (unformat (line_input, "tx"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001166 {
1167 which = VL_API_TRACE_TX;
1168 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001169 else if (unformat (line_input, "first %d", &first))
Florin Corase86a8ed2018-01-05 03:20:25 -08001170 {
1171 ;
1172 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001173 else if (unformat (line_input, "last %d", &last))
Florin Corase86a8ed2018-01-05 03:20:25 -08001174 {
1175 ;
1176 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001177 else if (unformat (line_input, "status"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001178 {
1179 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1180 am, which);
1181 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001182 else if (unformat (line_input, "free"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001183 {
Dave Barachf66f8832020-01-23 08:44:40 -05001184 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001185 vl_msg_api_trace_onoff (am, which, 0);
1186 vl_msg_api_trace_free (am, which);
Dave Barachf66f8832020-01-23 08:44:40 -05001187 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001188 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001189 else if (unformat (line_input, "post-mortem-on"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001190 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
Neale Rannsecff1cb2020-04-22 12:14:52 -04001191 else if (unformat (line_input, "post-mortem-off"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001192 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1193 else
1194 return clib_error_return (0, "unknown input `%U'",
1195 format_unformat_error, input);
1196 }
Dave Barachf35a0722019-06-12 16:50:38 -04001197out:
1198 vec_free (filename);
1199 vec_free (chroot_filename);
Neale Rannsecff1cb2020-04-22 12:14:52 -04001200 unformat_free (line_input);
Florin Corase86a8ed2018-01-05 03:20:25 -08001201 return 0;
1202}
1203
1204/*?
1205 * Display, replay, or save a binary API trace
1206?*/
1207
1208/* *INDENT-OFF* */
Filip Tehlarc863a912021-06-15 10:29:54 +00001209VLIB_CLI_COMMAND (api_trace_command, static) = {
Florin Corase86a8ed2018-01-05 03:20:25 -08001210 .path = "api trace",
Filip Tehlar36217e32021-07-23 08:51:10 +00001211 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1212 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1213 "json|replay <file>|replay-json <file>][nitems <n>]"
1214 "[initializers <file>]",
Florin Corase86a8ed2018-01-05 03:20:25 -08001215 .function = api_trace_command_fn,
Dave Barachf66f8832020-01-23 08:44:40 -05001216 .is_mp_safe = 1,
Florin Corase86a8ed2018-01-05 03:20:25 -08001217};
1218/* *INDENT-ON* */
1219
1220static clib_error_t *
Florin Corase86a8ed2018-01-05 03:20:25 -08001221api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1222{
1223 u32 nitems = 256 << 10;
1224 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barach39d69112019-11-27 11:42:13 -05001225 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001226
1227 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1228 {
1229 if (unformat (input, "on") || unformat (input, "enable"))
1230 {
1231 if (unformat (input, "nitems %d", &nitems))
1232 ;
1233 vl_msg_api_trace_configure (am, which, nitems);
1234 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1235 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1236 }
1237 else if (unformat (input, "save-api-table %s",
1238 &am->save_msg_table_filename))
1239 ;
1240 else
1241 return clib_error_return (0, "unknown input `%U'",
1242 format_unformat_error, input);
1243 }
1244 return 0;
1245}
1246
1247/*?
1248 * This module has three configuration parameters:
1249 * "on" or "enable" - enables binary api tracing
1250 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1251 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1252?*/
1253VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1254
1255static clib_error_t *
1256api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1257{
Dave Barach39d69112019-11-27 11:42:13 -05001258 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001259 u32 nitems;
1260
1261 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1262 {
1263 if (unformat (input, "length %d", &nitems) ||
1264 (unformat (input, "len %d", &nitems)))
1265 {
1266 if (nitems >= 1024)
1267 am->vlib_input_queue_length = nitems;
1268 else
1269 clib_warning ("vlib input queue length %d too small, ignored",
1270 nitems);
1271 }
1272 else
1273 return clib_error_return (0, "unknown input `%U'",
1274 format_unformat_error, input);
1275 }
1276 return 0;
1277}
1278
1279VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1280
1281static u8 *
1282extract_name (u8 * s)
1283{
1284 u8 *rv;
1285
1286 rv = vec_dup (s);
1287
1288 while (vec_len (rv) && rv[vec_len (rv)] != '_')
1289 _vec_len (rv)--;
1290
1291 rv[vec_len (rv)] = 0;
1292
1293 return rv;
1294}
1295
1296static u8 *
1297extract_crc (u8 * s)
1298{
1299 int i;
1300 u8 *rv;
1301
1302 rv = vec_dup (s);
1303
1304 for (i = vec_len (rv) - 1; i >= 0; i--)
1305 {
1306 if (rv[i] == '_')
1307 {
1308 vec_delete (rv, i + 1, 0);
1309 break;
1310 }
1311 }
1312 return rv;
1313}
1314
1315typedef struct
1316{
1317 u8 *name_and_crc;
1318 u8 *name;
1319 u8 *crc;
1320 u32 msg_index;
1321 int which;
1322} msg_table_unserialize_t;
1323
1324static int
1325table_id_cmp (void *a1, void *a2)
1326{
1327 msg_table_unserialize_t *n1 = a1;
1328 msg_table_unserialize_t *n2 = a2;
1329
1330 return (n1->msg_index - n2->msg_index);
1331}
1332
1333static int
1334table_name_and_crc_cmp (void *a1, void *a2)
1335{
1336 msg_table_unserialize_t *n1 = a1;
1337 msg_table_unserialize_t *n2 = a2;
1338
1339 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1340}
1341
1342static clib_error_t *
1343dump_api_table_file_command_fn (vlib_main_t * vm,
1344 unformat_input_t * input,
1345 vlib_cli_command_t * cmd)
1346{
1347 u8 *filename = 0;
Dave Barach39d69112019-11-27 11:42:13 -05001348 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001349 serialize_main_t _sm, *sm = &_sm;
1350 clib_error_t *error;
1351 u32 nmsgs;
1352 u32 msg_index;
1353 u8 *name_and_crc;
1354 int compare_current = 0;
1355 int numeric_sort = 0;
1356 msg_table_unserialize_t *table = 0, *item;
1357 u32 i;
1358 u32 ndifferences = 0;
1359
1360 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1361 {
1362 if (unformat (input, "file %s", &filename))
1363 ;
1364 else if (unformat (input, "compare-current")
1365 || unformat (input, "compare"))
1366 compare_current = 1;
1367 else if (unformat (input, "numeric"))
1368 numeric_sort = 1;
1369 else
1370 return clib_error_return (0, "unknown input `%U'",
1371 format_unformat_error, input);
1372 }
1373
1374 if (numeric_sort && compare_current)
1375 return clib_error_return
1376 (0, "Comparison and numeric sorting are incompatible");
1377
1378 if (filename == 0)
1379 return clib_error_return (0, "File not specified");
1380
1381 /* Load the serialized message table from the table dump */
1382
1383 error = unserialize_open_clib_file (sm, (char *) filename);
1384
1385 if (error)
1386 return error;
1387
1388 unserialize_integer (sm, &nmsgs, sizeof (u32));
1389
1390 for (i = 0; i < nmsgs; i++)
1391 {
1392 msg_index = unserialize_likely_small_unsigned_integer (sm);
1393 unserialize_cstring (sm, (char **) &name_and_crc);
1394 vec_add2 (table, item, 1);
1395 item->msg_index = msg_index;
1396 item->name_and_crc = name_and_crc;
1397 item->name = extract_name (name_and_crc);
1398 item->crc = extract_crc (name_and_crc);
1399 item->which = 0; /* file */
1400 }
Ole Troanedfe2c02019-07-30 15:38:13 +02001401 unserialize_close (sm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001402
1403 /* Compare with the current image? */
1404 if (compare_current)
1405 {
1406 /* Append the current message table */
1407 u8 *tblv = vl_api_serialize_message_table (am, 0);
1408
1409 serialize_open_vector (sm, tblv);
1410 unserialize_integer (sm, &nmsgs, sizeof (u32));
1411
1412 for (i = 0; i < nmsgs; i++)
1413 {
1414 msg_index = unserialize_likely_small_unsigned_integer (sm);
1415 unserialize_cstring (sm, (char **) &name_and_crc);
1416
1417 vec_add2 (table, item, 1);
1418 item->msg_index = msg_index;
1419 item->name_and_crc = name_and_crc;
1420 item->name = extract_name (name_and_crc);
1421 item->crc = extract_crc (name_and_crc);
1422 item->which = 1; /* current_image */
1423 }
1424 vec_free (tblv);
1425 }
1426
1427 /* Sort the table. */
1428 if (numeric_sort)
1429 vec_sort_with_function (table, table_id_cmp);
1430 else
1431 vec_sort_with_function (table, table_name_and_crc_cmp);
1432
1433 if (compare_current)
1434 {
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001435 u8 *dashes = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -08001436 ndifferences = 0;
1437
1438 /*
1439 * In this case, the recovered table will have two entries per
1440 * API message. So, if entries i and i+1 match, the message definitions
1441 * are identical. Otherwise, the crc is different, or a message is
1442 * present in only one of the tables.
1443 */
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001444 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1445 vec_validate_init_empty (dashes, 60, '-');
1446 vec_terminate_c_string (dashes);
1447 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1448 vec_free (dashes);
Florin Corase86a8ed2018-01-05 03:20:25 -08001449 for (i = 0; i < vec_len (table);)
1450 {
1451 /* Last message lonely? */
1452 if (i == vec_len (table) - 1)
1453 {
1454 ndifferences++;
1455 goto last_unique;
1456 }
1457
1458 /* Identical pair? */
1459 if (!strncmp
1460 ((char *) table[i].name_and_crc,
1461 (char *) table[i + 1].name_and_crc,
1462 vec_len (table[i].name_and_crc)))
1463 {
1464 i += 2;
1465 continue;
1466 }
1467
1468 ndifferences++;
1469
1470 /* Only in one of two tables? */
Andrew Yourtchenkoae605b82019-01-21 16:39:33 +01001471 if (i + 1 == vec_len (table)
1472 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
Florin Corase86a8ed2018-01-05 03:20:25 -08001473 {
1474 last_unique:
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001475 vlib_cli_output (vm, "%-60s | only in %s",
Florin Corase86a8ed2018-01-05 03:20:25 -08001476 table[i].name, table[i].which ?
1477 "image" : "file");
1478 i++;
1479 continue;
1480 }
1481 /* In both tables, but with different signatures */
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001482 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
Florin Corase86a8ed2018-01-05 03:20:25 -08001483 i += 2;
1484 }
1485 if (ndifferences == 0)
1486 vlib_cli_output (vm, "No api message signature differences found.");
1487 else
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001488 vlib_cli_output (vm, "\nFound %u api message signature differences",
Florin Corase86a8ed2018-01-05 03:20:25 -08001489 ndifferences);
1490 goto cleanup;
1491 }
1492
1493 /* Dump the table, sorted as shown above */
1494 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1495
1496 for (i = 0; i < vec_len (table); i++)
1497 {
1498 item = table + i;
1499 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1500 item->msg_index, item->crc);
1501 }
1502
1503cleanup:
1504 for (i = 0; i < vec_len (table); i++)
1505 {
1506 vec_free (table[i].name_and_crc);
1507 vec_free (table[i].name);
1508 vec_free (table[i].crc);
1509 }
1510
1511 vec_free (table);
1512
1513 return 0;
1514}
1515
1516/*?
1517 * Displays a serialized API message decode table, sorted by message name
1518 *
1519 * @cliexpar
1520 * @cliexstart{show api dump file <filename>}
1521 * Message name MsgID CRC
1522 * accept_session 407 8e2a127e
1523 * accept_session_reply 408 67d8c22a
1524 * add_node_next 549 e4202993
1525 * add_node_next_reply 550 e89d6eed
1526 * etc.
1527 * @cliexend
1528?*/
1529
1530/*?
1531 * Compares a serialized API message decode table with the current image
1532 *
1533 * @cliexpar
1534 * @cliexstart{show api dump file <filename> compare}
1535 * ip_add_del_route definition changed
1536 * ip_table_add_del definition changed
1537 * l2_macs_event only in image
1538 * vnet_ip4_fib_counters only in file
1539 * vnet_ip4_nbr_counters only in file
1540 * @cliexend
1541?*/
1542
1543/*?
1544 * Display a serialized API message decode table, compare a saved
1545 * decode table with the current image, to establish API differences.
1546 *
1547?*/
1548/* *INDENT-OFF* */
1549VLIB_CLI_COMMAND (dump_api_table_file, static) =
1550{
1551 .path = "show api dump",
1552 .short_help = "show api dump file <filename> [numeric | compare-current]",
1553 .function = dump_api_table_file_command_fn,
1554};
1555
1556/* *INDENT-ON* */
1557/*
1558 * fd.io coding-style-patch-verification: ON
1559 *
1560 * Local Variables:
1561 * eval: (c-set-style "gnu")
1562 * End:
1563 */