Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : * trace.c: VLIB trace buffer.
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vlib/vlib.h>
41 : #include <vlib/threads.h>
42 : #include <vnet/classify/vnet_classify.h>
43 :
44 : u8 *vnet_trace_placeholder;
45 :
46 : /* Helper function for nodes which only trace buffer data. */
47 : void
48 31424 : vlib_trace_frame_buffers_only (vlib_main_t * vm,
49 : vlib_node_runtime_t * node,
50 : u32 * buffers,
51 : uword n_buffers,
52 : uword next_buffer_stride,
53 : uword n_buffer_data_bytes_in_trace)
54 : {
55 : u32 n_left, *from;
56 :
57 31424 : n_left = n_buffers;
58 31424 : from = buffers;
59 :
60 464507 : while (n_left >= 4)
61 : {
62 : u32 bi0, bi1;
63 : vlib_buffer_t *b0, *b1;
64 : u8 *t0, *t1;
65 :
66 : /* Prefetch next iteration. */
67 433084 : vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
68 433094 : vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
69 :
70 433079 : bi0 = from[0];
71 433079 : bi1 = from[1];
72 :
73 433079 : b0 = vlib_get_buffer (vm, bi0);
74 433070 : b1 = vlib_get_buffer (vm, bi1);
75 :
76 433075 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
77 : {
78 432559 : t0 = vlib_add_trace (vm, node, b0, n_buffer_data_bytes_in_trace);
79 432495 : clib_memcpy_fast (t0, b0->data + b0->current_data,
80 : n_buffer_data_bytes_in_trace);
81 : }
82 433111 : if (b1->flags & VLIB_BUFFER_IS_TRACED)
83 : {
84 432585 : t1 = vlib_add_trace (vm, node, b1, n_buffer_data_bytes_in_trace);
85 432499 : clib_memcpy_fast (t1, b1->data + b1->current_data,
86 : n_buffer_data_bytes_in_trace);
87 : }
88 433083 : from += 2;
89 433083 : n_left -= 2;
90 : }
91 :
92 89000 : while (n_left >= 1)
93 : {
94 : u32 bi0;
95 : vlib_buffer_t *b0;
96 : u8 *t0;
97 :
98 57576 : bi0 = from[0];
99 :
100 57576 : b0 = vlib_get_buffer (vm, bi0);
101 :
102 57576 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
103 : {
104 57504 : t0 = vlib_add_trace (vm, node, b0, n_buffer_data_bytes_in_trace);
105 57504 : clib_memcpy_fast (t0, b0->data + b0->current_data,
106 : n_buffer_data_bytes_in_trace);
107 : }
108 57577 : from += 1;
109 57577 : n_left -= 1;
110 : }
111 31424 : }
112 :
113 : /* Free up all trace buffer memory. */
114 : void
115 16803 : clear_trace_buffer (void)
116 : {
117 : int i;
118 : vlib_trace_main_t *tm;
119 :
120 36176 : foreach_vlib_main ()
121 : {
122 19373 : tm = &this_vlib_main->trace_main;
123 :
124 19373 : tm->trace_enable = 0;
125 19373 : vec_free (tm->nodes);
126 : }
127 :
128 36176 : foreach_vlib_main ()
129 : {
130 19373 : tm = &this_vlib_main->trace_main;
131 :
132 524253 : for (i = 0; i < vec_len (tm->trace_buffer_pool); i++)
133 504880 : if (!pool_is_free_index (tm->trace_buffer_pool, i))
134 504880 : vec_free (tm->trace_buffer_pool[i]);
135 19373 : pool_free (tm->trace_buffer_pool);
136 : }
137 16803 : }
138 :
139 : u8 *
140 344671 : format_vlib_trace (u8 * s, va_list * va)
141 : {
142 344671 : vlib_main_t *vm = va_arg (*va, vlib_main_t *);
143 344671 : vlib_trace_header_t *h = va_arg (*va, vlib_trace_header_t *);
144 344671 : vlib_trace_header_t *e = vec_end (h);
145 : vlib_node_t *node, *prev_node;
146 344671 : clib_time_t *ct = &vm->clib_time;
147 : f64 t;
148 :
149 344671 : prev_node = 0;
150 4230110 : while (h < e)
151 : {
152 3885440 : node = vlib_get_node (vm, h->node_index);
153 :
154 3885440 : if (node != prev_node)
155 : {
156 3836920 : t =
157 3836920 : (h->time - vm->cpu_time_main_loop_start) * ct->seconds_per_clock;
158 : s =
159 3836920 : format (s, "\n%U: %v", format_time_interval, "h:m:s:u", t,
160 : node->name);
161 : }
162 3885440 : prev_node = node;
163 :
164 3885440 : if (node->format_trace)
165 3885440 : s = format (s, "\n %U", node->format_trace, vm, node, h->data);
166 : else
167 0 : s = format (s, "\n %U", node->format_buffer, h->data);
168 :
169 3885440 : h = vlib_trace_header_next (h);
170 : }
171 :
172 344671 : return s;
173 : }
174 :
175 : /* Root of all trace cli commands. */
176 : /* *INDENT-OFF* */
177 272887 : VLIB_CLI_COMMAND (trace_cli_command,static) = {
178 : .path = "trace",
179 : .short_help = "Packet tracer commands",
180 : };
181 : /* *INDENT-ON* */
182 :
183 : int
184 1696120 : trace_time_cmp (void *a1, void *a2)
185 : {
186 1696120 : vlib_trace_header_t **t1 = a1;
187 1696120 : vlib_trace_header_t **t2 = a2;
188 1696120 : i64 dt = t1[0]->time - t2[0]->time;
189 1696120 : return dt < 0 ? -1 : (dt > 0 ? +1 : 0);
190 : }
191 :
192 : /*
193 : * Return 1 if this packet passes the trace filter, or 0 otherwise
194 : */
195 : u32
196 0 : filter_accept (vlib_trace_main_t * tm, vlib_trace_header_t * h)
197 : {
198 0 : vlib_trace_header_t *e = vec_end (h);
199 :
200 0 : if (tm->filter_flag == 0)
201 0 : return 1;
202 :
203 : /*
204 : * When capturing a post-mortem dispatch trace,
205 : * toss all existing traces once per dispatch cycle.
206 : * So we can trace 4 billion pkts without running out of
207 : * memory...
208 : */
209 0 : if (tm->filter_flag == FILTER_FLAG_POST_MORTEM)
210 0 : return 0;
211 :
212 0 : if (tm->filter_flag == FILTER_FLAG_INCLUDE)
213 : {
214 0 : while (h < e)
215 : {
216 0 : if (h->node_index == tm->filter_node_index)
217 0 : return 1;
218 0 : h = vlib_trace_header_next (h);
219 : }
220 0 : return 0;
221 : }
222 : else /* FILTER_FLAG_EXCLUDE */
223 : {
224 0 : while (h < e)
225 : {
226 0 : if (h->node_index == tm->filter_node_index)
227 0 : return 0;
228 0 : h = vlib_trace_header_next (h);
229 : }
230 0 : return 1;
231 : }
232 :
233 : return 0;
234 : }
235 :
236 : /*
237 : * Remove traces from the trace buffer pool that don't pass the filter
238 : */
239 : void
240 31281 : trace_apply_filter (vlib_main_t * vm)
241 : {
242 31281 : vlib_trace_main_t *tm = &vm->trace_main;
243 : vlib_trace_header_t **h;
244 31281 : vlib_trace_header_t ***traces_to_remove = 0;
245 : u32 index;
246 : u32 trace_index;
247 : u32 n_accepted;
248 :
249 : u32 accept;
250 :
251 31281 : if (tm->filter_flag == FILTER_FLAG_NONE)
252 31281 : return;
253 :
254 : /*
255 : * Ideally we would retain the first N traces that pass the filter instead
256 : * of any N traces.
257 : */
258 0 : n_accepted = 0;
259 : /* *INDENT-OFF* */
260 0 : pool_foreach (h, tm->trace_buffer_pool)
261 : {
262 0 : accept = filter_accept(tm, h[0]);
263 :
264 0 : if ((n_accepted == tm->filter_count) || !accept)
265 0 : vec_add1 (traces_to_remove, h);
266 : else
267 0 : n_accepted++;
268 : }
269 : /* *INDENT-ON* */
270 :
271 : /* remove all traces that we don't want to keep */
272 0 : for (index = 0; index < vec_len (traces_to_remove); index++)
273 : {
274 0 : trace_index = traces_to_remove[index] - tm->trace_buffer_pool;
275 0 : vec_set_len (tm->trace_buffer_pool[trace_index], 0);
276 0 : pool_put_index (tm->trace_buffer_pool, trace_index);
277 : }
278 :
279 0 : vec_free (traces_to_remove);
280 : }
281 :
282 : static clib_error_t *
283 14321 : cli_show_trace_buffer (vlib_main_t * vm,
284 : unformat_input_t * input, vlib_cli_command_t * cmd)
285 : {
286 : vlib_trace_main_t *tm;
287 : vlib_trace_header_t **h, **traces;
288 14321 : u32 i, index = 0;
289 : char *fmt;
290 14321 : u8 *s = 0;
291 : u32 max;
292 :
293 : /*
294 : * By default display only this many traces. To display more, explicitly
295 : * specify a max. This prevents unexpectedly huge outputs.
296 : */
297 14321 : max = 50;
298 15932 : while (unformat_check_input (input) != (uword) UNFORMAT_END_OF_INPUT)
299 : {
300 1611 : if (unformat (input, "max %d", &max))
301 : ;
302 : else
303 0 : return clib_error_create ("expected 'max COUNT', got `%U'",
304 : format_unformat_error, input);
305 : }
306 :
307 :
308 : /* Get active traces from pool. */
309 :
310 30112 : foreach_vlib_main ()
311 : {
312 15791 : fmt = "------------------- Start of thread %d %s -------------------\n";
313 15791 : s = format (s, fmt, index, vlib_worker_threads[index].name);
314 :
315 15791 : tm = &this_vlib_main->trace_main;
316 :
317 15791 : trace_apply_filter (this_vlib_main);
318 :
319 15791 : traces = 0;
320 534065 : pool_foreach (h, tm->trace_buffer_pool)
321 : {
322 518274 : vec_add1 (traces, h[0]);
323 : }
324 :
325 15791 : if (vec_len (traces) == 0)
326 : {
327 1400 : s = format (s, "No packets in trace buffer\n");
328 1400 : goto done;
329 : }
330 :
331 : /* Sort them by increasing time. */
332 14391 : vec_sort_with_function (traces, trace_time_cmp);
333 :
334 358962 : for (i = 0; i < vec_len (traces); i++)
335 : {
336 348980 : if (i == max)
337 : {
338 4409 : char *warn = "Limiting display to %d packets."
339 : " To display more specify max.";
340 4409 : vlib_cli_output (vm, warn, max);
341 4409 : s = format (s, warn, max);
342 4409 : goto done;
343 : }
344 :
345 344571 : s = format (s, "Packet %d\n%U\n\n", i + 1, format_vlib_trace, vm,
346 344571 : traces[i]);
347 : }
348 :
349 9982 : done:
350 15791 : vec_free (traces);
351 :
352 15791 : index++;
353 : }
354 :
355 14321 : vlib_cli_output (vm, "%v", s);
356 14321 : vec_free (s);
357 14321 : return 0;
358 : }
359 :
360 : /* *INDENT-OFF* */
361 272887 : VLIB_CLI_COMMAND (show_trace_cli,static) = {
362 : .path = "show trace",
363 : .short_help = "Show trace buffer [max COUNT]",
364 : .function = cli_show_trace_buffer,
365 : };
366 : /* *INDENT-ON* */
367 :
368 : int vlib_enable_disable_pkt_trace_filter (int enable) __attribute__ ((weak));
369 :
370 : int
371 0 : vlib_enable_disable_pkt_trace_filter (int enable)
372 : {
373 0 : return 0;
374 : }
375 :
376 : void
377 16803 : vlib_trace_stop_and_clear (void)
378 : {
379 16803 : vlib_enable_disable_pkt_trace_filter (0); /* disble tracing */
380 16803 : clear_trace_buffer ();
381 16803 : }
382 :
383 :
384 : void
385 14730 : trace_update_capture_options (u32 add, u32 node_index, u32 filter, u8 verbose)
386 : {
387 : vlib_trace_main_t *tm;
388 : vlib_trace_node_t *tn;
389 :
390 14730 : if (add == ~0)
391 0 : add = 50;
392 :
393 31717 : foreach_vlib_main ()
394 : {
395 16987 : tm = &this_vlib_main->trace_main;
396 16987 : tm->verbose = verbose;
397 16987 : vec_validate (tm->nodes, node_index);
398 16987 : tn = tm->nodes + node_index;
399 :
400 : /*
401 : * Adding 0 makes no real sense, and there wa no other way
402 : * to explicilty zero-out the limits and count, so make
403 : * an "add 0" request really be "set to 0".
404 : */
405 16987 : if (add == 0)
406 0 : tn->limit = tn->count = 0;
407 : else
408 16987 : tn->limit += add;
409 : }
410 :
411 31717 : foreach_vlib_main ()
412 : {
413 16987 : tm = &this_vlib_main->trace_main;
414 16987 : tm->trace_enable = 1;
415 : }
416 :
417 14730 : vlib_enable_disable_pkt_trace_filter (! !filter);
418 14730 : }
419 :
420 : static clib_error_t *
421 14730 : cli_add_trace_buffer (vlib_main_t * vm,
422 : unformat_input_t * input, vlib_cli_command_t * cmd)
423 : {
424 14730 : unformat_input_t _line_input, *line_input = &_line_input;
425 : vlib_node_t *node;
426 : u32 node_index, add;
427 14730 : u8 verbose = 0;
428 14730 : int filter = 0;
429 14730 : clib_error_t *error = 0;
430 :
431 14730 : if (!unformat_user (input, unformat_line_input, line_input))
432 0 : return 0;
433 :
434 14730 : if (vnet_trace_placeholder == 0)
435 467 : vec_validate_aligned (vnet_trace_placeholder, 2048,
436 : CLIB_CACHE_LINE_BYTES);
437 :
438 29464 : while (unformat_check_input (line_input) != (uword) UNFORMAT_END_OF_INPUT)
439 : {
440 14734 : if (unformat (line_input, "%U %d",
441 : unformat_vlib_node, vm, &node_index, &add))
442 : ;
443 4 : else if (unformat (line_input, "verbose"))
444 0 : verbose = 1;
445 4 : else if (unformat (line_input, "filter"))
446 4 : filter = 1;
447 : else
448 : {
449 0 : error = clib_error_create ("expected NODE COUNT, got `%U'",
450 : format_unformat_error, line_input);
451 0 : goto done;
452 : }
453 : }
454 :
455 14730 : node = vlib_get_node (vm, node_index);
456 :
457 14730 : if ((node->flags & VLIB_NODE_FLAG_TRACE_SUPPORTED) == 0)
458 : {
459 0 : error = clib_error_create ("node '%U' doesn't support per-node "
460 : "tracing. There may be another way to "
461 : "initiate trace on this node.",
462 : format_vlib_node_name, vm, node_index);
463 0 : goto done;
464 : }
465 :
466 14730 : u32 filter_table = classify_get_trace_chain ();
467 14730 : if (filter && filter_table == ~0)
468 : {
469 0 : error = clib_error_create ("No packet trace filter configured...");
470 0 : goto done;
471 : }
472 :
473 14730 : trace_update_capture_options (add, node_index, filter, verbose);
474 :
475 14730 : done:
476 14730 : unformat_free (line_input);
477 :
478 14730 : return error;
479 : }
480 :
481 : /* *INDENT-OFF* */
482 272887 : VLIB_CLI_COMMAND (add_trace_cli,static) = {
483 : .path = "trace add",
484 : .short_help = "trace add <input-graph-node> <add'l-pkts-for-node-> [filter] [verbose]",
485 : .function = cli_add_trace_buffer,
486 : };
487 : /* *INDENT-ON* */
488 :
489 : /*
490 : * Configure a filter for packet traces.
491 : *
492 : * This supplements the packet trace feature so that only packets matching
493 : * the filter are included in the trace. Currently the only filter is to
494 : * keep packets that include a certain node in the trace or exclude a certain
495 : * node in the trace.
496 : *
497 : * The count of traced packets in the "trace add" command is still used to
498 : * create a certain number of traces. The "trace filter" command specifies
499 : * how many of those packets should be retained in the trace.
500 : *
501 : * For example, 1Mpps of traffic is arriving and one of those packets is being
502 : * dropped. To capture the trace for only that dropped packet, you can do:
503 : * trace filter include error-drop 1
504 : * trace add dpdk-input 1000000
505 : * <wait one second>
506 : * show trace
507 : *
508 : * Note that the filter could be implemented by capturing all traces and just
509 : * reducing traces displayed by the "show trace" function. But that would
510 : * require a lot of memory for storing the traces, making that infeasible.
511 : *
512 : * To remove traces from the trace pool that do not include a certain node
513 : * requires that the trace be "complete" before applying the filter. To
514 : * accomplish this, the trace pool is filtered upon each iteraction of the
515 : * main vlib loop. Doing so keeps the number of allocated traces down to a
516 : * reasonably low number. This requires that tracing for a buffer is not
517 : * performed after the vlib main loop interation completes. i.e. you can't
518 : * save away a buffer temporarily then inject it back into the graph and
519 : * expect that the trace_index is still valid (such as a traffic manager might
520 : * do). A new trace buffer should be allocated for those types of packets.
521 : *
522 : * The filter can be extended to support multiple nodes and other match
523 : * criteria (e.g. input sw_if_index, mac address) but for now just checks if
524 : * a specified node is in the trace or not in the trace.
525 : */
526 :
527 : void
528 0 : trace_filter_set (u32 node_index, u32 flag, u32 count)
529 : {
530 0 : foreach_vlib_main ()
531 : {
532 : vlib_trace_main_t *tm;
533 :
534 0 : tm = &this_vlib_main->trace_main;
535 0 : tm->filter_node_index = node_index;
536 0 : tm->filter_flag = flag;
537 0 : tm->filter_count = count;
538 :
539 : /*
540 : * Clear the trace limits to stop any in-progress tracing
541 : * Prevents runaway trace allocations when the filter changes
542 : * (or is removed)
543 : */
544 0 : vec_free (tm->nodes);
545 : }
546 0 : }
547 :
548 :
549 : static clib_error_t *
550 0 : cli_filter_trace (vlib_main_t * vm,
551 : unformat_input_t * input, vlib_cli_command_t * cmd)
552 : {
553 : u32 filter_node_index;
554 : u32 filter_flag;
555 : u32 filter_count;
556 :
557 0 : if (unformat (input, "include %U %d",
558 : unformat_vlib_node, vm, &filter_node_index, &filter_count))
559 : {
560 0 : filter_flag = FILTER_FLAG_INCLUDE;
561 : }
562 0 : else if (unformat (input, "exclude %U %d",
563 : unformat_vlib_node, vm, &filter_node_index,
564 : &filter_count))
565 : {
566 0 : filter_flag = FILTER_FLAG_EXCLUDE;
567 : }
568 0 : else if (unformat (input, "none"))
569 : {
570 0 : filter_flag = FILTER_FLAG_NONE;
571 0 : filter_node_index = 0;
572 0 : filter_count = 0;
573 : }
574 : else
575 : return
576 0 : clib_error_create
577 : ("expected 'include NODE COUNT' or 'exclude NODE COUNT' or 'none', got `%U'",
578 : format_unformat_error, input);
579 :
580 0 : trace_filter_set (filter_node_index, filter_flag, filter_count);
581 :
582 0 : return 0;
583 : }
584 :
585 : /* *INDENT-OFF* */
586 272887 : VLIB_CLI_COMMAND (filter_trace_cli,static) = {
587 : .path = "trace filter",
588 : .short_help = "trace filter none | [include|exclude] NODE COUNT",
589 : .function = cli_filter_trace,
590 : };
591 : /* *INDENT-ON* */
592 :
593 : static clib_error_t *
594 16803 : cli_clear_trace_buffer (vlib_main_t * vm,
595 : unformat_input_t * input, vlib_cli_command_t * cmd)
596 : {
597 16803 : vlib_trace_stop_and_clear ();
598 16803 : return 0;
599 : }
600 :
601 : /* *INDENT-OFF* */
602 272887 : VLIB_CLI_COMMAND (clear_trace_cli,static) = {
603 : .path = "clear trace",
604 : .short_help = "Clear trace buffer and free memory",
605 : .function = cli_clear_trace_buffer,
606 : };
607 : /* *INDENT-ON* */
608 :
609 : /* Placeholder function to get us linked in. */
610 : void
611 559 : vlib_trace_cli_reference (void)
612 : {
613 559 : }
614 :
615 : void *
616 5658900 : vlib_add_trace (vlib_main_t * vm,
617 : vlib_node_runtime_t * r, vlib_buffer_t * b, u32 n_data_bytes)
618 : {
619 5658900 : return vlib_add_trace_inline (vm, r, b, n_data_bytes);
620 : }
621 :
622 : vlib_is_packet_traced_fn_t *
623 0 : vlib_is_packet_traced_function_from_name (const char *name)
624 : {
625 0 : vlib_trace_filter_function_registration_t *reg =
626 : vlib_trace_filter_main.trace_filter_registration;
627 0 : while (reg)
628 : {
629 0 : if (clib_strcmp (reg->name, name) == 0)
630 0 : break;
631 0 : reg = reg->next;
632 : }
633 0 : if (!reg)
634 0 : return 0;
635 0 : return reg->function;
636 : }
637 :
638 : static vlib_is_packet_traced_fn_t *
639 559 : vlib_is_packet_traced_default_function ()
640 : {
641 559 : vlib_trace_filter_function_registration_t *reg =
642 : vlib_trace_filter_main.trace_filter_registration;
643 559 : vlib_trace_filter_function_registration_t *tmp_reg = reg;
644 1677 : while (reg)
645 : {
646 1118 : if (reg->priority > tmp_reg->priority)
647 559 : tmp_reg = reg;
648 1118 : reg = reg->next;
649 : }
650 559 : return tmp_reg->function;
651 : }
652 :
653 : static clib_error_t *
654 559 : vlib_trace_filter_function_init (vlib_main_t *vm)
655 : {
656 : vlib_is_packet_traced_fn_t *default_fn =
657 559 : vlib_is_packet_traced_default_function ();
658 1118 : foreach_vlib_main ()
659 : {
660 559 : vlib_trace_main_t *tm = &this_vlib_main->trace_main;
661 559 : tm->current_trace_filter_function = default_fn;
662 : }
663 559 : return 0;
664 : }
665 :
666 : vlib_trace_filter_main_t vlib_trace_filter_main;
667 :
668 5039 : VLIB_INIT_FUNCTION (vlib_trace_filter_function_init);
669 :
670 : static clib_error_t *
671 0 : show_trace_filter_function (vlib_main_t *vm, unformat_input_t *input,
672 : vlib_cli_command_t *cmd)
673 : {
674 0 : vlib_trace_filter_main_t *tfm = &vlib_trace_filter_main;
675 0 : vlib_trace_main_t *tm = &vm->trace_main;
676 0 : vlib_is_packet_traced_fn_t *current_trace_filter_fn =
677 : tm->current_trace_filter_function;
678 0 : vlib_trace_filter_function_registration_t *reg =
679 : tfm->trace_filter_registration;
680 :
681 0 : while (reg)
682 : {
683 0 : vlib_cli_output (vm, "%sname:%s description: %s priority: %u",
684 0 : reg->function == current_trace_filter_fn ? "(*) " : "",
685 : reg->name, reg->description, reg->priority);
686 0 : reg = reg->next;
687 : }
688 0 : return 0;
689 : }
690 :
691 272887 : VLIB_CLI_COMMAND (show_trace_filter_function_cli, static) = {
692 : .path = "show trace filter function",
693 : .short_help = "show trace filter function",
694 : .function = show_trace_filter_function,
695 : };
696 :
697 : uword
698 0 : unformat_vlib_trace_filter_function (unformat_input_t *input, va_list *args)
699 : {
700 0 : vlib_is_packet_traced_fn_t **res =
701 : va_arg (*args, vlib_is_packet_traced_fn_t **);
702 0 : vlib_trace_filter_main_t *tfm = &vlib_trace_filter_main;
703 :
704 0 : vlib_trace_filter_function_registration_t *reg =
705 : tfm->trace_filter_registration;
706 0 : while (reg)
707 : {
708 0 : if (unformat (input, reg->name))
709 : {
710 0 : *res = reg->function;
711 0 : return 1;
712 : }
713 0 : reg = reg->next;
714 : }
715 0 : return 0;
716 : }
717 :
718 : void
719 0 : vlib_set_trace_filter_function (vlib_is_packet_traced_fn_t *x)
720 : {
721 0 : foreach_vlib_main ()
722 : {
723 0 : this_vlib_main->trace_main.current_trace_filter_function = x;
724 : }
725 0 : }
726 :
727 : static clib_error_t *
728 0 : set_trace_filter_function (vlib_main_t *vm, unformat_input_t *input,
729 : vlib_cli_command_t *cmd)
730 : {
731 0 : unformat_input_t _line_input, *line_input = &_line_input;
732 0 : vlib_is_packet_traced_fn_t *res = 0;
733 0 : clib_error_t *error = 0;
734 :
735 0 : if (!unformat_user (input, unformat_line_input, line_input))
736 0 : return 0;
737 :
738 0 : while (unformat_check_input (line_input) != (uword) UNFORMAT_END_OF_INPUT)
739 : {
740 0 : if (unformat (line_input, "%U", unformat_vlib_trace_filter_function,
741 : &res))
742 : ;
743 : else
744 : {
745 0 : error = clib_error_create (
746 : "expected valid trace filter function, got `%U'",
747 : format_unformat_error, line_input);
748 0 : goto done;
749 : }
750 : }
751 0 : vlib_set_trace_filter_function (res);
752 :
753 0 : done:
754 0 : unformat_free (line_input);
755 :
756 0 : return error;
757 : }
758 :
759 272887 : VLIB_CLI_COMMAND (set_trace_filter_function_cli, static) = {
760 : .path = "set trace filter function",
761 : .short_help = "set trace filter function <func_name>",
762 : .function = set_trace_filter_function,
763 : };
764 : /*
765 : * fd.io coding-style-patch-verification: ON
766 : *
767 : * Local Variables:
768 : * eval: (c-set-style "gnu")
769 : * End:
770 : */
|