vrrp: fix vrrp_garp_or_na_send()'s memory leak
[vpp.git] / src / plugins / bufmon / bufmon.c
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 bufmon_alloc_free_callback (vlib_main_t *vm, u32 n_buffers, const int is_free)
30 {
31   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   if (PREDICT_FALSE (vm->thread_index >= vec_len (bm->ptd)))
37     {
38       clib_warning ("bufmon: thread index %d unknown for buffer %s (%d)",
39                     vm->thread_index, is_free ? "free" : "alloc", n_buffers);
40       return n_buffers;
41     }
42
43   ptd = vec_elt_at_index (bm->ptd, vm->thread_index);
44
45   cur_node = ptd->cur_node;
46   if (cur_node >= vec_len (ptd->pnd))
47     {
48       cur_node = vlib_get_current_process_node_index (vm);
49       vec_validate_aligned (ptd->pnd, cur_node, CLIB_CACHE_LINE_BYTES);
50     }
51
52   pnd = vec_elt_at_index (ptd->pnd, cur_node);
53
54   if (is_free)
55     pnd->free += n_buffers;
56   else
57     pnd->alloc += n_buffers;
58
59   return n_buffers;
60 }
61
62 static u32
63 bufmon_alloc_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
64                        u32 n_buffers)
65 {
66   return bufmon_alloc_free_callback (vm, n_buffers, 0 /* is_free */);
67 }
68
69 static u32
70 bufmon_free_callback (vlib_main_t *vm, u8 buffer_pool_index, u32 *buffers,
71                       u32 n_buffers)
72 {
73   return bufmon_alloc_free_callback (vm, n_buffers, 1 /* is_free */);
74 }
75
76 static u32
77 bufmon_count_buffers (vlib_main_t *vm, vlib_frame_t *frame)
78 {
79   vlib_buffer_t *b[VLIB_FRAME_SIZE];
80   u32 *from = vlib_frame_vector_args (frame);
81   const u32 n = frame->n_vectors;
82   u32 nc = 0;
83   u32 i;
84
85   vlib_get_buffers (vm, from, b, n);
86
87   for (i = 0; i < n; i++)
88     {
89       const vlib_buffer_t *cb = b[i];
90       while (cb->flags & VLIB_BUFFER_NEXT_PRESENT)
91         {
92           nc++;
93           cb = vlib_get_buffer (vm, cb->next_buffer);
94         }
95     }
96
97   return n + nc;
98 }
99
100 static uword
101 bufmon_dispatch_wrapper (vlib_main_t *vm, vlib_node_runtime_t *node,
102                          vlib_frame_t *frame)
103 {
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;
108   int pending_frames;
109   uword rv;
110
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);
114
115   if (frame)
116     pnd->in += bufmon_count_buffers (vm, frame);
117
118   pending_frames = vec_len (nm->pending_frames);
119   ptd->cur_node = node->node_index;
120
121   rv = node->function (vm, node, frame);
122
123   ptd->cur_node = ~0;
124   for (; pending_frames < vec_len (nm->pending_frames); pending_frames++)
125     {
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));
129     }
130
131   return rv;
132 }
133
134 static void
135 bufmon_unregister_callbacks (vlib_main_t *vm)
136 {
137   vlib_buffer_set_alloc_free_callback (vm, 0, 0);
138   foreach_vlib_main ()
139     vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
140 }
141
142 static clib_error_t *
143 bufmon_register_callbacks (vlib_main_t *vm)
144 {
145   if (vlib_buffer_set_alloc_free_callback (vm, bufmon_alloc_callback,
146                                            bufmon_free_callback))
147     goto err0;
148
149   foreach_vlib_main ()
150     if (vlib_node_set_dispatch_wrapper (this_vlib_main,
151                                         bufmon_dispatch_wrapper))
152       goto err1;
153
154   vec_validate_aligned (bufmon_main.ptd, vlib_thread_main.n_vlib_mains - 1,
155                         CLIB_CACHE_LINE_BYTES);
156   return 0;
157
158 err1:
159   foreach_vlib_main ()
160     vlib_node_set_dispatch_wrapper (this_vlib_main, 0);
161 err0:
162   vlib_buffer_set_alloc_free_callback (vm, 0, 0);
163   return clib_error_return (0, "failed to register callback");
164 }
165
166 static clib_error_t *
167 bufmon_enable_disable (vlib_main_t *vm, int enable)
168 {
169   bufmon_main_t *bm = &bufmon_main;
170
171   if (enable)
172     {
173       if (bm->enabled)
174         return 0;
175       clib_error_t *error = bufmon_register_callbacks (vm);
176       if (error)
177         return error;
178       bm->enabled = 1;
179     }
180   else
181     {
182       if (!bm->enabled)
183         return 0;
184       bufmon_unregister_callbacks (vm);
185       bm->enabled = 0;
186     }
187
188   return 0;
189 }
190
191 static clib_error_t *
192 set_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
193                    vlib_cli_command_t *cmd)
194 {
195   unformat_input_t _line_input, *line_input = &_line_input;
196   int on = 1;
197
198   if (unformat_user (input, unformat_line_input, line_input))
199     {
200       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
201         {
202           if (unformat (line_input, "on"))
203             on = 1;
204           else if (unformat (line_input, "off"))
205             on = 0;
206           else
207             {
208               unformat_free (line_input);
209               return clib_error_return (0, "unknown input `%U'",
210                                         format_unformat_error, line_input);
211             }
212         }
213       unformat_free (line_input);
214     }
215
216   return bufmon_enable_disable (vm, on);
217 }
218
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,
223 };
224
225 static clib_error_t *
226 show_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
227                     vlib_cli_command_t *cmd)
228 {
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;
233   int verbose = 0;
234   int status = 0;
235
236   if (unformat_user (input, unformat_line_input, line_input))
237     {
238       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
239         {
240           if (unformat (line_input, "verbose"))
241             verbose = 1;
242           else if (unformat (line_input, "status"))
243             status = 1;
244           else
245             {
246               unformat_free (line_input);
247               return clib_error_return (0, "unknown input `%U'",
248                                         format_unformat_error, line_input);
249             }
250         }
251       unformat_free (line_input);
252     }
253
254   if (status)
255     {
256       vlib_cli_output (vm, "buffers tracing is %s",
257                        bm->enabled ? "on" : "off");
258       return 0;
259     }
260
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)
265     {
266       vec_foreach (pnd, ptd->pnd)
267         {
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);
278         }
279     }
280
281   return 0;
282 }
283
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,
288 };
289
290 static clib_error_t *
291 clear_buffer_traces (vlib_main_t *vm, unformat_input_t *input,
292                      vlib_cli_command_t *cmd)
293 {
294   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   vec_foreach (ptd, bm->ptd)
299     vec_foreach (pnd, ptd->pnd)
300       vec_reset_length (pnd);
301
302   return 0;
303 }
304
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,
309 };
310
311 VLIB_PLUGIN_REGISTER () = {
312   .version = VPP_BUILD_VER,
313   .description = "Buffers monitoring plugin",
314 };