2 #include <vnet/plugin/plugin.h>
3 #include <vpp/app/version.h>
11 } bufmon_per_node_data_t;
15 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
16 bufmon_per_node_data_t *pnd;
18 } bufmon_per_thread_data_t;
22 bufmon_per_thread_data_t *ptd;
26 static bufmon_main_t bufmon_main;
29 bufmon_alloc_free_callback (vlib_main_t *vm, u32 n_buffers, const int is_free)
31 bufmon_main_t *bm = &bufmon_main;
32 bufmon_per_thread_data_t *ptd;
33 bufmon_per_node_data_t *pnd;
36 if (PREDICT_FALSE (vm->thread_index >= vec_len (bm->ptd)))
38 clib_warning ("bufmon: thread index %d unknown for buffer %s (%d)",
39 vm->thread_index, is_free ? "free" : "alloc", n_buffers);
43 ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
45 cur_node = ptd->cur_node;
46 if (cur_node >= vec_len (ptd->pnd))
48 cur_node = vlib_get_current_process_node_index (vm);
49 vec_validate_aligned (ptd->pnd, cur_node, CLIB_CACHE_LINE_BYTES);
52 pnd = vec_elt_at_index (ptd->pnd, cur_node);
55 pnd->free += n_buffers;
57 pnd->alloc += n_buffers;
63 bufmon_alloc_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
66 return bufmon_alloc_free_callback (vm, n_buffers, 0 /* is_free */);
70 bufmon_free_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
73 return bufmon_alloc_free_callback (vm, n_buffers, 1 /* is_free */);
77 bufmon_count_buffers (vlib_main_t *vm, vlib_frame_t *frame)
79 vlib_buffer_t *b[VLIB_FRAME_SIZE];
80 u32 *from = vlib_frame_vector_args (frame);
81 const u32 n = frame->n_vectors;
85 vlib_get_buffers (vm, from, b, n);
87 for (i = 0; i < n; i++)
89 const vlib_buffer_t *cb = b[i];
90 while (cb->flags & VLIB_BUFFER_NEXT_PRESENT)
93 cb = vlib_get_buffer (vm, cb->next_buffer);
101 bufmon_dispatch_wrapper (vlib_main_t *vm, vlib_node_runtime_t *node,
104 vlib_node_main_t *nm = &vm->node_main;
105 bufmon_main_t *bm = &bufmon_main;
106 bufmon_per_thread_data_t *ptd;
107 bufmon_per_node_data_t *pnd;
111 ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
112 vec_validate_aligned (ptd->pnd, node->node_index, CLIB_CACHE_LINE_BYTES);
113 pnd = vec_elt_at_index (ptd->pnd, node->node_index);
116 pnd->in += bufmon_count_buffers (vm, frame);
118 pending_frames = vec_len (nm->pending_frames);
119 ptd->cur_node = node->node_index;
121 rv = node->function (vm, node, frame);
124 for (; pending_frames < vec_len (nm->pending_frames); pending_frames++)
126 vlib_pending_frame_t *p =
127 vec_elt_at_index (nm->pending_frames, pending_frames);
128 pnd->out += bufmon_count_buffers (vm, vlib_get_frame (vm, p->frame));
135 bufmon_unregister_callbacks (vlib_main_t *vm)
137 vlib_buffer_set_alloc_free_callback (vm, 0, 0);
139 vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
142 static clib_error_t *
143 bufmon_register_callbacks (vlib_main_t *vm)
145 if (vlib_buffer_set_alloc_free_callback (vm, bufmon_alloc_callback,
146 bufmon_free_callback))
150 if (vlib_node_set_dispatch_wrapper (this_vlib_main,
151 bufmon_dispatch_wrapper))
154 vec_validate_aligned (bufmon_main.ptd, vlib_thread_main.n_vlib_mains - 1,
155 CLIB_CACHE_LINE_BYTES);
160 vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
162 vlib_buffer_set_alloc_free_callback (vm, 0, 0);
163 return clib_error_return (0, "failed to register callback");
166 static clib_error_t *
167 bufmon_enable_disable (vlib_main_t *vm, int enable)
169 bufmon_main_t *bm = &bufmon_main;
175 clib_error_t *error = bufmon_register_callbacks (vm);
184 bufmon_unregister_callbacks (vm);
191 static clib_error_t *
192 set_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
193 vlib_cli_command_t *cmd)
195 unformat_input_t _line_input, *line_input = &_line_input;
198 if (unformat_user (input, unformat_line_input, line_input))
200 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
202 if (unformat (line_input, "on"))
204 else if (unformat (line_input, "off"))
208 unformat_free (line_input);
209 return clib_error_return (0, "unknown input `%U'",
210 format_unformat_error, line_input);
213 unformat_free (line_input);
216 return bufmon_enable_disable (vm, on);
219 VLIB_CLI_COMMAND (set_buffer_traces_command, static) = {
220 .path = "set buffer traces",
221 .short_help = "set buffer traces [on|off]",
222 .function = set_buffer_traces,
225 static clib_error_t *
226 show_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
227 vlib_cli_command_t *cmd)
229 unformat_input_t _line_input, *line_input = &_line_input;
230 const bufmon_main_t *bm = &bufmon_main;
231 const bufmon_per_thread_data_t *ptd;
232 const bufmon_per_node_data_t *pnd;
236 if (unformat_user (input, unformat_line_input, line_input))
238 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
240 if (unformat (line_input, "verbose"))
242 else if (unformat (line_input, "status"))
246 unformat_free (line_input);
247 return clib_error_return (0, "unknown input `%U'",
248 format_unformat_error, line_input);
251 unformat_free (line_input);
256 vlib_cli_output (vm, "buffers tracing is %s",
257 bm->enabled ? "on" : "off");
261 vlib_cli_output (vm, "%U\n\n", format_vlib_buffer_pool_all, vm);
262 vlib_cli_output (vm, "%30s%20s%20s%20s%20s%20s", "Node", "Allocated",
263 "Freed", "In", "Out", "Buffered");
264 vec_foreach (ptd, bm->ptd)
266 vec_foreach (pnd, ptd->pnd)
268 const u64 in = pnd->alloc + pnd->in;
269 const u64 out = pnd->free + pnd->out;
270 const i64 buffered = in - out;
271 if (0 == in && 0 == out)
272 continue; /* skip nodes w/o activity */
273 if (0 == buffered && !verbose)
274 continue; /* if not verbose, skip nodes w/o buffered buffers */
275 vlib_cli_output (vm, "%30U%20lu%20lu%20lu%20lu%20ld",
276 format_vlib_node_name, vm, pnd - ptd->pnd,
277 pnd->alloc, pnd->free, pnd->in, pnd->out, buffered);
284 VLIB_CLI_COMMAND (show_buffer_traces_command, static) = {
285 .path = "show buffer traces",
286 .short_help = "show buffer traces [status|verbose]",
287 .function = show_buffer_traces,
290 static clib_error_t *
291 clear_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
292 vlib_cli_command_t *cmd)
294 const bufmon_main_t *bm = &bufmon_main;
295 const bufmon_per_thread_data_t *ptd;
296 const bufmon_per_node_data_t *pnd;
298 vec_foreach (ptd, bm->ptd)
299 vec_foreach (pnd, ptd->pnd)
300 vec_reset_length (pnd);
305 VLIB_CLI_COMMAND (clear_buffers_trace_command, static) = {
306 .path = "clear buffer traces",
307 .short_help = "clear buffer traces",
308 .function = clear_buffer_traces,
311 VLIB_PLUGIN_REGISTER () = {
312 .version = VPP_BUILD_VER,
313 .description = "Buffers monitoring plugin",