Line data Source code
1 : /*
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 :
26 : static clib_error_t *
27 0 : vl_api_show_histogram_command (vlib_main_t * vm,
28 : unformat_input_t * input,
29 : vlib_cli_command_t * cli_cmd)
30 : {
31 0 : u64 total_counts = 0;
32 : int i;
33 :
34 0 : for (i = 0; i < SLEEP_N_BUCKETS; i++)
35 : {
36 0 : total_counts += vector_rate_histogram[i];
37 : }
38 :
39 0 : if (total_counts == 0)
40 : {
41 0 : vlib_cli_output (vm, "No control-plane activity.");
42 0 : 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 0 : foreach_histogram_bucket;
56 : #undef _
57 :
58 0 : return 0;
59 : }
60 :
61 : /*?
62 : * Display the binary api sleep-time histogram
63 : ?*/
64 : /* *INDENT-OFF* */
65 272887 : VLIB_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 :
73 : static clib_error_t *
74 0 : vl_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 0 : for (i = 0; i < SLEEP_N_BUCKETS; i++)
81 0 : vector_rate_histogram[i] = 0;
82 0 : return 0;
83 : }
84 :
85 : /*?
86 : * Clear the binary api sleep-time histogram
87 : ?*/
88 : /* *INDENT-OFF* */
89 272887 : VLIB_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 :
97 : static clib_error_t *
98 0 : vl_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;
104 0 : api_main_t *am = vlibapi_get_main ();
105 0 : u32 *confused_indices = 0;
106 :
107 0 : if (!pool_elts (am->vl_clients))
108 0 : goto socket_clients;
109 0 : vlib_cli_output (vm, "Shared memory clients");
110 0 : vlib_cli_output (vm, "%20s %8s %14s %18s %s",
111 : "Name", "PID", "Queue Length", "Queue VA", "Health");
112 :
113 : /* *INDENT-OFF* */
114 0 : pool_foreach (regpp, am->vl_clients)
115 : {
116 0 : regp = *regpp;
117 :
118 0 : if (regp)
119 : {
120 0 : if (regp->unanswered_pings > 0)
121 0 : health = "questionable";
122 : else
123 0 : health = "OK";
124 :
125 0 : q = regp->vl_input_queue;
126 :
127 0 : 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 0 : clib_warning ("NULL client registration index %d",
134 : regpp - am->vl_clients);
135 0 : vec_add1 (confused_indices, regpp - am->vl_clients);
136 : }
137 : }
138 : /* *INDENT-ON* */
139 :
140 : /* This should "never happen," but if it does, fix it... */
141 0 : if (PREDICT_FALSE (vec_len (confused_indices) > 0))
142 : {
143 : int i;
144 0 : for (i = 0; i < vec_len (confused_indices); i++)
145 : {
146 0 : pool_put_index (am->vl_clients, confused_indices[i]);
147 : }
148 : }
149 0 : vec_free (confused_indices);
150 :
151 0 : if (am->missing_clients)
152 0 : vlib_cli_output (vm, "%u messages with missing clients",
153 : am->missing_clients);
154 0 : socket_clients:
155 0 : vl_sock_api_dump_clients (vm, am);
156 :
157 0 : return 0;
158 : }
159 :
160 : static clib_error_t *
161 0 : vl_api_status_command (vlib_main_t * vm,
162 : unformat_input_t * input, vlib_cli_command_t * cli_cmd)
163 : {
164 0 : api_main_t *am = vlibapi_get_main ();
165 :
166 : /* check if rx_trace and tx_trace are not null pointers */
167 0 : if (am->rx_trace == 0)
168 : {
169 0 : vlib_cli_output (vm, "RX Trace disabled\n");
170 : }
171 : else
172 : {
173 0 : if (am->rx_trace->enabled == 0)
174 0 : vlib_cli_output (vm, "RX Trace disabled\n");
175 : else
176 0 : vlib_cli_output (vm, "RX Trace enabled\n");
177 : }
178 :
179 0 : if (am->tx_trace == 0)
180 : {
181 0 : vlib_cli_output (vm, "TX Trace disabled\n");
182 : }
183 : else
184 : {
185 0 : if (am->tx_trace->enabled == 0)
186 0 : vlib_cli_output (vm, "TX Trace disabled\n");
187 : else
188 0 : vlib_cli_output (vm, "TX Trace enabled\n");
189 : }
190 :
191 0 : return 0;
192 : }
193 :
194 : /* *INDENT-OFF* */
195 272887 : VLIB_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* */
206 272887 : VLIB_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* */
218 272887 : VLIB_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 :
226 : static clib_error_t *
227 0 : vl_api_message_table_command (vlib_main_t * vm,
228 : unformat_input_t * input,
229 : vlib_cli_command_t * cli_cmd)
230 : {
231 0 : api_main_t *am = vlibapi_get_main ();
232 : int i;
233 0 : int verbose = 0;
234 :
235 0 : if (unformat (input, "verbose"))
236 0 : verbose = 1;
237 :
238 :
239 0 : if (verbose == 0)
240 0 : vlib_cli_output (vm, "%-4s %s", "ID", "Name");
241 : else
242 0 : vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
243 : "MP-safe");
244 :
245 0 : for (i = 1; i < vec_len (am->msg_data); i++)
246 : {
247 0 : vl_api_msg_data_t *m = vl_api_get_msg_data (am, i);
248 0 : if (verbose == 0)
249 : {
250 0 : vlib_cli_output (vm, "%-4d %s", i,
251 0 : m->name ? m->name : " [no handler]");
252 : }
253 : else
254 : {
255 0 : vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
256 0 : m->name ? m->name : " [no handler]", m->bounce,
257 0 : m->is_mp_safe);
258 : }
259 : }
260 :
261 0 : return 0;
262 : }
263 :
264 : /*?
265 : * Display the current api message decode tables
266 : ?*/
267 : /* *INDENT-OFF* */
268 272887 : VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
269 : {
270 : .path = "show api message-table",
271 : .short_help = "Message Table",
272 : .function = vl_api_message_table_command,
273 : };
274 : /* *INDENT-ON* */
275 :
276 : static int
277 0 : range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
278 : {
279 : int len0, len1, clen;
280 :
281 0 : len0 = vec_len (a0->name);
282 0 : len1 = vec_len (a1->name);
283 0 : clen = len0 < len1 ? len0 : len1;
284 0 : return (strncmp ((char *) a0->name, (char *) a1->name, clen));
285 : }
286 :
287 : static u8 *
288 0 : format_api_msg_range (u8 * s, va_list * args)
289 : {
290 0 : vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
291 :
292 0 : if (rp == 0)
293 0 : s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
294 : else
295 0 : s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
296 0 : rp->last_msg_id);
297 :
298 0 : return s;
299 : }
300 :
301 : static clib_error_t *
302 0 : vl_api_show_plugin_command (vlib_main_t * vm,
303 : unformat_input_t * input,
304 : vlib_cli_command_t * cli_cmd)
305 : {
306 0 : api_main_t *am = vlibapi_get_main ();
307 0 : vl_api_msg_range_t *rp = 0;
308 : int i;
309 :
310 0 : if (vec_len (am->msg_ranges) == 0)
311 : {
312 0 : vlib_cli_output (vm, "No plugin API message ranges configured...");
313 0 : return 0;
314 : }
315 :
316 0 : rp = vec_dup (am->msg_ranges);
317 :
318 0 : vec_sort_with_function (rp, range_compare);
319 :
320 0 : vlib_cli_output (vm, "Plugin API message ID ranges...\n");
321 0 : vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
322 :
323 0 : for (i = 0; i < vec_len (rp); i++)
324 0 : vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
325 :
326 0 : vec_free (rp);
327 :
328 0 : return 0;
329 : }
330 :
331 : /*?
332 : * Display the plugin binary API message range table
333 : ?*/
334 : /* *INDENT-OFF* */
335 272887 : VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
336 : {
337 : .path = "show api plugin",
338 : .short_help = "show api plugin",
339 : .function = vl_api_show_plugin_command,
340 : };
341 : /* *INDENT-ON* */
342 :
343 : typedef enum
344 : {
345 : DUMP,
346 : DUMP_JSON,
347 : REPLAY,
348 : INITIALIZERS,
349 : } vl_api_replay_t;
350 :
351 : u8 *
352 0 : format_vl_msg_api_trace_status (u8 * s, va_list * args)
353 : {
354 0 : api_main_t *am = va_arg (*args, api_main_t *);
355 0 : vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
356 : vl_api_trace_t *tp;
357 : char *trace_name;
358 :
359 0 : switch (which)
360 : {
361 0 : case VL_API_TRACE_TX:
362 0 : tp = am->tx_trace;
363 0 : trace_name = "TX trace";
364 0 : break;
365 :
366 0 : case VL_API_TRACE_RX:
367 0 : tp = am->rx_trace;
368 0 : trace_name = "RX trace";
369 0 : break;
370 :
371 0 : default:
372 0 : abort ();
373 : }
374 :
375 0 : if (tp == 0)
376 : {
377 0 : s = format (s, "%s: not yet configured.\n", trace_name);
378 0 : return s;
379 : }
380 :
381 0 : s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
382 0 : trace_name, vec_len (tp->traces), tp->nitems,
383 0 : tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
384 0 : return s;
385 : }
386 :
387 : static void
388 0 : vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
389 : u32 first_index, u32 last_index,
390 : vl_api_replay_t which)
391 : {
392 : vl_api_trace_file_header_t *hp;
393 : int i, fd;
394 0 : u16 *msgid_vec = 0;
395 : struct stat statb;
396 : size_t file_size;
397 : u8 *msg;
398 0 : api_main_t *am = vlibapi_get_main ();
399 0 : u8 *tmpbuf = 0;
400 : u32 nitems, nitems_msgtbl;
401 :
402 0 : fd = open ((char *) filename, O_RDONLY);
403 :
404 0 : if (fd < 0)
405 : {
406 0 : vlib_cli_output (vm, "Couldn't open %s\n", filename);
407 0 : return;
408 : }
409 :
410 0 : if (fstat (fd, &statb) < 0)
411 : {
412 0 : vlib_cli_output (vm, "Couldn't stat %s\n", filename);
413 0 : close (fd);
414 0 : return;
415 : }
416 :
417 0 : if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
418 : {
419 0 : vlib_cli_output (vm, "File not plausible: %s\n", filename);
420 0 : close (fd);
421 0 : return;
422 : }
423 :
424 0 : file_size = statb.st_size;
425 0 : file_size = (file_size + 4095) & ~(4095);
426 :
427 0 : hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
428 :
429 0 : if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
430 : {
431 0 : vlib_cli_output (vm, "mmap failed: %s\n", filename);
432 0 : close (fd);
433 0 : return;
434 : }
435 0 : close (fd);
436 :
437 0 : clib_mem_unpoison (hp, file_size);
438 :
439 0 : nitems = ntohl (hp->nitems);
440 :
441 0 : if (last_index == (u32) ~ 0)
442 : {
443 0 : last_index = nitems - 1;
444 : }
445 :
446 0 : if (first_index >= nitems || last_index >= nitems)
447 : {
448 0 : vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
449 : first_index, last_index, nitems - 1);
450 0 : munmap (hp, file_size);
451 0 : return;
452 : }
453 0 : if (hp->wrapped)
454 0 : vlib_cli_output (vm,
455 : "Note: wrapped/incomplete trace, results may vary\n");
456 :
457 0 : size_t file_size_left = file_size;
458 :
459 : #define assert_size(size_left, s) \
460 : do \
461 : { \
462 : if ((s) >= size_left) \
463 : { \
464 : vlib_cli_output (vm, "corrupted file"); \
465 : munmap (hp, file_size); \
466 : vec_free (msgid_vec); \
467 : return; \
468 : } \
469 : size_left -= s; \
470 : } \
471 : while (0);
472 :
473 0 : assert_size (file_size_left, sizeof (hp[0]));
474 0 : msg = (u8 *) (hp + 1);
475 :
476 0 : serialize_main_t _sm, *sm = &_sm;
477 0 : u32 msgtbl_size = ntohl (hp->msgtbl_size);
478 : u8 *name_and_crc;
479 :
480 0 : assert_size (file_size_left, msgtbl_size);
481 :
482 0 : unserialize_open_data (sm, msg, msgtbl_size);
483 0 : unserialize_integer (sm, &nitems_msgtbl, sizeof (u32));
484 :
485 0 : for (i = 0; i < nitems_msgtbl; i++)
486 : {
487 0 : u16 msg_index = unserialize_likely_small_unsigned_integer (sm);
488 0 : unserialize_cstring (sm, (char **) &name_and_crc);
489 0 : u32 msg_index2 = vl_msg_api_get_msg_index (name_and_crc);
490 0 : ASSERT (~0 == msg_index2 || msg_index2 <= 65535);
491 0 : if (~0 == msg_index2)
492 0 : vlib_cli_output (vm, "warning: can't find msg index for id %d\n",
493 : msg_index);
494 0 : vec_validate (msgid_vec, msg_index);
495 0 : msgid_vec[msg_index] = msg_index2;
496 : }
497 :
498 0 : msg += msgtbl_size;
499 :
500 0 : for (i = 0; i < first_index; i++)
501 : {
502 : int size;
503 : u16 msg_id;
504 :
505 0 : assert_size (file_size_left, sizeof (u32));
506 0 : size = clib_host_to_net_u32 (*(u32 *) msg);
507 0 : msg += sizeof (u32);
508 :
509 0 : assert_size (file_size_left, clib_max (size, sizeof (u16)));
510 0 : msg_id = ntohs (*((u16 *) msg));
511 0 : if (msg_id >= vec_len (msgid_vec) ||
512 0 : msgid_vec[msg_id] >= vec_len (am->msg_data))
513 0 : vlib_cli_output (vm, "warning: unknown msg id %d for msg number %d\n",
514 : msg_id, i);
515 :
516 0 : msg += size;
517 : }
518 :
519 0 : if (which == REPLAY)
520 0 : am->replay_in_progress = 1;
521 :
522 0 : for (; i <= last_index; i++)
523 : {
524 : vl_api_msg_data_t *m;
525 : u16 msg_id;
526 : int size;
527 :
528 0 : if (which == DUMP)
529 0 : vlib_cli_output (vm, "---------- trace %d -----------\n", i);
530 :
531 0 : assert_size (file_size_left, sizeof (u32));
532 0 : size = clib_host_to_net_u32 (*(u32 *) msg);
533 0 : msg += sizeof (u32);
534 :
535 0 : assert_size (file_size_left, clib_max (size, sizeof (u16)));
536 0 : msg_id = ntohs (*((u16 *) msg));
537 :
538 0 : if (msg_id >= vec_len (msgid_vec) ||
539 0 : msgid_vec[msg_id] >= vec_len (am->msg_data))
540 : {
541 0 : vlib_cli_output (
542 : vm, "warning: unknown msg id %d for msg number %d, skipping\n",
543 : msg_id, i);
544 0 : msg += size;
545 0 : continue;
546 : }
547 :
548 0 : msg_id = msgid_vec[msg_id];
549 0 : m = vl_api_get_msg_data (am, msg_id);
550 :
551 : /* Copy the buffer (from the read-only mmap'ed file) */
552 0 : vec_validate (tmpbuf, size - 1 + sizeof (uword));
553 0 : clib_memcpy (tmpbuf + sizeof (uword), msg, size);
554 0 : clib_memset (tmpbuf, 0xf, sizeof (uword));
555 :
556 : /*
557 : * Endian swap if needed. All msg data is supposed to be in
558 : * network byte order.
559 : */
560 0 : if (((which == DUMP || which == DUMP_JSON) &&
561 : clib_arch_is_little_endian))
562 : {
563 0 : if (m && m->endian_handler == 0)
564 : {
565 0 : vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
566 0 : munmap (hp, file_size);
567 0 : vec_free (tmpbuf);
568 0 : am->replay_in_progress = 0;
569 0 : return;
570 : }
571 0 : if (m)
572 : {
573 0 : m->endian_handler (tmpbuf + sizeof (uword));
574 : }
575 : }
576 :
577 : /* msg_id always in network byte order */
578 : if (clib_arch_is_little_endian)
579 : {
580 0 : u16 *msg_idp = (u16 *) (tmpbuf + sizeof (uword));
581 0 : *msg_idp = msg_id;
582 : }
583 :
584 0 : switch (which)
585 : {
586 0 : case DUMP_JSON:
587 0 : vlib_cli_output (vm, "%U", format_vl_api_msg_json, am, msg_id,
588 : tmpbuf + sizeof (uword));
589 0 : break;
590 :
591 0 : case DUMP:
592 0 : vlib_cli_output (vm, "%U", format_vl_api_msg_text, am, msg_id,
593 : tmpbuf + sizeof (uword));
594 0 : break;
595 :
596 0 : case INITIALIZERS:
597 0 : if (m)
598 : {
599 : u8 *s;
600 : int j;
601 :
602 0 : vlib_cli_output (vm, "/*%U*/", format_vl_api_msg_text, am,
603 : msg_id, tmpbuf + sizeof (uword));
604 :
605 0 : vlib_cli_output (vm, "*/\n");
606 :
607 0 : s = format (0, "static u8 * vl_api_%s_%d[%d] = {", m->name, i,
608 : m->trace_size);
609 :
610 0 : for (j = 0; j < m->trace_size; j++)
611 : {
612 0 : if ((j & 7) == 0)
613 0 : s = format (s, "\n ");
614 0 : s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
615 : }
616 0 : s = format (s, "\n};\n%c", 0);
617 0 : vlib_cli_output (vm, (char *) s);
618 0 : vec_free (s);
619 : }
620 0 : break;
621 :
622 0 : case REPLAY:
623 0 : if (m && m->handler && m->replay_allowed)
624 : {
625 0 : if (!m->is_mp_safe)
626 0 : vl_msg_api_barrier_sync ();
627 0 : m->handler (tmpbuf + sizeof (uword));
628 0 : if (!m->is_mp_safe)
629 0 : vl_msg_api_barrier_release ();
630 : }
631 : else
632 : {
633 0 : if (m && m->replay_allowed)
634 0 : vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
635 : msg_id);
636 0 : break;
637 : }
638 0 : break;
639 : }
640 :
641 0 : vec_set_len (tmpbuf, 0);
642 0 : msg += size;
643 : }
644 :
645 0 : munmap (hp, file_size);
646 0 : vec_free (tmpbuf);
647 0 : vec_free (msgid_vec);
648 0 : am->replay_in_progress = 0;
649 : }
650 :
651 : static int
652 1576 : file_exists (u8 *fname)
653 : {
654 1576 : FILE *fp = 0;
655 1576 : fp = fopen ((char *) fname, "r");
656 1576 : if (fp)
657 : {
658 0 : fclose (fp);
659 0 : return 1;
660 : }
661 1576 : return 0;
662 : }
663 :
664 : typedef struct
665 : {
666 : vlib_main_t *vm;
667 : u8 is_json;
668 : } vl_msg_print_args;
669 :
670 : static int
671 0 : vl_msg_print_trace (u8 *msg, void *ctx)
672 : {
673 0 : vl_msg_print_args *a = ctx;
674 0 : api_main_t *am = vlibapi_get_main ();
675 0 : u16 msg_id = ntohs (*((u16 *) msg));
676 0 : vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
677 0 : u8 is_json = a->is_json;
678 0 : u8 *tmpbuf = 0;
679 :
680 0 : if (!m)
681 : {
682 0 : vlib_cli_output (a->vm, "Unknown msg id %d\n", msg_id);
683 0 : return 0;
684 : }
685 :
686 0 : if (clib_arch_is_little_endian && (m->endian_handler != NULL))
687 : {
688 0 : u32 msg_length = vec_len (msg);
689 0 : vec_validate (tmpbuf, msg_length - 1);
690 0 : clib_memcpy_fast (tmpbuf, msg, msg_length);
691 0 : msg = tmpbuf;
692 :
693 0 : m->endian_handler (tmpbuf);
694 : }
695 :
696 0 : vlib_cli_output (a->vm, "%U\n",
697 : is_json ? format_vl_api_msg_json : format_vl_api_msg_text,
698 : am, msg_id, msg);
699 :
700 0 : vec_free (tmpbuf);
701 0 : return 0;
702 : }
703 :
704 : static int
705 0 : vl_msg_api_dump_trace (vlib_main_t *vm, vl_api_trace_which_t which, u8 is_json)
706 : {
707 0 : api_main_t *am = vlibapi_get_main ();
708 : vl_api_trace_t *tp;
709 :
710 0 : switch (which)
711 : {
712 0 : case VL_API_TRACE_TX:
713 0 : tp = am->tx_trace;
714 0 : break;
715 0 : case VL_API_TRACE_RX:
716 0 : tp = am->rx_trace;
717 0 : break;
718 0 : default:
719 0 : return -1;
720 : }
721 :
722 0 : if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
723 0 : return -1;
724 :
725 : vl_msg_print_args args;
726 0 : clib_memset (&args, 0, sizeof (args));
727 0 : args.is_json = is_json;
728 0 : args.vm = vm;
729 0 : vl_msg_traverse_trace (tp, vl_msg_print_trace, &args);
730 :
731 0 : return 0;
732 : }
733 :
734 : static char *
735 1 : vl_msg_read_file (FILE *f)
736 1 : {
737 1 : const size_t bufsize = 1024;
738 1 : char *buf[bufsize], *v = 0;
739 : size_t n;
740 :
741 2 : while ((n = fread (buf, 1, bufsize, f)))
742 1 : vec_add (v, buf, n);
743 :
744 : /* most callers expect a NULL-terminated C-string */
745 1 : if (v)
746 1 : vec_add1 (v, 0);
747 :
748 1 : return v;
749 : }
750 :
751 : static u16
752 1 : vl_msg_find_id_by_name_and_crc (vlib_main_t *vm, api_main_t *am, char *name)
753 : {
754 : uword *p;
755 1 : p = hash_get_mem (am->msg_index_by_name_and_crc, name);
756 1 : if (!p)
757 0 : return (u16) ~0;
758 :
759 1 : return p[0];
760 : }
761 :
762 : static u16
763 0 : vl_msg_find_id_by_name (vlib_main_t *vm, api_main_t *am, char *name)
764 : {
765 : uword *p;
766 :
767 0 : if (!am->msg_id_by_name)
768 : {
769 0 : vlib_cli_output (vm, "message id table not yet initialized!\n");
770 0 : return (u16) ~0;
771 : }
772 :
773 0 : p = hash_get_mem (am->msg_id_by_name, name);
774 0 : if (!p)
775 0 : return (u16) ~0;
776 :
777 0 : return p[0];
778 : }
779 :
780 : static int
781 1 : vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o)
782 : {
783 1 : api_main_t *am = vlibapi_get_main ();
784 : u16 msg_id;
785 1 : int len = 0, rv = -1;
786 : vl_api_msg_data_t *m;
787 1 : u8 *msg = 0;
788 :
789 1 : cJSON *msg_id_obj = cJSON_GetObjectItem (o, "_msgname");
790 1 : if (!msg_id_obj)
791 : {
792 0 : vlib_cli_output (vm, "Missing '_msgname' element!\n");
793 0 : return rv;
794 : }
795 1 : char *name = cJSON_GetStringValue (msg_id_obj);
796 :
797 1 : cJSON *crc_obj = cJSON_GetObjectItem (o, "_crc");
798 1 : if (!crc_obj)
799 : {
800 0 : vlib_cli_output (vm, "Missing '_crc' element!\n");
801 0 : return rv;
802 : }
803 1 : char *crc = cJSON_GetStringValue (crc_obj);
804 1 : u8 proc_warning = 0;
805 :
806 1 : u8 *name_crc = format (0, "%s_%s%c", name, crc, 0);
807 1 : msg_id = vl_msg_find_id_by_name_and_crc (vm, am, (char *) name_crc);
808 1 : m = vl_api_get_msg_data (am, msg_id);
809 1 : if (msg_id == (u16) ~0)
810 : {
811 0 : msg_id = vl_msg_find_id_by_name (vm, am, name);
812 0 : if (msg_id == (u16) ~0)
813 : {
814 0 : vlib_cli_output (vm, "unknown msg id %d!\n", msg_id);
815 0 : vec_free (name_crc);
816 0 : return rv;
817 : }
818 0 : proc_warning = 1;
819 : }
820 1 : vec_free (name_crc);
821 :
822 1 : if (m->replay_allowed)
823 : {
824 1 : if (proc_warning)
825 0 : vlib_cli_output (vm, "warning: msg %d has different signature\n");
826 :
827 1 : if (!m->fromjson_handler)
828 : {
829 0 : vlib_cli_output (vm, "missing fromjson convert function! id %d\n",
830 : msg_id);
831 0 : return rv;
832 : }
833 :
834 1 : msg = (u8 *) m->fromjson_handler (o, &len);
835 1 : if (!msg)
836 : {
837 0 : vlib_cli_output (vm, "failed to convert JSON (msg id %d)!\n",
838 : msg_id);
839 0 : return rv;
840 : }
841 :
842 : if (clib_arch_is_little_endian)
843 1 : m->endian_handler (msg);
844 :
845 1 : if (!m->handler)
846 : {
847 0 : vlib_cli_output (vm, "no handler for msg id %d!\n", msg_id);
848 0 : goto end;
849 : }
850 :
851 1 : if (m->handler)
852 : {
853 1 : if (!m->is_mp_safe)
854 1 : vl_msg_api_barrier_sync ();
855 1 : m->handler (msg);
856 1 : if (!m->is_mp_safe)
857 1 : vl_msg_api_barrier_release ();
858 : }
859 : }
860 :
861 1 : rv = 0;
862 1 : end:
863 1 : if (msg)
864 1 : cJSON_free (msg);
865 1 : return rv;
866 : }
867 :
868 : static void
869 1 : vl_msg_replay_json (vlib_main_t *vm, u8 *filename)
870 : {
871 1 : api_main_t *am = vlibapi_get_main ();
872 1 : cJSON *o = 0;
873 1 : int rv = 0;
874 1 : FILE *f = fopen ((char *) filename, "r");
875 :
876 1 : if (!f)
877 : {
878 0 : vlib_cli_output (vm, "failed to open %s!\n", filename);
879 0 : return;
880 : }
881 :
882 1 : char *buf = vl_msg_read_file (f);
883 1 : fclose (f);
884 :
885 1 : o = cJSON_Parse (buf);
886 1 : vec_free (buf);
887 1 : if (!o)
888 : {
889 0 : vlib_cli_output (vm, "%s: Failed parsing JSON input: %s\n", filename,
890 : cJSON_GetErrorPtr ());
891 0 : return;
892 : }
893 :
894 1 : if (cJSON_IsArray (o))
895 : {
896 1 : am->replay_in_progress = 1;
897 1 : size_t size = cJSON_GetArraySize (o);
898 2 : for (int i = 0; i < size; i++)
899 : {
900 1 : rv = vl_msg_exec_json_command (vm, cJSON_GetArrayItem (o, i));
901 1 : if (rv < 0)
902 : {
903 0 : am->replay_in_progress = 0;
904 0 : break;
905 : }
906 : }
907 : }
908 : else
909 : {
910 0 : rv = vl_msg_exec_json_command (vm, o);
911 : }
912 :
913 1 : if (rv < 0)
914 0 : vlib_cli_output (vm, "error during replaying API trace");
915 :
916 1 : cJSON_Delete (o);
917 : }
918 :
919 : static void
920 0 : vl_msg_dump_file_json (vlib_main_t *vm, u8 *filename)
921 : {
922 0 : FILE *f = fopen ((char *) filename, "r");
923 : char *buf;
924 :
925 0 : if (!f)
926 : {
927 0 : vlib_cli_output (vm, "failed to open %s!\n", filename);
928 0 : return;
929 : }
930 :
931 0 : buf = vl_msg_read_file (f);
932 0 : fclose (f);
933 :
934 0 : if (!buf)
935 : {
936 0 : vlib_cli_output (vm, "no content in %s!\n", filename);
937 0 : return;
938 : }
939 :
940 0 : vlib_cli_output (vm, buf);
941 0 : vec_free (buf);
942 : }
943 :
944 : /** api_trace_command_fn - control the binary API trace / replay feature
945 :
946 : Note: this command MUST be marked thread-safe. Replay with
947 : multiple worker threads depends in many cases on worker thread
948 : graph replica maintenance. If we (implicitly) assert a worker
949 : thread barrier at the debug CLI level, all graph replica changes
950 : are deferred until the replay operation completes. If an interface
951 : is deleted, the wheels fall off.
952 : */
953 :
954 : static clib_error_t *
955 1583 : api_trace_command_fn (vlib_main_t * vm,
956 : unformat_input_t * input, vlib_cli_command_t * cmd)
957 : {
958 1583 : unformat_input_t _line_input, *line_input = &_line_input;
959 1583 : u32 nitems = 256 << 10;
960 1583 : api_main_t *am = vlibapi_get_main ();
961 1583 : vl_api_trace_which_t which = VL_API_TRACE_RX;
962 1583 : u8 *filename = 0;
963 1583 : u8 *chroot_filename = 0;
964 1583 : u32 first = 0;
965 1583 : u32 last = (u32) ~ 0;
966 : FILE *fp;
967 : int rv;
968 :
969 : /* Get a line of input. */
970 1583 : if (!unformat_user (input, unformat_line_input, line_input))
971 0 : return 0;
972 :
973 1593 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
974 : {
975 1585 : if (unformat (line_input, "on") || unformat (line_input, "enable"))
976 : {
977 4 : if (unformat (line_input, "nitems %d", &nitems))
978 : ;
979 4 : vlib_worker_thread_barrier_sync (vm);
980 4 : vl_msg_api_trace_configure (am, which, nitems);
981 4 : vl_msg_api_trace_onoff (am, which, 1 /* on */ );
982 4 : vlib_worker_thread_barrier_release (vm);
983 : }
984 1581 : else if (unformat (line_input, "off"))
985 : {
986 0 : vlib_worker_thread_barrier_sync (vm);
987 0 : vl_msg_api_trace_onoff (am, which, 0);
988 0 : vlib_worker_thread_barrier_release (vm);
989 : }
990 1581 : else if (unformat (line_input, "save-json %s", &filename))
991 : {
992 1 : if (strstr ((char *) filename, "..") ||
993 1 : index ((char *) filename, '/'))
994 : {
995 0 : vlib_cli_output (vm, "illegal characters in filename '%s'",
996 : filename);
997 0 : goto out;
998 : }
999 :
1000 1 : chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1001 :
1002 1 : vec_free (filename);
1003 :
1004 1 : if (file_exists (chroot_filename))
1005 : {
1006 0 : vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1007 0 : goto out;
1008 : }
1009 :
1010 1 : fp = fopen ((char *) chroot_filename, "w");
1011 1 : if (fp == NULL)
1012 : {
1013 0 : vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1014 0 : goto out;
1015 : }
1016 1 : vlib_worker_thread_barrier_sync (vm);
1017 1 : rv = vl_msg_api_trace_save (am, which, fp, 1);
1018 1 : if (rv == -1)
1019 0 : vlib_cli_output (vm, "API Trace data not present\n");
1020 1 : else if (rv < 0)
1021 0 : vlib_cli_output (vm, "failed to save api trace\n");
1022 : else
1023 1 : vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1024 1 : vlib_worker_thread_barrier_release (vm);
1025 1 : fclose (fp);
1026 : }
1027 1580 : else if (unformat (line_input, "save %s", &filename))
1028 : {
1029 1575 : if (strstr ((char *) filename, "..")
1030 1575 : || index ((char *) filename, '/'))
1031 : {
1032 0 : vlib_cli_output (vm, "illegal characters in filename '%s'",
1033 : filename);
1034 0 : goto out;
1035 : }
1036 :
1037 1575 : chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1038 :
1039 1575 : vec_free (filename);
1040 :
1041 1575 : if (file_exists (chroot_filename))
1042 : {
1043 0 : vlib_cli_output (vm, "file exists: %s\n", chroot_filename);
1044 0 : goto out;
1045 : }
1046 :
1047 1575 : fp = fopen ((char *) chroot_filename, "w");
1048 1575 : if (fp == NULL)
1049 : {
1050 0 : vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1051 0 : goto out;
1052 : }
1053 1575 : vlib_worker_thread_barrier_sync (vm);
1054 1575 : rv = vl_msg_api_trace_save (am, which, fp, 0);
1055 1575 : vlib_worker_thread_barrier_release (vm);
1056 1575 : fclose (fp);
1057 1575 : if (rv == -1)
1058 0 : vlib_cli_output (vm, "API Trace data not present\n");
1059 1575 : else if (rv == -2)
1060 0 : vlib_cli_output (vm, "File for writing is closed\n");
1061 1575 : else if (rv == -10)
1062 0 : vlib_cli_output (vm, "Error while writing header to file\n");
1063 1575 : else if (rv == -11)
1064 0 : vlib_cli_output (vm, "Error while writing trace to file\n");
1065 1575 : else if (rv == -12)
1066 0 : vlib_cli_output (vm,
1067 : "Error while writing end of buffer trace to file\n");
1068 1575 : else if (rv == -13)
1069 0 : vlib_cli_output (vm,
1070 : "Error while writing start of buffer trace to file\n");
1071 1575 : else if (rv < 0)
1072 0 : vlib_cli_output (vm, "Unknown error while saving: %d", rv);
1073 : else
1074 1575 : vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1075 1575 : goto out;
1076 : }
1077 5 : else if (unformat (line_input, "tojson %s", &filename))
1078 : {
1079 0 : vl_msg_api_process_file (vm, filename, first, last, DUMP_JSON);
1080 : }
1081 5 : else if (unformat (line_input, "dump-file-json %s", &filename))
1082 : {
1083 0 : vl_msg_dump_file_json (vm, filename);
1084 : }
1085 5 : else if (unformat (line_input, "dump-file %s", &filename))
1086 : {
1087 0 : vl_msg_api_process_file (vm, filename, first, last, DUMP);
1088 : }
1089 5 : else if (unformat (line_input, "dump-json"))
1090 : {
1091 0 : vl_msg_api_dump_trace (vm, which, 1);
1092 : }
1093 5 : else if (unformat (line_input, "dump"))
1094 : {
1095 0 : vl_msg_api_dump_trace (vm, which, 0);
1096 : }
1097 5 : else if (unformat (line_input, "replay-json %s", &filename))
1098 : {
1099 1 : vl_msg_replay_json (vm, filename);
1100 : }
1101 4 : else if (unformat (line_input, "replay %s", &filename))
1102 : {
1103 0 : vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1104 : }
1105 4 : else if (unformat (line_input, "initializers %s", &filename))
1106 : {
1107 0 : vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1108 : }
1109 4 : else if (unformat (line_input, "tx"))
1110 : {
1111 2 : which = VL_API_TRACE_TX;
1112 : }
1113 2 : else if (unformat (line_input, "first %d", &first))
1114 : {
1115 : ;
1116 : }
1117 2 : else if (unformat (line_input, "last %d", &last))
1118 : {
1119 : ;
1120 : }
1121 2 : else if (unformat (line_input, "status"))
1122 : {
1123 0 : vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1124 : am, which);
1125 : }
1126 2 : else if (unformat (line_input, "free"))
1127 : {
1128 2 : vlib_worker_thread_barrier_sync (vm);
1129 2 : vl_msg_api_trace_onoff (am, which, 0);
1130 2 : vl_msg_api_trace_free (am, which);
1131 2 : vlib_worker_thread_barrier_release (vm);
1132 : }
1133 0 : else if (unformat (line_input, "post-mortem-on"))
1134 0 : vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1135 0 : else if (unformat (line_input, "post-mortem-off"))
1136 0 : vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
1137 : else
1138 0 : return clib_error_return (0, "unknown input `%U'",
1139 : format_unformat_error, input);
1140 : }
1141 8 : out:
1142 1583 : vec_free (filename);
1143 1583 : vec_free (chroot_filename);
1144 1583 : unformat_free (line_input);
1145 1583 : return 0;
1146 : }
1147 :
1148 : /*?
1149 : * Display, replay, or save a binary API trace
1150 : ?*/
1151 :
1152 : /* *INDENT-OFF* */
1153 272887 : VLIB_CLI_COMMAND (api_trace_command, static) = {
1154 : .path = "api trace",
1155 : .short_help = "api trace [tx][on|off][first <n>][last <n>][status][free]"
1156 : "[post-mortem-on][dump|dump-file|dump-json|save|tojson|save-"
1157 : "json|replay <file>|replay-json <file>][nitems <n>]"
1158 : "[initializers <file>]",
1159 : .function = api_trace_command_fn,
1160 : .is_mp_safe = 1,
1161 : };
1162 : /* *INDENT-ON* */
1163 :
1164 : static clib_error_t *
1165 559 : api_trace_config_fn (vlib_main_t * vm, unformat_input_t * input)
1166 : {
1167 559 : u32 nitems = 256 << 10;
1168 559 : vl_api_trace_which_t which = VL_API_TRACE_RX;
1169 559 : api_main_t *am = vlibapi_get_main ();
1170 :
1171 1118 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1172 : {
1173 559 : if (unformat (input, "on") || unformat (input, "enable"))
1174 : {
1175 559 : if (unformat (input, "nitems %d", &nitems))
1176 : ;
1177 559 : vl_msg_api_trace_configure (am, which, nitems);
1178 559 : vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1179 559 : vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
1180 : }
1181 0 : else if (unformat (input, "save-api-table %s",
1182 : &am->save_msg_table_filename))
1183 : ;
1184 : else
1185 0 : return clib_error_return (0, "unknown input `%U'",
1186 : format_unformat_error, input);
1187 : }
1188 559 : return 0;
1189 : }
1190 :
1191 : /*?
1192 : * This module has three configuration parameters:
1193 : * "on" or "enable" - enables binary api tracing
1194 : * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
1195 : * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
1196 : ?*/
1197 7306 : VLIB_CONFIG_FUNCTION (api_trace_config_fn, "api-trace");
1198 :
1199 : static clib_error_t *
1200 559 : api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
1201 : {
1202 559 : api_main_t *am = vlibapi_get_main ();
1203 : u32 nitems;
1204 :
1205 559 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1206 : {
1207 0 : if (unformat (input, "length %d", &nitems) ||
1208 0 : (unformat (input, "len %d", &nitems)))
1209 : {
1210 0 : if (nitems >= 1024)
1211 0 : am->vlib_input_queue_length = nitems;
1212 : else
1213 0 : clib_warning ("vlib input queue length %d too small, ignored",
1214 : nitems);
1215 : }
1216 : else
1217 0 : return clib_error_return (0, "unknown input `%U'",
1218 : format_unformat_error, input);
1219 : }
1220 559 : return 0;
1221 : }
1222 :
1223 7306 : VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
1224 :
1225 : static u8 *
1226 0 : extract_name (u8 * s)
1227 : {
1228 : u8 *rv;
1229 :
1230 0 : rv = vec_dup (s);
1231 :
1232 0 : while (vec_len (rv) && rv[vec_len (rv)] != '_')
1233 0 : vec_dec_len (rv, 1);
1234 :
1235 0 : rv[vec_len (rv)] = 0;
1236 :
1237 0 : return rv;
1238 : }
1239 :
1240 : static u8 *
1241 0 : extract_crc (u8 * s)
1242 : {
1243 : int i;
1244 : u8 *rv;
1245 :
1246 0 : rv = vec_dup (s);
1247 :
1248 0 : for (i = vec_len (rv) - 1; i >= 0; i--)
1249 : {
1250 0 : if (rv[i] == '_')
1251 : {
1252 0 : vec_delete (rv, i + 1, 0);
1253 0 : break;
1254 : }
1255 : }
1256 0 : return rv;
1257 : }
1258 :
1259 : typedef struct
1260 : {
1261 : u8 *name_and_crc;
1262 : u8 *name;
1263 : u8 *crc;
1264 : u32 msg_index;
1265 : int which;
1266 : } msg_table_unserialize_t;
1267 :
1268 : static int
1269 0 : table_id_cmp (void *a1, void *a2)
1270 : {
1271 0 : msg_table_unserialize_t *n1 = a1;
1272 0 : msg_table_unserialize_t *n2 = a2;
1273 :
1274 0 : return (n1->msg_index - n2->msg_index);
1275 : }
1276 :
1277 : static int
1278 0 : table_name_and_crc_cmp (void *a1, void *a2)
1279 : {
1280 0 : msg_table_unserialize_t *n1 = a1;
1281 0 : msg_table_unserialize_t *n2 = a2;
1282 :
1283 0 : return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
1284 : }
1285 :
1286 : static clib_error_t *
1287 0 : dump_api_table_file_command_fn (vlib_main_t * vm,
1288 : unformat_input_t * input,
1289 : vlib_cli_command_t * cmd)
1290 : {
1291 0 : u8 *filename = 0;
1292 0 : api_main_t *am = vlibapi_get_main ();
1293 0 : serialize_main_t _sm, *sm = &_sm;
1294 : clib_error_t *error;
1295 : u32 nmsgs;
1296 : u32 msg_index;
1297 : u8 *name_and_crc;
1298 0 : int compare_current = 0;
1299 0 : int numeric_sort = 0;
1300 0 : msg_table_unserialize_t *table = 0, *item;
1301 : u32 i;
1302 0 : u32 ndifferences = 0;
1303 :
1304 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1305 : {
1306 0 : if (unformat (input, "file %s", &filename))
1307 : ;
1308 0 : else if (unformat (input, "compare-current")
1309 0 : || unformat (input, "compare"))
1310 0 : compare_current = 1;
1311 0 : else if (unformat (input, "numeric"))
1312 0 : numeric_sort = 1;
1313 : else
1314 0 : return clib_error_return (0, "unknown input `%U'",
1315 : format_unformat_error, input);
1316 : }
1317 :
1318 0 : if (numeric_sort && compare_current)
1319 0 : return clib_error_return
1320 : (0, "Comparison and numeric sorting are incompatible");
1321 :
1322 0 : if (filename == 0)
1323 0 : return clib_error_return (0, "File not specified");
1324 :
1325 : /* Load the serialized message table from the table dump */
1326 :
1327 0 : error = unserialize_open_clib_file (sm, (char *) filename);
1328 :
1329 0 : if (error)
1330 0 : return error;
1331 :
1332 0 : unserialize_integer (sm, &nmsgs, sizeof (u32));
1333 :
1334 0 : for (i = 0; i < nmsgs; i++)
1335 : {
1336 0 : msg_index = unserialize_likely_small_unsigned_integer (sm);
1337 0 : unserialize_cstring (sm, (char **) &name_and_crc);
1338 0 : vec_add2 (table, item, 1);
1339 0 : item->msg_index = msg_index;
1340 0 : item->name_and_crc = name_and_crc;
1341 0 : item->name = extract_name (name_and_crc);
1342 0 : item->crc = extract_crc (name_and_crc);
1343 0 : item->which = 0; /* file */
1344 : }
1345 0 : unserialize_close (sm);
1346 :
1347 : /* Compare with the current image? */
1348 0 : if (compare_current)
1349 : {
1350 : /* Append the current message table */
1351 0 : u8 *tblv = vl_api_serialize_message_table (am, 0);
1352 :
1353 0 : serialize_open_vector (sm, tblv);
1354 0 : unserialize_integer (sm, &nmsgs, sizeof (u32));
1355 :
1356 0 : for (i = 0; i < nmsgs; i++)
1357 : {
1358 0 : msg_index = unserialize_likely_small_unsigned_integer (sm);
1359 0 : unserialize_cstring (sm, (char **) &name_and_crc);
1360 :
1361 0 : vec_add2 (table, item, 1);
1362 0 : item->msg_index = msg_index;
1363 0 : item->name_and_crc = name_and_crc;
1364 0 : item->name = extract_name (name_and_crc);
1365 0 : item->crc = extract_crc (name_and_crc);
1366 0 : item->which = 1; /* current_image */
1367 : }
1368 0 : vec_free (tblv);
1369 : }
1370 :
1371 : /* Sort the table. */
1372 0 : if (numeric_sort)
1373 0 : vec_sort_with_function (table, table_id_cmp);
1374 : else
1375 0 : vec_sort_with_function (table, table_name_and_crc_cmp);
1376 :
1377 0 : if (compare_current)
1378 : {
1379 0 : u8 *dashes = 0;
1380 0 : ndifferences = 0;
1381 :
1382 : /*
1383 : * In this case, the recovered table will have two entries per
1384 : * API message. So, if entries i and i+1 match, the message definitions
1385 : * are identical. Otherwise, the crc is different, or a message is
1386 : * present in only one of the tables.
1387 : */
1388 0 : vlib_cli_output (vm, "%-60s | %s", "Message Name", "Result");
1389 0 : vec_validate_init_empty (dashes, 60, '-');
1390 0 : vec_terminate_c_string (dashes);
1391 0 : vlib_cli_output (vm, "%60s-|-%s", dashes, "-----------------");
1392 0 : vec_free (dashes);
1393 0 : for (i = 0; i < vec_len (table);)
1394 : {
1395 : /* Last message lonely? */
1396 0 : if (i == vec_len (table) - 1)
1397 : {
1398 0 : ndifferences++;
1399 0 : goto last_unique;
1400 : }
1401 :
1402 : /* Identical pair? */
1403 0 : if (!strncmp
1404 0 : ((char *) table[i].name_and_crc,
1405 0 : (char *) table[i + 1].name_and_crc,
1406 0 : vec_len (table[i].name_and_crc)))
1407 : {
1408 0 : i += 2;
1409 0 : continue;
1410 : }
1411 :
1412 0 : ndifferences++;
1413 :
1414 : /* Only in one of two tables? */
1415 0 : if (i + 1 == vec_len (table)
1416 0 : || strcmp ((char *) table[i].name, (char *) table[i + 1].name))
1417 : {
1418 0 : last_unique:
1419 0 : vlib_cli_output (vm, "%-60s | only in %s",
1420 0 : table[i].name, table[i].which ?
1421 : "image" : "file");
1422 0 : i++;
1423 0 : continue;
1424 : }
1425 : /* In both tables, but with different signatures */
1426 0 : vlib_cli_output (vm, "%-60s | definition changed", table[i].name);
1427 0 : i += 2;
1428 : }
1429 0 : if (ndifferences == 0)
1430 0 : vlib_cli_output (vm, "No api message signature differences found.");
1431 : else
1432 0 : vlib_cli_output (vm, "\nFound %u api message signature differences",
1433 : ndifferences);
1434 0 : goto cleanup;
1435 : }
1436 :
1437 : /* Dump the table, sorted as shown above */
1438 0 : vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
1439 :
1440 0 : for (i = 0; i < vec_len (table); i++)
1441 : {
1442 0 : item = table + i;
1443 0 : vlib_cli_output (vm, "%-60s %8u %10s", item->name,
1444 0 : item->msg_index, item->crc);
1445 : }
1446 :
1447 0 : cleanup:
1448 0 : for (i = 0; i < vec_len (table); i++)
1449 : {
1450 0 : vec_free (table[i].name_and_crc);
1451 0 : vec_free (table[i].name);
1452 0 : vec_free (table[i].crc);
1453 : }
1454 :
1455 0 : vec_free (table);
1456 :
1457 0 : return 0;
1458 : }
1459 :
1460 : /*?
1461 : * Displays a serialized API message decode table, sorted by message name
1462 : *
1463 : * @cliexpar
1464 : * @cliexstart{show api dump file <filename>}
1465 : * Message name MsgID CRC
1466 : * accept_session 407 8e2a127e
1467 : * accept_session_reply 408 67d8c22a
1468 : * add_node_next 549 e4202993
1469 : * add_node_next_reply 550 e89d6eed
1470 : * etc.
1471 : * @cliexend
1472 : ?*/
1473 :
1474 : /*?
1475 : * Compares a serialized API message decode table with the current image
1476 : *
1477 : * @cliexpar
1478 : * @cliexstart{show api dump file <filename> compare}
1479 : * ip_add_del_route definition changed
1480 : * ip_table_add_del definition changed
1481 : * l2_macs_event only in image
1482 : * vnet_ip4_fib_counters only in file
1483 : * vnet_ip4_nbr_counters only in file
1484 : * @cliexend
1485 : ?*/
1486 :
1487 : /*?
1488 : * Display a serialized API message decode table, compare a saved
1489 : * decode table with the current image, to establish API differences.
1490 : *
1491 : ?*/
1492 : /* *INDENT-OFF* */
1493 272887 : VLIB_CLI_COMMAND (dump_api_table_file, static) =
1494 : {
1495 : .path = "show api dump",
1496 : .short_help = "show api dump file <filename> [numeric | compare-current]",
1497 : .function = dump_api_table_file_command_fn,
1498 : };
1499 :
1500 : /* *INDENT-ON* */
1501 : /*
1502 : * fd.io coding-style-patch-verification: ON
1503 : *
1504 : * Local Variables:
1505 : * eval: (c-set-style "gnu")
1506 : * End:
1507 : */
|