blob: 4492f5af9808d58781b73d5c87b21c37f326b165 [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?*/
Florin Corase86a8ed2018-01-05 03:20:25 -080064VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
65{
66 .path = "show api histogram",
67 .short_help = "show api histogram",
68 .function = vl_api_show_histogram_command,
69};
Florin Corase86a8ed2018-01-05 03:20:25 -080070
71static clib_error_t *
72vl_api_clear_histogram_command (vlib_main_t * vm,
73 unformat_input_t * input,
74 vlib_cli_command_t * cli_cmd)
75{
76 int i;
77
78 for (i = 0; i < SLEEP_N_BUCKETS; i++)
79 vector_rate_histogram[i] = 0;
80 return 0;
81}
82
83/*?
84 * Clear the binary api sleep-time histogram
85?*/
Florin Corase86a8ed2018-01-05 03:20:25 -080086VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
87{
88 .path = "clear api histogram",
89 .short_help = "clear api histogram",
90 .function = vl_api_clear_histogram_command,
91};
Florin Corase86a8ed2018-01-05 03:20:25 -080092
93static clib_error_t *
94vl_api_client_command (vlib_main_t * vm,
95 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
96{
97 vl_api_registration_t **regpp, *regp;
98 svm_queue_t *q;
99 char *health;
Dave Barach39d69112019-11-27 11:42:13 -0500100 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800101 u32 *confused_indices = 0;
102
103 if (!pool_elts (am->vl_clients))
104 goto socket_clients;
105 vlib_cli_output (vm, "Shared memory clients");
106 vlib_cli_output (vm, "%20s %8s %14s %18s %s",
107 "Name", "PID", "Queue Length", "Queue VA", "Health");
108
Damjan Marionb2c31b62020-12-13 21:47:40 +0100109 pool_foreach (regpp, am->vl_clients)
110 {
Florin Corase86a8ed2018-01-05 03:20:25 -0800111 regp = *regpp;
112
113 if (regp)
114 {
115 if (regp->unanswered_pings > 0)
116 health = "questionable";
117 else
118 health = "OK";
119
120 q = regp->vl_input_queue;
121
122 vlib_cli_output (vm, "%20s %8d %14d 0x%016llx %s\n",
123 regp->name, q->consumer_pid, q->cursize,
124 q, health);
125 }
126 else
127 {
128 clib_warning ("NULL client registration index %d",
129 regpp - am->vl_clients);
130 vec_add1 (confused_indices, regpp - am->vl_clients);
131 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100132 }
Florin Corase86a8ed2018-01-05 03:20:25 -0800133
134 /* This should "never happen," but if it does, fix it... */
135 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
136 {
137 int i;
138 for (i = 0; i < vec_len (confused_indices); i++)
139 {
140 pool_put_index (am->vl_clients, confused_indices[i]);
141 }
142 }
143 vec_free (confused_indices);
144
145 if (am->missing_clients)
146 vlib_cli_output (vm, "%u messages with missing clients",
147 am->missing_clients);
148socket_clients:
149 vl_sock_api_dump_clients (vm, am);
150
151 return 0;
152}
153
154static clib_error_t *
155vl_api_status_command (vlib_main_t * vm,
156 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
157{
Dave Barach39d69112019-11-27 11:42:13 -0500158 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800159
160 /* check if rx_trace and tx_trace are not null pointers */
161 if (am->rx_trace == 0)
162 {
163 vlib_cli_output (vm, "RX Trace disabled\n");
164 }
165 else
166 {
167 if (am->rx_trace->enabled == 0)
168 vlib_cli_output (vm, "RX Trace disabled\n");
169 else
170 vlib_cli_output (vm, "RX Trace enabled\n");
171 }
172
173 if (am->tx_trace == 0)
174 {
175 vlib_cli_output (vm, "TX Trace disabled\n");
176 }
177 else
178 {
179 if (am->tx_trace->enabled == 0)
180 vlib_cli_output (vm, "TX Trace disabled\n");
181 else
182 vlib_cli_output (vm, "TX Trace enabled\n");
183 }
184
185 return 0;
186}
187
Florin Corase86a8ed2018-01-05 03:20:25 -0800188VLIB_CLI_COMMAND (cli_show_api_command, static) =
189{
190 .path = "show api",
191 .short_help = "Show API information",
192};
Florin Corase86a8ed2018-01-05 03:20:25 -0800193
194/*?
195 * Display current api client connections
196?*/
Florin Corase86a8ed2018-01-05 03:20:25 -0800197VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
198{
199 .path = "show api clients",
200 .short_help = "Client information",
201 .function = vl_api_client_command,
202};
Florin Corase86a8ed2018-01-05 03:20:25 -0800203
204/*?
205 * Display the current api message tracing status
206?*/
Florin Corase86a8ed2018-01-05 03:20:25 -0800207VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
208{
209 .path = "show api trace-status",
210 .short_help = "Display API trace status",
211 .function = vl_api_status_command,
212};
Florin Corase86a8ed2018-01-05 03:20:25 -0800213
214static clib_error_t *
215vl_api_message_table_command (vlib_main_t * vm,
216 unformat_input_t * input,
217 vlib_cli_command_t * cli_cmd)
218{
Dave Barach39d69112019-11-27 11:42:13 -0500219 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800220 int i;
221 int verbose = 0;
222
223 if (unformat (input, "verbose"))
224 verbose = 1;
225
226
227 if (verbose == 0)
228 vlib_cli_output (vm, "%-4s %s", "ID", "Name");
229 else
230 vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
231 "MP-safe");
232
Damjan Marioncada9eb2022-05-18 22:16:11 +0200233 for (i = 1; i < vec_len (am->msg_data); i++)
Florin Corase86a8ed2018-01-05 03:20:25 -0800234 {
Damjan Marioncada9eb2022-05-18 22:16:11 +0200235 vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
Florin Corase86a8ed2018-01-05 03:20:25 -0800236 if (verbose == 0)
237 {
238 vlib_cli_output (vm, "%-4d %s", i,
Damjan Marioncada9eb2022-05-18 22:16:11 +0200239 m->name ? m->name : " [no handler]");
Florin Corase86a8ed2018-01-05 03:20:25 -0800240 }
241 else
242 {
243 vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
Damjan Marioncada9eb2022-05-18 22:16:11 +0200244 m->name ? m->name : " [no handler]", m->bounce,
245 m->is_mp_safe);
Florin Corase86a8ed2018-01-05 03:20:25 -0800246 }
247 }
248
249 return 0;
250}
251
252/*?
253 * Display the current api message decode tables
254?*/
Florin Corase86a8ed2018-01-05 03:20:25 -0800255VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
256{
257 .path = "show api message-table",
258 .short_help = "Message Table",
259 .function = vl_api_message_table_command,
260};
Florin Corase86a8ed2018-01-05 03:20:25 -0800261
262static int
263range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
264{
265 int len0, len1, clen;
266
267 len0 = vec_len (a0->name);
268 len1 = vec_len (a1->name);
269 clen = len0 < len1 ? len0 : len1;
270 return (strncmp ((char *) a0->name, (char *) a1->name, clen));
271}
272
273static u8 *
274format_api_msg_range (u8 * s, va_list * args)
275{
276 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
277
278 if (rp == 0)
279 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
280 else
281 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
282 rp->last_msg_id);
283
284 return s;
285}
286
287static clib_error_t *
288vl_api_show_plugin_command (vlib_main_t * vm,
289 unformat_input_t * input,
290 vlib_cli_command_t * cli_cmd)
291{
Dave Barach39d69112019-11-27 11:42:13 -0500292 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800293 vl_api_msg_range_t *rp = 0;
294 int i;
295
296 if (vec_len (am->msg_ranges) == 0)
297 {
298 vlib_cli_output (vm, "No plugin API message ranges configured...");
299 return 0;
300 }
301
302 rp = vec_dup (am->msg_ranges);
303
304 vec_sort_with_function (rp, range_compare);
305
306 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
307 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
308
309 for (i = 0; i < vec_len (rp); i++)
310 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
311
312 vec_free (rp);
313
314 return 0;
315}
316
317/*?
318 * Display the plugin binary API message range table
319?*/
Florin Corase86a8ed2018-01-05 03:20:25 -0800320VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
321{
322 .path = "show api plugin",
323 .short_help = "show api plugin",
324 .function = vl_api_show_plugin_command,
325};
Florin Corase86a8ed2018-01-05 03:20:25 -0800326
327typedef enum
328{
329 DUMP,
Filip Tehlar36217e32021-07-23 08:51:10 +0000330 DUMP_JSON,
Florin Corase86a8ed2018-01-05 03:20:25 -0800331 REPLAY,
332 INITIALIZERS,
333} vl_api_replay_t;
334
335u8 *
336format_vl_msg_api_trace_status (u8 * s, va_list * args)
337{
338 api_main_t *am = va_arg (*args, api_main_t *);
339 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
340 vl_api_trace_t *tp;
341 char *trace_name;
342
343 switch (which)
344 {
345 case VL_API_TRACE_TX:
346 tp = am->tx_trace;
347 trace_name = "TX trace";
348 break;
349
350 case VL_API_TRACE_RX:
351 tp = am->rx_trace;
352 trace_name = "RX trace";
353 break;
354
355 default:
356 abort ();
357 }
358
359 if (tp == 0)
360 {
361 s = format (s, "%s: not yet configured.\n", trace_name);
362 return s;
363 }
364
365 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
366 trace_name, vec_len (tp->traces), tp->nitems,
367 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
368 return s;
369}
370
Florin Corase86a8ed2018-01-05 03:20:25 -0800371static void
372vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
373 u32 first_index, u32 last_index,
374 vl_api_replay_t which)
375{
376 vl_api_trace_file_header_t *hp;
377 int i, fd;
Filip Tehlar36217e32021-07-23 08:51:10 +0000378 u16 *msgid_vec = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -0800379 struct stat statb;
380 size_t file_size;
381 u8 *msg;
Dave Barach39d69112019-11-27 11:42:13 -0500382 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800383 u8 *tmpbuf = 0;
Ole Troanedfe2c02019-07-30 15:38:13 +0200384 u32 nitems, nitems_msgtbl;
Florin Corase86a8ed2018-01-05 03:20:25 -0800385
386 fd = open ((char *) filename, O_RDONLY);
387
388 if (fd < 0)
389 {
390 vlib_cli_output (vm, "Couldn't open %s\n", filename);
391 return;
392 }
393
394 if (fstat (fd, &statb) < 0)
395 {
396 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
397 close (fd);
398 return;
399 }
400
401 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
402 {
403 vlib_cli_output (vm, "File not plausible: %s\n", filename);
404 close (fd);
405 return;
406 }
407
408 file_size = statb.st_size;
Benoît Ganneaba49832020-01-21 18:35:49 +0100409 file_size = (file_size + 4095) & ~(4095);
Florin Corase86a8ed2018-01-05 03:20:25 -0800410
411 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
412
413 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
414 {
415 vlib_cli_output (vm, "mmap failed: %s\n", filename);
416 close (fd);
417 return;
418 }
419 close (fd);
420
Damjan Marion79934e82022-04-05 12:40:31 +0200421 clib_mem_unpoison (hp, file_size);
Benoît Ganneb2f09142019-12-16 15:37:28 +0100422
Ole Troanedfe2c02019-07-30 15:38:13 +0200423 nitems = ntohl (hp->nitems);
Florin Corase86a8ed2018-01-05 03:20:25 -0800424
425 if (last_index == (u32) ~ 0)
426 {
427 last_index = nitems - 1;
428 }
429
430 if (first_index >= nitems || last_index >= nitems)
431 {
432 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
433 first_index, last_index, nitems - 1);
434 munmap (hp, file_size);
435 return;
436 }
437 if (hp->wrapped)
438 vlib_cli_output (vm,
439 "Note: wrapped/incomplete trace, results may vary\n");
440
Filip Tehlar36217e32021-07-23 08:51:10 +0000441 size_t file_size_left = file_size;
442
443#define assert_size(size_left, s) \
444 do \
445 { \
446 if ((s) >= size_left) \
447 { \
448 vlib_cli_output (vm, "corrupted file"); \
449 munmap (hp, file_size); \
450 vec_free (msgid_vec); \
451 return; \
452 } \
453 size_left -= s; \
454 } \
455 while (0);
456
457 assert_size (file_size_left, sizeof (hp[0]));
Florin Corase86a8ed2018-01-05 03:20:25 -0800458 msg = (u8 *) (hp + 1);
459
Ole Troanedfe2c02019-07-30 15:38:13 +0200460 serialize_main_t _sm, *sm = &_sm;
461 u32 msgtbl_size = ntohl (hp->msgtbl_size);
462 u8 *name_and_crc;
463
Filip Tehlar36217e32021-07-23 08:51:10 +0000464 assert_size (file_size_left, msgtbl_size);
465
Ole Troanedfe2c02019-07-30 15:38:13 +0200466 unserialize_open_data (sm, msg, msgtbl_size);
467 unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
468
469 for (i = 0; i < nitems_msgtbl; i++)
470 {
471 u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
472 unserialize_cstring (sm, (char **) &name_and_crc);
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100473 u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
474 ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
475 if (~0 == msg_index2)
476 vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
477 msg_index);
Ole Troanedfe2c02019-07-30 15:38:13 +0200478 vec_validate (msgid_vec, msg_index);
479 msgid_vec[msg_index] = msg_index2;
480 }
481
482 msg += msgtbl_size;
483
Florin Corase86a8ed2018-01-05 03:20:25 -0800484 for (i = 0; i < first_index; i++)
485 {
Florin Corase86a8ed2018-01-05 03:20:25 -0800486 int size;
487 u16 msg_id;
488
Filip Tehlar36217e32021-07-23 08:51:10 +0000489 assert_size (file_size_left, sizeof (u32));
Florin Corase86a8ed2018-01-05 03:20:25 -0800490 size = clib_host_to_net_u32 (*(u32 *) msg);
491 msg += sizeof (u32);
492
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100493 assert_size (file_size_left, clib_max (size, sizeof (u16)));
Ole Troanedfe2c02019-07-30 15:38:13 +0200494 msg_id = ntohs (*((u16 *) msg));
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100495 if (msg_id >= vec_len (msgid_vec) ||
Damjan Marioncada9eb2022-05-18 22:16:11 +0200496 msgid_vec[msg_id] >= vec_len (am->msg_data))
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100497 vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
498 msg_id, i);
499
Florin Corase86a8ed2018-01-05 03:20:25 -0800500 msg += size;
501 }
502
503 if (which == REPLAY)
504 am->replay_in_progress = 1;
505
506 for (; i <= last_index; i++)
507 {
Damjan Marioncada9eb2022-05-18 22:16:11 +0200508 vl_api_msg_data_t *m;
Florin Corase86a8ed2018-01-05 03:20:25 -0800509 u16 msg_id;
510 int size;
511
512 if (which == DUMP)
513 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
514
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100515 assert_size (file_size_left, sizeof (u32));
Florin Corase86a8ed2018-01-05 03:20:25 -0800516 size = clib_host_to_net_u32 (*(u32 *) msg);
517 msg += sizeof (u32);
518
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100519 assert_size (file_size_left, clib_max (size, sizeof (u16)));
Ole Troanedfe2c02019-07-30 15:38:13 +0200520 msg_id = ntohs (*((u16 *) msg));
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100521
522 if (msg_id >= vec_len (msgid_vec) ||
Damjan Marioncada9eb2022-05-18 22:16:11 +0200523 msgid_vec[msg_id] >= vec_len (am->msg_data))
Ole Troanedfe2c02019-07-30 15:38:13 +0200524 {
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100525 vlib_cli_output (
526 vm, "warning: unknown msg id %d for msg number %d, skipping\n",
527 msg_id, i);
528 msg += size;
529 continue;
Ole Troanedfe2c02019-07-30 15:38:13 +0200530 }
Florin Corase86a8ed2018-01-05 03:20:25 -0800531
Benoît Ganne7e0442a2022-01-20 13:44:12 +0100532 msg_id = msgid_vec[msg_id];
Damjan Marioncada9eb2022-05-18 22:16:11 +0200533 m = vl_api_get_msg_data (am, msg_id);
Florin Corase86a8ed2018-01-05 03:20:25 -0800534
535 /* Copy the buffer (from the read-only mmap'ed file) */
536 vec_validate (tmpbuf, size - 1 + sizeof (uword));
537 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
Dave Barachb7b92992018-10-17 10:38:51 -0400538 clib_memset (tmpbuf, 0xf, sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800539
540 /*
Ole Troanedfe2c02019-07-30 15:38:13 +0200541 * Endian swap if needed. All msg data is supposed to be in
542 * network byte order.
Florin Corase86a8ed2018-01-05 03:20:25 -0800543 */
Filip Tehlar36217e32021-07-23 08:51:10 +0000544 if (((which == DUMP || which == DUMP_JSON) &&
545 clib_arch_is_little_endian))
Florin Corase86a8ed2018-01-05 03:20:25 -0800546 {
Damjan Marioncada9eb2022-05-18 22:16:11 +0200547 if (m && m->endian_handler == 0)
Florin Corase86a8ed2018-01-05 03:20:25 -0800548 {
549 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
550 munmap (hp, file_size);
551 vec_free (tmpbuf);
552 am->replay_in_progress = 0;
553 return;
554 }
Andrew Yourtchenkoa3018af2022-08-17 13:24:11 +0000555 if (m)
556 {
557 m->endian_handler (tmpbuf + sizeof (uword));
558 }
Florin Corase86a8ed2018-01-05 03:20:25 -0800559 }
560
561 /* msg_id always in network byte order */
562 if (clib_arch_is_little_endian)
563 {
Ole Troanedfe2c02019-07-30 15:38:13 +0200564 u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800565 *msg_idp = msg_id;
566 }
567
568 switch (which)
569 {
Filip Tehlar36217e32021-07-23 08:51:10 +0000570 case DUMP_JSON:
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200571 vlib_cli_output (vm, "%U", format_vl_api_msg_json, am, msg_id,
572 tmpbuf + sizeof (uword));
Filip Tehlar36217e32021-07-23 08:51:10 +0000573 break;
574
Florin Corase86a8ed2018-01-05 03:20:25 -0800575 case DUMP:
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200576 vlib_cli_output (vm, "%U", format_vl_api_msg_text, am, msg_id,
577 tmpbuf + sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800578 break;
579
580 case INITIALIZERS:
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200581 if (m)
Florin Corase86a8ed2018-01-05 03:20:25 -0800582 {
583 u8 *s;
584 int j;
Florin Corase86a8ed2018-01-05 03:20:25 -0800585
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200586 vlib_cli_output (vm, "/*%U*/", format_vl_api_msg_text, am,
587 msg_id, tmpbuf + sizeof (uword));
Florin Corase86a8ed2018-01-05 03:20:25 -0800588
Florin Corase86a8ed2018-01-05 03:20:25 -0800589 vlib_cli_output (vm, "*/\n");
590
Damjan Marioncada9eb2022-05-18 22:16:11 +0200591 s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
592 m->trace_size);
Florin Corase86a8ed2018-01-05 03:20:25 -0800593
Damjan Marioncada9eb2022-05-18 22:16:11 +0200594 for (j = 0; j < m->trace_size; j++)
Florin Corase86a8ed2018-01-05 03:20:25 -0800595 {
596 if ((j & 7) == 0)
597 s = format (s, "\n ");
598 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
599 }
600 s = format (s, "\n};\n%c", 0);
601 vlib_cli_output (vm, (char *) s);
602 vec_free (s);
603 }
604 break;
605
606 case REPLAY:
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200607 if (m && m->handler && m->replay_allowed)
Florin Corase86a8ed2018-01-05 03:20:25 -0800608 {
Damjan Marioncada9eb2022-05-18 22:16:11 +0200609 if (!m->is_mp_safe)
Florin Corase86a8ed2018-01-05 03:20:25 -0800610 vl_msg_api_barrier_sync ();
Damjan Marioncada9eb2022-05-18 22:16:11 +0200611 m->handler (tmpbuf + sizeof (uword));
612 if (!m->is_mp_safe)
Florin Corase86a8ed2018-01-05 03:20:25 -0800613 vl_msg_api_barrier_release ();
614 }
615 else
616 {
Andrew Yourtchenko618afb52022-08-26 13:46:44 +0000617 if (m && m->replay_allowed)
Florin Corase86a8ed2018-01-05 03:20:25 -0800618 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
619 msg_id);
620 break;
621 }
622 break;
623 }
624
Damjan Marion8bea5892022-04-04 22:40:45 +0200625 vec_set_len (tmpbuf, 0);
Florin Corase86a8ed2018-01-05 03:20:25 -0800626 msg += size;
627 }
628
Florin Corase86a8ed2018-01-05 03:20:25 -0800629 munmap (hp, file_size);
630 vec_free (tmpbuf);
Filip Tehlar36217e32021-07-23 08:51:10 +0000631 vec_free (msgid_vec);
Florin Corase86a8ed2018-01-05 03:20:25 -0800632 am->replay_in_progress = 0;
633}
634
Filip Tehlar36217e32021-07-23 08:51:10 +0000635static int
636file_exists (u8 *fname)
637{
638 FILE *fp = 0;
639 fp = fopen ((char *) fname, "r");
640 if (fp)
641 {
642 fclose (fp);
643 return 1;
644 }
645 return 0;
646}
647
648typedef struct
649{
650 vlib_main_t *vm;
651 u8 is_json;
652} vl_msg_print_args;
653
654static int
655vl_msg_print_trace (u8 *msg, void *ctx)
656{
657 vl_msg_print_args *a = ctx;
658 api_main_t *am = vlibapi_get_main ();
659 u16 msg_id = ntohs (*((u16 *) msg));
Damjan Marioncada9eb2022-05-18 22:16:11 +0200660 vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
Filip Tehlar36217e32021-07-23 08:51:10 +0000661 u8 is_json = a->is_json;
662 u8 *tmpbuf = 0;
663
Damjan Marioncada9eb2022-05-18 22:16:11 +0200664 if (!m)
665 {
666 vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
667 return 0;
668 }
669
Matthew Smith5b32d3a2023-04-19 20:02:25 +0000670 if (clib_arch_is_little_endian && (m->endian_handler != NULL))
Filip Tehlar36217e32021-07-23 08:51:10 +0000671 {
672 u32 msg_length = vec_len (msg);
673 vec_validate (tmpbuf, msg_length - 1);
674 clib_memcpy_fast (tmpbuf, msg, msg_length);
675 msg = tmpbuf;
676
Damjan Marioncada9eb2022-05-18 22:16:11 +0200677 m->endian_handler (tmpbuf);
Filip Tehlar36217e32021-07-23 08:51:10 +0000678 }
679
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200680 vlib_cli_output (a->vm, "%U\n",
681 is_json ? format_vl_api_msg_json : format_vl_api_msg_text,
682 am, msg_id, msg);
Filip Tehlar36217e32021-07-23 08:51:10 +0000683
684 vec_free (tmpbuf);
685 return 0;
686}
687
688static int
689vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
690{
691 api_main_t *am = vlibapi_get_main ();
692 vl_api_trace_t *tp;
693
694 switch (which)
695 {
696 case VL_API_TRACE_TX:
697 tp = am->tx_trace;
698 break;
699 case VL_API_TRACE_RX:
700 tp = am->rx_trace;
701 break;
702 default:
703 return -1;
704 }
705
706 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
707 return -1;
708
709 vl_msg_print_args args;
710 clib_memset (&args, 0, sizeof (args));
711 args.is_json = is_json;
712 args.vm = vm;
713 vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
714
715 return 0;
716}
717
718static char *
719vl_msg_read_file (FILE *f)
720{
721 const size_t bufsize = 1024;
722 char *buf[bufsize], *v = 0;
723 size_t n;
724
725 while ((n = fread (buf, 1, bufsize, f)))
726 vec_add (v, buf, n);
727
Benoît Ganne2b9a4bf2021-10-11 13:49:59 +0200728 /* most callers expect a NULL-terminated C-string */
729 if (v)
730 vec_add1 (v, 0);
731
Filip Tehlar36217e32021-07-23 08:51:10 +0000732 return v;
733}
734
735static u16
736vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
737{
738 uword *p;
739 p = hash_get_mem (am->msg_index_by_name_and_crc, name);
740 if (!p)
741 return (u16) ~0;
742
743 return p[0];
744}
745
746static u16
747vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
748{
749 uword *p;
750
751 if (!am->msg_id_by_name)
752 {
753 vlib_cli_output (vm, "message id table not yet initialized!\n");
754 return (u16) ~0;
755 }
756
757 p = hash_get_mem (am->msg_id_by_name, name);
758 if (!p)
759 return (u16) ~0;
760
761 return p[0];
762}
763
764static int
765vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
766{
767 api_main_t *am = vlibapi_get_main ();
768 u16 msg_id;
Filip Tehlar36217e32021-07-23 08:51:10 +0000769 int len = 0, rv = -1;
Damjan Marioncada9eb2022-05-18 22:16:11 +0200770 vl_api_msg_data_t *m;
Filip Tehlar36217e32021-07-23 08:51:10 +0000771 u8 *msg = 0;
772
773 cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
774 if (!msg_id_obj)
775 {
776 vlib_cli_output (vm, "Missing '_msgname' element!\n");
777 return rv;
778 }
779 char *name = cJSON_GetStringValue (msg_id_obj);
780
781 cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
Florin Corasf6e6da92021-10-12 08:41:09 -0700782 if (!crc_obj)
Filip Tehlar36217e32021-07-23 08:51:10 +0000783 {
784 vlib_cli_output (vm, "Missing '_crc' element!\n");
785 return rv;
786 }
787 char *crc = cJSON_GetStringValue (crc_obj);
788 u8 proc_warning = 0;
789
790 u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
791 msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
Damjan Marioncada9eb2022-05-18 22:16:11 +0200792 m = vl_api_get_msg_data (am, msg_id);
Filip Tehlar36217e32021-07-23 08:51:10 +0000793 if (msg_id == (u16) ~0)
794 {
795 msg_id = vl_msg_find_id_by_name (vm, am, name);
796 if (msg_id == (u16) ~0)
797 {
798 vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
799 vec_free (name_crc);
800 return rv;
801 }
802 proc_warning = 1;
803 }
804 vec_free (name_crc);
805
Damjan Marioncada9eb2022-05-18 22:16:11 +0200806 if (m->replay_allowed)
Filip Tehlar36217e32021-07-23 08:51:10 +0000807 {
Filip Tehlar36217e32021-07-23 08:51:10 +0000808 if (proc_warning)
809 vlib_cli_output (vm, "warning: msg %d has different signature\n");
810
Damjan Marioncada9eb2022-05-18 22:16:11 +0200811 if (!m->fromjson_handler)
Filip Tehlar36217e32021-07-23 08:51:10 +0000812 {
813 vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
814 msg_id);
815 return rv;
816 }
817
Damjan Marioncada9eb2022-05-18 22:16:11 +0200818 msg = (u8 *) m->fromjson_handler (o, &len);
Filip Tehlar36217e32021-07-23 08:51:10 +0000819 if (!msg)
820 {
821 vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
822 msg_id);
823 return rv;
824 }
825
826 if (clib_arch_is_little_endian)
Damjan Marioncada9eb2022-05-18 22:16:11 +0200827 m->endian_handler (msg);
Filip Tehlar36217e32021-07-23 08:51:10 +0000828
Damjan Marioncada9eb2022-05-18 22:16:11 +0200829 if (!m->handler)
Filip Tehlar36217e32021-07-23 08:51:10 +0000830 {
831 vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
832 goto end;
833 }
834
Damjan Marionfe45f8f2022-05-20 16:01:22 +0200835 if (m->handler)
836 {
837 if (!m->is_mp_safe)
838 vl_msg_api_barrier_sync ();
839 m->handler (msg);
840 if (!m->is_mp_safe)
841 vl_msg_api_barrier_release ();
842 }
Filip Tehlar36217e32021-07-23 08:51:10 +0000843 }
844
845 rv = 0;
846end:
847 if (msg)
848 cJSON_free (msg);
849 return rv;
850}
851
852static void
853vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
854{
855 api_main_t *am = vlibapi_get_main ();
856 cJSON *o = 0;
857 int rv = 0;
858 FILE *f = fopen ((char *) filename, "r");
859
860 if (!f)
861 {
862 vlib_cli_output (vm, "failed to open %s!\n", filename);
863 return;
864 }
865
866 char *buf = vl_msg_read_file (f);
867 fclose (f);
868
869 o = cJSON_Parse (buf);
870 vec_free (buf);
871 if (!o)
872 {
873 vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
874 cJSON_GetErrorPtr ());
875 return;
876 }
877
878 if (cJSON_IsArray (o))
879 {
880 am->replay_in_progress = 1;
881 size_t size = cJSON_GetArraySize (o);
882 for (int i = 0; i < size; i++)
883 {
884 rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
885 if (rv < 0)
886 {
887 am->replay_in_progress = 0;
888 break;
889 }
890 }
891 }
892 else
893 {
894 rv = vl_msg_exec_json_command (vm, o);
895 }
896
897 if (rv < 0)
898 vlib_cli_output (vm, "error during replaying API trace");
899
900 cJSON_Delete (o);
901}
902
903static void
904vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
905{
906 FILE *f = fopen ((char *) filename, "r");
907 char *buf;
908
909 if (!f)
910 {
911 vlib_cli_output (vm, "failed to open %s!\n", filename);
912 return;
913 }
914
915 buf = vl_msg_read_file (f);
916 fclose (f);
917
918 if (!buf)
919 {
920 vlib_cli_output (vm, "no content in %s!\n", filename);
921 return;
922 }
923
924 vlib_cli_output (vm, buf);
925 vec_free (buf);
926}
927
Dave Barachf66f8832020-01-23 08:44:40 -0500928/** api_trace_command_fn - control the binary API trace / replay feature
929
930 Note: this command MUST be marked thread-safe. Replay with
931 multiple worker threads depends in many cases on worker thread
932 graph replica maintenance. If we (implicitly) assert a worker
933 thread barrier at the debug CLI level, all graph replica changes
934 are deferred until the replay operation completes. If an interface
935 is deleted, the wheels fall off.
936 */
937
Florin Corase86a8ed2018-01-05 03:20:25 -0800938static clib_error_t *
939api_trace_command_fn (vlib_main_t * vm,
940 unformat_input_t * input, vlib_cli_command_t * cmd)
941{
Neale Rannsecff1cb2020-04-22 12:14:52 -0400942 unformat_input_t _line_input, *line_input = &_line_input;
Florin Corase86a8ed2018-01-05 03:20:25 -0800943 u32 nitems = 256 << 10;
Dave Barach39d69112019-11-27 11:42:13 -0500944 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -0800945 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barachf35a0722019-06-12 16:50:38 -0400946 u8 *filename = 0;
947 u8 *chroot_filename = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -0800948 u32 first = 0;
949 u32 last = (u32) ~ 0;
950 FILE *fp;
951 int rv;
952
Neale Rannsecff1cb2020-04-22 12:14:52 -0400953 /* Get a line of input. */
954 if (!unformat_user (input, unformat_line_input, line_input))
955 return 0;
956
957 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Florin Corase86a8ed2018-01-05 03:20:25 -0800958 {
Neale Rannsecff1cb2020-04-22 12:14:52 -0400959 if (unformat (line_input, "on") || unformat (line_input, "enable"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800960 {
Neale Rannsecff1cb2020-04-22 12:14:52 -0400961 if (unformat (line_input, "nitems %d", &nitems))
Florin Corase86a8ed2018-01-05 03:20:25 -0800962 ;
Dave Barachf66f8832020-01-23 08:44:40 -0500963 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800964 vl_msg_api_trace_configure (am, which, nitems);
965 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
Dave Barachf66f8832020-01-23 08:44:40 -0500966 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800967 }
Neale Rannsecff1cb2020-04-22 12:14:52 -0400968 else if (unformat (line_input, "off"))
Florin Corase86a8ed2018-01-05 03:20:25 -0800969 {
Dave Barachf66f8832020-01-23 08:44:40 -0500970 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800971 vl_msg_api_trace_onoff (am, which, 0);
Dave Barachf66f8832020-01-23 08:44:40 -0500972 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -0800973 }
Filip Tehlar36217e32021-07-23 08:51:10 +0000974 else if (unformat (line_input, "save-json %s", &filename))
975 {
976 if (strstr ((char *) filename, "..") ||
977 index ((char *) filename, '/'))
978 {
979 vlib_cli_output (vm, "illegal characters in filename '%s'",
980 filename);
981 goto out;
982 }
983
984 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
985
986 vec_free (filename);
987
988 if (file_exists (chroot_filename))
989 {
990 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
991 goto out;
992 }
993
994 fp = fopen ((char *) chroot_filename, "w");
995 if (fp == NULL)
996 {
997 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
998 goto out;
999 }
1000 vlib_worker_thread_barrier_sync (vm);
1001 rv = vl_msg_api_trace_save (am, which, fp, 1);
1002 if (rv == -1)
1003 vlib_cli_output (vm, "API Trace data not present\n");
1004 else if (rv < 0)
1005 vlib_cli_output (vm, "failed to save api trace\n");
1006 else
1007 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1008 vlib_worker_thread_barrier_release (vm);
1009 fclose (fp);
1010 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001011 else if (unformat (line_input, "save %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001012 {
Florin Corase86a8ed2018-01-05 03:20:25 -08001013 if (strstr ((char *) filename, "..")
1014 || index ((char *) filename, '/'))
1015 {
1016 vlib_cli_output (vm, "illegal characters in filename '%s'",
1017 filename);
Dave Barachf35a0722019-06-12 16:50:38 -04001018 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -08001019 }
1020
1021 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1022
1023 vec_free (filename);
1024
Filip Tehlar36217e32021-07-23 08:51:10 +00001025 if (file_exists (chroot_filename))
1026 {
1027 vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1028 goto out;
1029 }
1030
Florin Corase86a8ed2018-01-05 03:20:25 -08001031 fp = fopen ((char *) chroot_filename, "w");
1032 if (fp == NULL)
1033 {
1034 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
Dave Barachf35a0722019-06-12 16:50:38 -04001035 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -08001036 }
Dave Barachf66f8832020-01-23 08:44:40 -05001037 vlib_worker_thread_barrier_sync (vm);
Filip Tehlar36217e32021-07-23 08:51:10 +00001038 rv = vl_msg_api_trace_save (am, which, fp, 0);
Dave Barachf66f8832020-01-23 08:44:40 -05001039 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001040 fclose (fp);
1041 if (rv == -1)
1042 vlib_cli_output (vm, "API Trace data not present\n");
1043 else if (rv == -2)
1044 vlib_cli_output (vm, "File for writing is closed\n");
1045 else if (rv == -10)
1046 vlib_cli_output (vm, "Error while writing header to file\n");
1047 else if (rv == -11)
1048 vlib_cli_output (vm, "Error while writing trace to file\n");
1049 else if (rv == -12)
1050 vlib_cli_output (vm,
1051 "Error while writing end of buffer trace to file\n");
1052 else if (rv == -13)
1053 vlib_cli_output (vm,
1054 "Error while writing start of buffer trace to file\n");
1055 else if (rv < 0)
Andrey "Zed" Zaikin701625b2018-04-18 17:07:07 +03001056 vlib_cli_output (vm, "Unknown error while saving: %d", rv);
Florin Corase86a8ed2018-01-05 03:20:25 -08001057 else
1058 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
Dave Barachf35a0722019-06-12 16:50:38 -04001059 goto out;
Florin Corase86a8ed2018-01-05 03:20:25 -08001060 }
Filip Tehlar36217e32021-07-23 08:51:10 +00001061 else if (unformat (line_input, "tojson %s", &filename))
1062 {
1063 vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1064 }
1065 else if (unformat (line_input, "dump-file-json %s", &filename))
1066 {
1067 vl_msg_dump_file_json (vm, filename);
1068 }
1069 else if (unformat (line_input, "dump-file %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001070 {
1071 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1072 }
Filip Tehlar36217e32021-07-23 08:51:10 +00001073 else if (unformat (line_input, "dump-json"))
1074 {
1075 vl_msg_api_dump_trace (vm, which, 1);
1076 }
1077 else if (unformat (line_input, "dump"))
1078 {
1079 vl_msg_api_dump_trace (vm, which, 0);
1080 }
1081 else if (unformat (line_input, "replay-json %s", &filename))
1082 {
1083 vl_msg_replay_json (vm, filename);
1084 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001085 else if (unformat (line_input, "replay %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001086 {
1087 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1088 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001089 else if (unformat (line_input, "initializers %s", &filename))
Florin Corase86a8ed2018-01-05 03:20:25 -08001090 {
1091 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1092 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001093 else if (unformat (line_input, "tx"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001094 {
1095 which = VL_API_TRACE_TX;
1096 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001097 else if (unformat (line_input, "first %d", &first))
Florin Corase86a8ed2018-01-05 03:20:25 -08001098 {
1099 ;
1100 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001101 else if (unformat (line_input, "last %d", &last))
Florin Corase86a8ed2018-01-05 03:20:25 -08001102 {
1103 ;
1104 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001105 else if (unformat (line_input, "status"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001106 {
1107 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1108 am, which);
1109 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001110 else if (unformat (line_input, "free"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001111 {
Dave Barachf66f8832020-01-23 08:44:40 -05001112 vlib_worker_thread_barrier_sync (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001113 vl_msg_api_trace_onoff (am, which, 0);
1114 vl_msg_api_trace_free (am, which);
Dave Barachf66f8832020-01-23 08:44:40 -05001115 vlib_worker_thread_barrier_release (vm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001116 }
Neale Rannsecff1cb2020-04-22 12:14:52 -04001117 else if (unformat (line_input, "post-mortem-on"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001118 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
Neale Rannsecff1cb2020-04-22 12:14:52 -04001119 else if (unformat (line_input, "post-mortem-off"))
Florin Corase86a8ed2018-01-05 03:20:25 -08001120 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1121 else
1122 return clib_error_return (0, "unknown input `%U'",
1123 format_unformat_error, input);
1124 }
Dave Barachf35a0722019-06-12 16:50:38 -04001125out:
1126 vec_free (filename);
1127 vec_free (chroot_filename);
Neale Rannsecff1cb2020-04-22 12:14:52 -04001128 unformat_free (line_input);
Florin Corase86a8ed2018-01-05 03:20:25 -08001129 return 0;
1130}
1131
1132/*?
1133 * Display, replay, or save a binary API trace
1134?*/
1135
Filip Tehlarc863a912021-06-15 10:29:54 +00001136VLIB_CLI_COMMAND (api_trace_command, static) = {
Florin Corase86a8ed2018-01-05 03:20:25 -08001137 .path = "api trace",
Filip Tehlar36217e32021-07-23 08:51:10 +00001138 .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1139 "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1140 "json|replay <file>|replay-json <file>][nitems <n>]"
1141 "[initializers <file>]",
Florin Corase86a8ed2018-01-05 03:20:25 -08001142 .function = api_trace_command_fn,
Dave Barachf66f8832020-01-23 08:44:40 -05001143 .is_mp_safe = 1,
Florin Corase86a8ed2018-01-05 03:20:25 -08001144};
Florin Corase86a8ed2018-01-05 03:20:25 -08001145
1146static clib_error_t *
Florin Corase86a8ed2018-01-05 03:20:25 -08001147api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1148{
1149 u32 nitems = 256 << 10;
1150 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barach39d69112019-11-27 11:42:13 -05001151 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001152
1153 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1154 {
1155 if (unformat (input, "on") || unformat (input, "enable"))
1156 {
1157 if (unformat (input, "nitems %d", &nitems))
1158 ;
1159 vl_msg_api_trace_configure (am, which, nitems);
1160 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1161 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1162 }
1163 else if (unformat (input, "save-api-table %s",
1164 &am->save_msg_table_filename))
1165 ;
1166 else
1167 return clib_error_return (0, "unknown input `%U'",
1168 format_unformat_error, input);
1169 }
1170 return 0;
1171}
1172
1173/*?
1174 * This module has three configuration parameters:
1175 * "on" or "enable" - enables binary api tracing
1176 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1177 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1178?*/
1179VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1180
1181static clib_error_t *
1182api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1183{
Dave Barach39d69112019-11-27 11:42:13 -05001184 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001185 u32 nitems;
1186
1187 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1188 {
1189 if (unformat (input, "length %d", &nitems) ||
1190 (unformat (input, "len %d", &nitems)))
1191 {
1192 if (nitems >= 1024)
1193 am->vlib_input_queue_length = nitems;
1194 else
1195 clib_warning ("vlib input queue length %d too small, ignored",
1196 nitems);
1197 }
1198 else
1199 return clib_error_return (0, "unknown input `%U'",
1200 format_unformat_error, input);
1201 }
1202 return 0;
1203}
1204
1205VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1206
1207static u8 *
1208extract_name (u8 * s)
1209{
1210 u8 *rv;
1211
1212 rv = vec_dup (s);
1213
1214 while (vec_len (rv) && rv[vec_len (rv)] != '_')
Andrew Yourtchenko105cb1e2022-04-15 14:23:41 +00001215 vec_dec_len (rv, 1);
Florin Corase86a8ed2018-01-05 03:20:25 -08001216
1217 rv[vec_len (rv)] = 0;
1218
1219 return rv;
1220}
1221
1222static u8 *
1223extract_crc (u8 * s)
1224{
1225 int i;
1226 u8 *rv;
1227
1228 rv = vec_dup (s);
1229
1230 for (i = vec_len (rv) - 1; i >= 0; i--)
1231 {
1232 if (rv[i] == '_')
1233 {
1234 vec_delete (rv, i + 1, 0);
1235 break;
1236 }
1237 }
1238 return rv;
1239}
1240
1241typedef struct
1242{
1243 u8 *name_and_crc;
1244 u8 *name;
1245 u8 *crc;
1246 u32 msg_index;
1247 int which;
1248} msg_table_unserialize_t;
1249
1250static int
1251table_id_cmp (void *a1, void *a2)
1252{
1253 msg_table_unserialize_t *n1 = a1;
1254 msg_table_unserialize_t *n2 = a2;
1255
1256 return (n1->msg_index - n2->msg_index);
1257}
1258
1259static int
1260table_name_and_crc_cmp (void *a1, void *a2)
1261{
1262 msg_table_unserialize_t *n1 = a1;
1263 msg_table_unserialize_t *n2 = a2;
1264
1265 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1266}
1267
1268static clib_error_t *
1269dump_api_table_file_command_fn (vlib_main_t * vm,
1270 unformat_input_t * input,
1271 vlib_cli_command_t * cmd)
1272{
1273 u8 *filename = 0;
Dave Barach39d69112019-11-27 11:42:13 -05001274 api_main_t *am = vlibapi_get_main ();
Florin Corase86a8ed2018-01-05 03:20:25 -08001275 serialize_main_t _sm, *sm = &_sm;
1276 clib_error_t *error;
1277 u32 nmsgs;
1278 u32 msg_index;
1279 u8 *name_and_crc;
1280 int compare_current = 0;
1281 int numeric_sort = 0;
1282 msg_table_unserialize_t *table = 0, *item;
1283 u32 i;
1284 u32 ndifferences = 0;
1285
1286 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1287 {
1288 if (unformat (input, "file %s", &filename))
1289 ;
1290 else if (unformat (input, "compare-current")
1291 || unformat (input, "compare"))
1292 compare_current = 1;
1293 else if (unformat (input, "numeric"))
1294 numeric_sort = 1;
1295 else
1296 return clib_error_return (0, "unknown input `%U'",
1297 format_unformat_error, input);
1298 }
1299
1300 if (numeric_sort && compare_current)
1301 return clib_error_return
1302 (0, "Comparison and numeric sorting are incompatible");
1303
1304 if (filename == 0)
1305 return clib_error_return (0, "File not specified");
1306
1307 /* Load the serialized message table from the table dump */
1308
1309 error = unserialize_open_clib_file (sm, (char *) filename);
1310
1311 if (error)
1312 return error;
1313
1314 unserialize_integer (sm, &nmsgs, sizeof (u32));
1315
1316 for (i = 0; i < nmsgs; i++)
1317 {
1318 msg_index = unserialize_likely_small_unsigned_integer (sm);
1319 unserialize_cstring (sm, (char **) &name_and_crc);
1320 vec_add2 (table, item, 1);
1321 item->msg_index = msg_index;
1322 item->name_and_crc = name_and_crc;
1323 item->name = extract_name (name_and_crc);
1324 item->crc = extract_crc (name_and_crc);
1325 item->which = 0; /* file */
1326 }
Ole Troanedfe2c02019-07-30 15:38:13 +02001327 unserialize_close (sm);
Florin Corase86a8ed2018-01-05 03:20:25 -08001328
1329 /* Compare with the current image? */
1330 if (compare_current)
1331 {
1332 /* Append the current message table */
1333 u8 *tblv = vl_api_serialize_message_table (am, 0);
1334
1335 serialize_open_vector (sm, tblv);
1336 unserialize_integer (sm, &nmsgs, sizeof (u32));
1337
1338 for (i = 0; i < nmsgs; i++)
1339 {
1340 msg_index = unserialize_likely_small_unsigned_integer (sm);
1341 unserialize_cstring (sm, (char **) &name_and_crc);
1342
1343 vec_add2 (table, item, 1);
1344 item->msg_index = msg_index;
1345 item->name_and_crc = name_and_crc;
1346 item->name = extract_name (name_and_crc);
1347 item->crc = extract_crc (name_and_crc);
1348 item->which = 1; /* current_image */
1349 }
1350 vec_free (tblv);
1351 }
1352
1353 /* Sort the table. */
1354 if (numeric_sort)
1355 vec_sort_with_function (table, table_id_cmp);
1356 else
1357 vec_sort_with_function (table, table_name_and_crc_cmp);
1358
1359 if (compare_current)
1360 {
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001361 u8 *dashes = 0;
Florin Corase86a8ed2018-01-05 03:20:25 -08001362 ndifferences = 0;
1363
1364 /*
1365 * In this case, the recovered table will have two entries per
1366 * API message. So, if entries i and i+1 match, the message definitions
1367 * are identical. Otherwise, the crc is different, or a message is
1368 * present in only one of the tables.
1369 */
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001370 vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1371 vec_validate_init_empty (dashes, 60, '-');
1372 vec_terminate_c_string (dashes);
1373 vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1374 vec_free (dashes);
Florin Corase86a8ed2018-01-05 03:20:25 -08001375 for (i = 0; i < vec_len (table);)
1376 {
1377 /* Last message lonely? */
1378 if (i == vec_len (table) - 1)
1379 {
1380 ndifferences++;
1381 goto last_unique;
1382 }
1383
1384 /* Identical pair? */
1385 if (!strncmp
1386 ((char *) table[i].name_and_crc,
1387 (char *) table[i + 1].name_and_crc,
1388 vec_len (table[i].name_and_crc)))
1389 {
1390 i += 2;
1391 continue;
1392 }
1393
1394 ndifferences++;
1395
1396 /* Only in one of two tables? */
Andrew Yourtchenkoae605b82019-01-21 16:39:33 +01001397 if (i + 1 == vec_len (table)
1398 || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
Florin Corase86a8ed2018-01-05 03:20:25 -08001399 {
1400 last_unique:
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001401 vlib_cli_output (vm, "%-60s | only in %s",
Florin Corase86a8ed2018-01-05 03:20:25 -08001402 table[i].name, table[i].which ?
1403 "image" : "file");
1404 i++;
1405 continue;
1406 }
1407 /* In both tables, but with different signatures */
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001408 vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
Florin Corase86a8ed2018-01-05 03:20:25 -08001409 i += 2;
1410 }
1411 if (ndifferences == 0)
1412 vlib_cli_output (vm, "No api message signature differences found.");
1413 else
Andrew Yourtchenko05f7ca12019-01-21 16:28:48 +01001414 vlib_cli_output (vm, "\nFound %u api message signature differences",
Florin Corase86a8ed2018-01-05 03:20:25 -08001415 ndifferences);
1416 goto cleanup;
1417 }
1418
1419 /* Dump the table, sorted as shown above */
1420 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1421
1422 for (i = 0; i < vec_len (table); i++)
1423 {
1424 item = table + i;
1425 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1426 item->msg_index, item->crc);
1427 }
1428
1429cleanup:
1430 for (i = 0; i < vec_len (table); i++)
1431 {
1432 vec_free (table[i].name_and_crc);
1433 vec_free (table[i].name);
1434 vec_free (table[i].crc);
1435 }
1436
1437 vec_free (table);
1438
1439 return 0;
1440}
1441
1442/*?
1443 * Displays a serialized API message decode table, sorted by message name
1444 *
1445 * @cliexpar
1446 * @cliexstart{show api dump file <filename>}
1447 * Message name MsgID CRC
1448 * accept_session 407 8e2a127e
1449 * accept_session_reply 408 67d8c22a
1450 * add_node_next 549 e4202993
1451 * add_node_next_reply 550 e89d6eed
1452 * etc.
1453 * @cliexend
1454?*/
1455
1456/*?
1457 * Compares a serialized API message decode table with the current image
1458 *
1459 * @cliexpar
1460 * @cliexstart{show api dump file <filename> compare}
1461 * ip_add_del_route definition changed
1462 * ip_table_add_del definition changed
1463 * l2_macs_event only in image
1464 * vnet_ip4_fib_counters only in file
1465 * vnet_ip4_nbr_counters only in file
1466 * @cliexend
1467?*/
1468
1469/*?
1470 * Display a serialized API message decode table, compare a saved
1471 * decode table with the current image, to establish API differences.
1472 *
1473?*/
Florin Corase86a8ed2018-01-05 03:20:25 -08001474VLIB_CLI_COMMAND (dump_api_table_file, static) =
1475{
1476 .path = "show api dump",
1477 .short_help = "show api dump file <filename> [numeric | compare-current]",
1478 .function = dump_api_table_file_command_fn,
1479};
1480
Florin Corase86a8ed2018-01-05 03:20:25 -08001481/*
1482 * fd.io coding-style-patch-verification: ON
1483 *
1484 * Local Variables:
1485 * eval: (c-set-style "gnu")
1486 * End:
1487 */