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 : * @file
17 : * @brief Host utility functions
18 : */
19 : #include <vppinfra/format.h>
20 : #include <vlib/vlib.h>
21 :
22 : #include <vlib/threads.h>
23 : #include <vnet/vnet.h>
24 : #include <vppinfra/format.h>
25 :
26 : /**
27 : * @brief GDB callable function: vl - Return vector length of vector
28 : *
29 : * @param *p - void - address of vector
30 : *
31 : * @return length - u32
32 : *
33 : */
34 : u32
35 0 : vl (void *p)
36 : {
37 0 : return vec_len (p);
38 : }
39 :
40 : /**
41 : * @brief GDB callable function: pvh - Return vector header of vector
42 : *
43 : * @param *p - void - address of vector
44 : *
45 : * @return vh - vec_header_t, the vector header
46 : *
47 : */
48 : vec_header_t *
49 0 : pvh (void *p)
50 : {
51 0 : return _vec_find (p);
52 : }
53 :
54 :
55 : /**
56 : * @brief GDB callable function: pe - call pool_elts - number of elements in a pool
57 : *
58 : * @param *v - void - address of pool
59 : *
60 : * @return number - uword
61 : *
62 : */
63 : uword
64 0 : pe (void *v)
65 : {
66 0 : return (pool_elts (v));
67 : }
68 :
69 : /**
70 : * @brief GDB callable function: ph - call pool_header - get pool header.
71 : *
72 : * @param *p - void - address of pool
73 : *
74 : * @return pool_header_t
75 : *
76 : */
77 : pool_header_t *
78 0 : ph (void *p)
79 : {
80 0 : return pool_header (p);
81 : }
82 :
83 : /**
84 : * @brief GDB callable function: pifi - call pool_is_free_index - is passed index free?
85 : *
86 : * @param *p - void - address of pool
87 : * @param *index - u32
88 : *
89 : * @return 0|1 - int
90 : *
91 : */
92 : int
93 0 : pifi (void *p, u32 index)
94 : {
95 0 : return pool_is_free_index (p, index);
96 : }
97 :
98 : /**
99 : * @brief GDB callable function: debug_hex_bytes - return formatted hex string
100 : *
101 : * @param *s - u8
102 : * @param n - u32 - number of bytes to format
103 : *
104 : */
105 : void
106 0 : debug_hex_bytes (u8 * s, u32 n)
107 : {
108 0 : fformat (stderr, "%U\n", format_hex_bytes, s, n);
109 0 : }
110 :
111 : /**
112 : * @brief GDB callable function: vlib_dump_frame_ownership
113 : *
114 : */
115 : void
116 0 : vlib_dump_frame_ownership (void)
117 : {
118 0 : vlib_main_t *vm = vlib_get_main ();
119 0 : vlib_node_main_t *nm = &vm->node_main;
120 : vlib_node_runtime_t *this_node_runtime;
121 : vlib_next_frame_t *nf;
122 : u32 first_nf_index;
123 : u32 index;
124 :
125 0 : vec_foreach (this_node_runtime, nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL])
126 : {
127 0 : first_nf_index = this_node_runtime->next_frame_index;
128 :
129 0 : for (index = first_nf_index; index < first_nf_index +
130 0 : this_node_runtime->n_next_nodes; index++)
131 : {
132 : vlib_node_runtime_t *owned_runtime;
133 0 : nf = vec_elt_at_index (vm->node_main.next_frames, index);
134 0 : if (nf->flags & VLIB_FRAME_OWNER)
135 : {
136 0 : owned_runtime = vec_elt_at_index (nm->nodes_by_type[0],
137 : nf->node_runtime_index);
138 0 : fformat (stderr,
139 : "%s next index %d owns enqueue rights to %s\n",
140 0 : nm->nodes[this_node_runtime->node_index]->name,
141 : index - first_nf_index,
142 0 : nm->nodes[owned_runtime->node_index]->name);
143 0 : fformat (stderr, " nf index %d nf->frame %p\n",
144 0 : nf - vm->node_main.next_frames, nf->frame);
145 : }
146 : }
147 : }
148 0 : }
149 :
150 : /**
151 : * @brief GDB callable function: vlib_runtime_index_to_node_name
152 : *
153 : * Takes node index and will return the node name.
154 : *
155 : * @param index - u32
156 : */
157 : void
158 0 : vlib_runtime_index_to_node_name (u32 index)
159 : {
160 0 : vlib_main_t *vm = vlib_get_main ();
161 0 : vlib_node_main_t *nm = &vm->node_main;
162 :
163 0 : if (index >= vec_len (nm->nodes))
164 : {
165 0 : fformat (stderr, "%d out of range, max %d\n", vec_len (nm->nodes));
166 0 : return;
167 : }
168 :
169 0 : fformat (stderr, "node runtime index %d name %s\n", index,
170 0 : nm->nodes[index]->name);
171 : }
172 :
173 : void
174 0 : gdb_show_errors (int verbose)
175 : {
176 : extern vlib_cli_command_t vlib_cli_show_errors;
177 : unformat_input_t input;
178 0 : vlib_main_t *vm = vlib_get_main ();
179 :
180 0 : if (verbose == 0)
181 0 : unformat_init_string (&input, "verbose 0", 9);
182 0 : else if (verbose == 1)
183 0 : unformat_init_string (&input, "verbose 1", 9);
184 : else
185 : {
186 0 : fformat (stderr, "verbose not 0 or 1\n");
187 0 : return;
188 : }
189 :
190 0 : vlib_cli_show_errors.function (vm, &input, 0 /* cmd */ );
191 0 : unformat_free (&input);
192 : }
193 :
194 : void
195 0 : gdb_show_session (int verbose)
196 : {
197 : extern vlib_cli_command_t vlib_cli_show_session_command;
198 : unformat_input_t input;
199 0 : vlib_main_t *vm = vlib_get_main ();
200 :
201 0 : if (verbose == 0)
202 0 : unformat_init_string (&input, "verbose 0", 9);
203 0 : else if (verbose == 1)
204 0 : unformat_init_string (&input, "verbose 1", 9);
205 0 : else if (verbose == 2)
206 0 : unformat_init_string (&input, "verbose 2", 9);
207 : else
208 : {
209 0 : fformat (stderr, "verbose not 0 - 2\n");
210 0 : return;
211 : }
212 :
213 0 : vlib_cli_show_session_command.function (vm, &input, 0 /* cmd */ );
214 0 : unformat_free (&input);
215 : }
216 :
217 : static int
218 0 : trace_cmp (void *a1, void *a2)
219 : {
220 0 : vlib_trace_header_t **t1 = a1;
221 0 : vlib_trace_header_t **t2 = a2;
222 0 : i64 dt = t1[0]->time - t2[0]->time;
223 0 : return dt < 0 ? -1 : (dt > 0 ? +1 : 0);
224 : }
225 :
226 : void
227 0 : gdb_show_traces ()
228 : {
229 : vlib_trace_main_t *tm;
230 : vlib_trace_header_t **h, **traces;
231 0 : u32 i, index = 0;
232 : char *fmt;
233 0 : u8 *s = 0;
234 : u32 max;
235 :
236 : /* By default display only this many traces. */
237 0 : max = 50;
238 :
239 : /* Get active traces from pool. */
240 :
241 0 : foreach_vlib_main ()
242 : {
243 0 : fmt = "------------------- Start of thread %d %s -------------------\n";
244 0 : s = format (s, fmt, index, vlib_worker_threads[index].name);
245 :
246 0 : tm = &this_vlib_main->trace_main;
247 :
248 0 : trace_apply_filter (this_vlib_main);
249 :
250 0 : traces = 0;
251 0 : pool_foreach (h, tm->trace_buffer_pool)
252 : {
253 0 : vec_add1 (traces, h[0]);
254 : }
255 :
256 0 : if (vec_len (traces) == 0)
257 : {
258 0 : s = format (s, "No packets in trace buffer\n");
259 0 : goto done;
260 : }
261 :
262 : /* Sort them by increasing time. */
263 0 : vec_sort_with_function (traces, trace_cmp);
264 :
265 0 : for (i = 0; i < vec_len (traces); i++)
266 : {
267 0 : if (i == max)
268 : {
269 0 : fformat (stderr,
270 : "Limiting display to %d packets."
271 : " To display more specify max.",
272 : max);
273 0 : goto done;
274 : }
275 :
276 0 : s = format (s, "Packet %d\n%U\n\n", i + 1, format_vlib_trace,
277 0 : vlib_get_first_main (), traces[i]);
278 : }
279 :
280 0 : done:
281 0 : vec_free (traces);
282 :
283 0 : index++;
284 : }
285 :
286 0 : fformat (stderr, "%v", s);
287 0 : vec_free (s);
288 0 : }
289 :
290 : /**
291 : * @brief GDB callable function: show_gdb_command_fn - show gdb
292 : *
293 : * Shows list of functions for VPP available in GDB
294 : *
295 : * @return error - clib_error_t
296 : */
297 : static clib_error_t *
298 0 : show_gdb_command_fn (vlib_main_t * vm,
299 : unformat_input_t * input, vlib_cli_command_t * cmd)
300 : {
301 0 : vlib_cli_output (vm, "vl(p) returns vec_len(p)");
302 0 : vlib_cli_output (vm, "vb(b) returns vnet_buffer(b) [opaque]");
303 0 : vlib_cli_output (vm, "vb2(b) returns vnet_buffer2(b) [opaque2]");
304 0 : vlib_cli_output (vm, "vbi(b) returns b index");
305 0 : vlib_cli_output (vm,
306 : "vgb(bi) returns vlib_get_buffer(vlib_get_main(), bi)");
307 0 : vlib_cli_output (vm, "pe(p) returns pool_elts(p)");
308 0 : vlib_cli_output (vm, "ph(p) returns pool_header(p)");
309 0 : vlib_cli_output (vm, "pifi(p, i) returns pool_is_free_index(p, i)");
310 0 : vlib_cli_output (vm, "gdb_show_errors(0|1) dumps error counters");
311 0 : vlib_cli_output (vm, "gdb_show_session dumps session counters");
312 0 : vlib_cli_output (vm, "gdb_show_traces() dumps buffer traces");
313 0 : vlib_cli_output (vm, "gdb_validate_buffer(b) check vlib_buffer b sanity");
314 0 : vlib_cli_output (vm, "debug_hex_bytes (ptr, n_bytes) dumps n_bytes in hex");
315 0 : vlib_cli_output (vm, "vlib_dump_frame_ownership() does what it says");
316 0 : vlib_cli_output (vm, "vlib_runtime_index_to_node_name (index) prints NN");
317 :
318 0 : return 0;
319 : }
320 :
321 : /* *INDENT-OFF* */
322 285289 : VLIB_CLI_COMMAND (show_gdb_funcs_command, static) = {
323 : .path = "show gdb",
324 : .short_help = "Describe functions which can be called from gdb",
325 : .function = show_gdb_command_fn,
326 : };
327 : /* *INDENT-ON* */
328 :
329 : vlib_buffer_t *
330 0 : vgb (u32 bi)
331 : {
332 0 : return vlib_get_buffer (vlib_get_main (), bi);
333 : }
334 :
335 : vnet_buffer_opaque_t *
336 0 : vb (void *vb_arg)
337 : {
338 0 : vlib_buffer_t *b = (vlib_buffer_t *) vb_arg;
339 : vnet_buffer_opaque_t *rv;
340 :
341 0 : rv = vnet_buffer (b);
342 :
343 0 : return rv;
344 : }
345 :
346 : vnet_buffer_opaque2_t *
347 0 : vb2 (void *vb_arg)
348 : {
349 0 : vlib_buffer_t *b = (vlib_buffer_t *) vb_arg;
350 : vnet_buffer_opaque2_t *rv;
351 :
352 0 : rv = vnet_buffer2 (b);
353 :
354 0 : return rv;
355 : }
356 :
357 : u32
358 0 : vbi (vlib_buffer_t * b)
359 : {
360 0 : vlib_main_t *vm = vlib_get_main ();
361 0 : vlib_buffer_main_t *bm = vm->buffer_main;
362 0 : u32 bi = pointer_to_uword (b) - bm->buffer_mem_start;
363 0 : bi >>= CLIB_LOG2_CACHE_LINE_BYTES;
364 0 : return bi;
365 : }
366 :
367 : int
368 0 : gdb_validate_buffer (vlib_buffer_t * b)
369 : {
370 0 : vlib_main_t *vm = vlib_get_main ();
371 0 : u32 bi = vbi (b);
372 : u8 *s =
373 0 : vlib_validate_buffers (vm, &bi, 0, 1, VLIB_BUFFER_KNOWN_ALLOCATED, 1);
374 0 : if (s)
375 : {
376 0 : fformat (stderr, "gdb_validate_buffer(): %v", s);
377 0 : return -1;
378 : }
379 0 : fformat (stderr, "gdb_validate_buffer(): no error found\n");
380 0 : return 0;
381 : }
382 :
383 : /**
384 : * Dump a trajectory trace, reasonably easy to call from gdb
385 : */
386 : void
387 0 : gdb_dump_trajectory_trace (u32 bi)
388 : {
389 : #if VLIB_BUFFER_TRACE_TRAJECTORY > 0
390 : vlib_main_t *vm = vlib_get_main ();
391 : vlib_node_main_t *vnm = &vm->node_main;
392 : vlib_buffer_t *b;
393 : u16 *trace;
394 : u8 i;
395 :
396 : b = vlib_get_buffer (vm, bi);
397 :
398 : trace = b->trajectory_trace;
399 :
400 : fformat (stderr, "Context trace for bi %d b 0x%llx, visited %d\n", bi, b,
401 : b->trajectory_nb);
402 :
403 : for (i = 0; i < b->trajectory_nb; i++)
404 : {
405 : u32 node_index;
406 :
407 : node_index = trace[i];
408 :
409 : if (node_index >= vec_len (vnm->nodes))
410 : {
411 : fformat (stderr, "Skip bogus node index %d\n", node_index);
412 : continue;
413 : }
414 :
415 : fformat (stderr, "%v (%d)\n", vnm->nodes[node_index]->name, node_index);
416 : }
417 : #else
418 0 : fformat (stderr, "in vlib/buffers.h, "
419 : "#define VLIB_BUFFER_TRACE_TRAJECTORY 1\n");
420 :
421 : #endif
422 0 : }
423 :
424 : void
425 0 : gdb_dump_buffer (vlib_buffer_t *b)
426 : {
427 0 : fformat (stderr, "%U\n", format_vnet_buffer, b);
428 0 : }
429 :
430 : /* Cafeteria plan, maybe you don't want these functions */
431 : clib_error_t *
432 575 : gdb_func_init (vlib_main_t * vm)
433 : {
434 575 : return 0;
435 : }
436 :
437 80639 : VLIB_INIT_FUNCTION (gdb_func_init);
438 :
439 : /*
440 : * fd.io coding-style-patch-verification: ON
441 : *
442 : * Local Variables:
443 : * eval: (c-set-style "gnu")
444 : * End:
445 : */
|