Line data Source code
1 : #include <vlib/vlib.h>
2 : #include <vnet/plugin/plugin.h>
3 : #include <vpp/app/version.h>
4 :
5 : typedef struct
6 : {
7 : u64 in;
8 : u64 out;
9 : u64 alloc;
10 : u64 free;
11 : } bufmon_per_node_data_t;
12 :
13 : typedef struct
14 : {
15 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
16 : bufmon_per_node_data_t *pnd;
17 : u32 cur_node;
18 : } bufmon_per_thread_data_t;
19 :
20 : typedef struct
21 : {
22 : bufmon_per_thread_data_t *ptd;
23 : int enabled;
24 : } bufmon_main_t;
25 :
26 : static bufmon_main_t bufmon_main;
27 :
28 : static u32
29 0 : bufmon_alloc_free_callback (vlib_main_t *vm, u32 n_buffers, const int is_free)
30 : {
31 0 : bufmon_main_t *bm = &bufmon_main;
32 : bufmon_per_thread_data_t *ptd;
33 : bufmon_per_node_data_t *pnd;
34 : u32 cur_node;
35 :
36 0 : if (PREDICT_FALSE (vm->thread_index >= vec_len (bm->ptd)))
37 : {
38 0 : clib_warning ("bufmon: thread index %d unknown for buffer %s (%d)",
39 : vm->thread_index, is_free ? "free" : "alloc", n_buffers);
40 0 : return n_buffers;
41 : }
42 :
43 0 : ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
44 :
45 0 : cur_node = ptd->cur_node;
46 0 : if (cur_node >= vec_len (ptd->pnd))
47 : {
48 0 : cur_node = vlib_get_current_process_node_index (vm);
49 0 : vec_validate_aligned (ptd->pnd, cur_node, CLIB_CACHE_LINE_BYTES);
50 : }
51 :
52 0 : pnd = vec_elt_at_index (ptd->pnd, cur_node);
53 :
54 0 : if (is_free)
55 0 : pnd->free += n_buffers;
56 : else
57 0 : pnd->alloc += n_buffers;
58 :
59 0 : return n_buffers;
60 : }
61 :
62 : static u32
63 0 : bufmon_alloc_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
64 : u32 n_buffers)
65 : {
66 0 : return bufmon_alloc_free_callback (vm, n_buffers, 0 /* is_free */);
67 : }
68 :
69 : static u32
70 0 : bufmon_free_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
71 : u32 n_buffers)
72 : {
73 0 : return bufmon_alloc_free_callback (vm, n_buffers, 1 /* is_free */);
74 : }
75 :
76 : static u32
77 0 : bufmon_count_buffers (vlib_main_t *vm, vlib_frame_t *frame)
78 : {
79 : vlib_buffer_t *b[VLIB_FRAME_SIZE];
80 0 : u32 *from = vlib_frame_vector_args (frame);
81 0 : const u32 n = frame->n_vectors;
82 0 : u32 nc = 0;
83 : u32 i;
84 :
85 0 : vlib_get_buffers (vm, from, b, n);
86 :
87 0 : for (i = 0; i < n; i++)
88 : {
89 0 : const vlib_buffer_t *cb = b[i];
90 0 : while (cb->flags & VLIB_BUFFER_NEXT_PRESENT)
91 : {
92 0 : nc++;
93 0 : cb = vlib_get_buffer (vm, cb->next_buffer);
94 : }
95 : }
96 :
97 0 : return n + nc;
98 : }
99 :
100 : static uword
101 0 : bufmon_dispatch_wrapper (vlib_main_t *vm, vlib_node_runtime_t *node,
102 : vlib_frame_t *frame)
103 : {
104 0 : vlib_node_main_t *nm = &vm->node_main;
105 0 : bufmon_main_t *bm = &bufmon_main;
106 : bufmon_per_thread_data_t *ptd;
107 : bufmon_per_node_data_t *pnd;
108 : int pending_frames;
109 : uword rv;
110 :
111 0 : ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
112 0 : vec_validate_aligned (ptd->pnd, node->node_index, CLIB_CACHE_LINE_BYTES);
113 0 : pnd = vec_elt_at_index (ptd->pnd, node->node_index);
114 :
115 0 : if (frame)
116 0 : pnd->in += bufmon_count_buffers (vm, frame);
117 :
118 0 : pending_frames = vec_len (nm->pending_frames);
119 0 : ptd->cur_node = node->node_index;
120 :
121 0 : rv = node->function (vm, node, frame);
122 :
123 0 : ptd->cur_node = ~0;
124 0 : for (; pending_frames < vec_len (nm->pending_frames); pending_frames++)
125 : {
126 0 : vlib_pending_frame_t *p =
127 0 : vec_elt_at_index (nm->pending_frames, pending_frames);
128 0 : pnd->out += bufmon_count_buffers (vm, vlib_get_frame (vm, p->frame));
129 : }
130 :
131 0 : return rv;
132 : }
133 :
134 : static void
135 0 : bufmon_unregister_callbacks (vlib_main_t *vm)
136 : {
137 0 : vlib_buffer_set_alloc_free_callback (vm, 0, 0);
138 0 : foreach_vlib_main ()
139 0 : vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
140 0 : }
141 :
142 : static clib_error_t *
143 0 : bufmon_register_callbacks (vlib_main_t *vm)
144 : {
145 0 : if (vlib_buffer_set_alloc_free_callback (vm, bufmon_alloc_callback,
146 : bufmon_free_callback))
147 0 : goto err0;
148 :
149 0 : foreach_vlib_main ()
150 0 : if (vlib_node_set_dispatch_wrapper (this_vlib_main,
151 : bufmon_dispatch_wrapper))
152 0 : goto err1;
153 :
154 0 : vec_validate_aligned (bufmon_main.ptd, vlib_thread_main.n_vlib_mains - 1,
155 : CLIB_CACHE_LINE_BYTES);
156 0 : return 0;
157 :
158 0 : err1:
159 0 : foreach_vlib_main ()
160 0 : vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
161 0 : err0:
162 0 : vlib_buffer_set_alloc_free_callback (vm, 0, 0);
163 0 : return clib_error_return (0, "failed to register callback");
164 : }
165 :
166 : static clib_error_t *
167 0 : bufmon_enable_disable (vlib_main_t *vm, int enable)
168 : {
169 0 : bufmon_main_t *bm = &bufmon_main;
170 :
171 0 : if (enable)
172 : {
173 0 : if (bm->enabled)
174 0 : return 0;
175 0 : clib_error_t *error = bufmon_register_callbacks (vm);
176 0 : if (error)
177 0 : return error;
178 0 : bm->enabled = 1;
179 : }
180 : else
181 : {
182 0 : if (!bm->enabled)
183 0 : return 0;
184 0 : bufmon_unregister_callbacks (vm);
185 0 : bm->enabled = 0;
186 : }
187 :
188 0 : return 0;
189 : }
190 :
191 : static clib_error_t *
192 0 : set_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
193 : vlib_cli_command_t *cmd)
194 : {
195 0 : unformat_input_t _line_input, *line_input = &_line_input;
196 0 : int on = 1;
197 :
198 0 : if (unformat_user (input, unformat_line_input, line_input))
199 : {
200 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
201 : {
202 0 : if (unformat (line_input, "on"))
203 0 : on = 1;
204 0 : else if (unformat (line_input, "off"))
205 0 : on = 0;
206 : else
207 : {
208 0 : unformat_free (line_input);
209 0 : return clib_error_return (0, "unknown input `%U'",
210 : format_unformat_error, line_input);
211 : }
212 : }
213 0 : unformat_free (line_input);
214 : }
215 :
216 0 : return bufmon_enable_disable (vm, on);
217 : }
218 :
219 253847 : 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,
223 : };
224 :
225 : static clib_error_t *
226 0 : show_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
227 : vlib_cli_command_t *cmd)
228 : {
229 0 : unformat_input_t _line_input, *line_input = &_line_input;
230 0 : const bufmon_main_t *bm = &bufmon_main;
231 : const bufmon_per_thread_data_t *ptd;
232 : const bufmon_per_node_data_t *pnd;
233 0 : int verbose = 0;
234 0 : int status = 0;
235 :
236 0 : if (unformat_user (input, unformat_line_input, line_input))
237 : {
238 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
239 : {
240 0 : if (unformat (line_input, "verbose"))
241 0 : verbose = 1;
242 0 : else if (unformat (line_input, "status"))
243 0 : status = 1;
244 : else
245 : {
246 0 : unformat_free (line_input);
247 0 : return clib_error_return (0, "unknown input `%U'",
248 : format_unformat_error, line_input);
249 : }
250 : }
251 0 : unformat_free (line_input);
252 : }
253 :
254 0 : if (status)
255 : {
256 0 : vlib_cli_output (vm, "buffers tracing is %s",
257 0 : bm->enabled ? "on" : "off");
258 0 : return 0;
259 : }
260 :
261 0 : vlib_cli_output (vm, "%U\n\n", format_vlib_buffer_pool_all, vm);
262 0 : vlib_cli_output (vm, "%30s%20s%20s%20s%20s%20s", "Node", "Allocated",
263 : "Freed", "In", "Out", "Buffered");
264 0 : vec_foreach (ptd, bm->ptd)
265 : {
266 0 : vec_foreach (pnd, ptd->pnd)
267 : {
268 0 : const u64 in = pnd->alloc + pnd->in;
269 0 : const u64 out = pnd->free + pnd->out;
270 0 : const i64 buffered = in - out;
271 0 : if (0 == in && 0 == out)
272 0 : continue; /* skip nodes w/o activity */
273 0 : if (0 == buffered && !verbose)
274 0 : continue; /* if not verbose, skip nodes w/o buffered buffers */
275 0 : vlib_cli_output (vm, "%30U%20lu%20lu%20lu%20lu%20ld",
276 0 : format_vlib_node_name, vm, pnd - ptd->pnd,
277 : pnd->alloc, pnd->free, pnd->in, pnd->out, buffered);
278 : }
279 : }
280 :
281 0 : return 0;
282 : }
283 :
284 253847 : 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,
288 : };
289 :
290 : static clib_error_t *
291 0 : clear_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
292 : vlib_cli_command_t *cmd)
293 : {
294 0 : const bufmon_main_t *bm = &bufmon_main;
295 : const bufmon_per_thread_data_t *ptd;
296 : const bufmon_per_node_data_t *pnd;
297 :
298 0 : vec_foreach (ptd, bm->ptd)
299 0 : vec_foreach (pnd, ptd->pnd)
300 0 : vec_reset_length (pnd);
301 :
302 0 : return 0;
303 : }
304 :
305 253847 : VLIB_CLI_COMMAND (clear_buffers_trace_command, static) = {
306 : .path = "clear buffer traces",
307 : .short_help = "clear buffer traces",
308 : .function = clear_buffer_traces,
309 : };
310 :
311 : VLIB_PLUGIN_REGISTER () = {
312 : .version = VPP_BUILD_VER,
313 : .description = "Buffers monitoring plugin",
314 : };
|