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 : * error.c: VLIB error handler
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 <vppinfra/heap.h>
42 : #include <vlib/stats/stats.h>
43 :
44 : uword
45 26 : vlib_error_drop_buffers (vlib_main_t * vm,
46 : vlib_node_runtime_t * node,
47 : u32 * buffers,
48 : u32 next_buffer_stride,
49 : u32 n_buffers,
50 : u32 next_index,
51 : u32 drop_error_node, u32 drop_error_code)
52 : {
53 : u32 n_left_this_frame, n_buffers_left, *args, n_args_left;
54 : vlib_error_t drop_error;
55 : vlib_node_t *n;
56 :
57 26 : n = vlib_get_node (vm, drop_error_node);
58 26 : drop_error = n->error_heap_index + drop_error_code;
59 :
60 26 : n_buffers_left = n_buffers;
61 52 : while (n_buffers_left > 0)
62 : {
63 26 : vlib_get_next_frame (vm, node, next_index, args, n_args_left);
64 :
65 26 : n_left_this_frame = clib_min (n_buffers_left, n_args_left);
66 26 : n_buffers_left -= n_left_this_frame;
67 26 : n_args_left -= n_left_this_frame;
68 :
69 154 : while (n_left_this_frame >= 4)
70 : {
71 : u32 bi0, bi1, bi2, bi3;
72 : vlib_buffer_t *b0, *b1, *b2, *b3;
73 :
74 128 : args[0] = bi0 = buffers[0];
75 128 : args[1] = bi1 = buffers[1];
76 128 : args[2] = bi2 = buffers[2];
77 128 : args[3] = bi3 = buffers[3];
78 :
79 128 : b0 = vlib_get_buffer (vm, bi0);
80 128 : b1 = vlib_get_buffer (vm, bi1);
81 128 : b2 = vlib_get_buffer (vm, bi2);
82 128 : b3 = vlib_get_buffer (vm, bi3);
83 :
84 128 : b0->error = drop_error;
85 128 : b1->error = drop_error;
86 128 : b2->error = drop_error;
87 128 : b3->error = drop_error;
88 :
89 128 : buffers += 4;
90 128 : args += 4;
91 128 : n_left_this_frame -= 4;
92 : }
93 :
94 51 : while (n_left_this_frame >= 1)
95 : {
96 : u32 bi0;
97 : vlib_buffer_t *b0;
98 :
99 25 : args[0] = bi0 = buffers[0];
100 :
101 25 : b0 = vlib_get_buffer (vm, bi0);
102 25 : b0->error = drop_error;
103 :
104 25 : buffers += 1;
105 25 : args += 1;
106 25 : n_left_this_frame -= 1;
107 : }
108 :
109 26 : vlib_put_next_frame (vm, node, next_index, n_args_left);
110 : }
111 :
112 26 : return n_buffers;
113 : }
114 :
115 : static u8 *
116 2278460 : format_stats_counter_name (u8 *s, va_list *va)
117 : {
118 2278460 : u8 *id = va_arg (*va, u8 *);
119 :
120 38557100 : for (u32 i = 0; id[i] != 0; i++)
121 36278600 : vec_add1 (s, id[i] == ' ' ? ' ' : id[i]);
122 :
123 2278460 : return s;
124 : }
125 :
126 : void
127 418928 : vlib_unregister_errors (vlib_main_t *vm, u32 node_index)
128 : {
129 418928 : vlib_error_main_t *em = &vm->error_main;
130 418928 : vlib_node_t *n = vlib_get_node (vm, node_index);
131 : vlib_error_desc_t *cd;
132 :
133 418928 : if (n->n_errors > 0)
134 : {
135 741 : cd = vec_elt_at_index (em->counters_heap, n->error_heap_index);
136 4713 : for (u32 i = 0; i < n->n_errors; i++)
137 3972 : vlib_stats_remove_entry (cd[i].stats_entry_index);
138 741 : heap_dealloc (em->counters_heap, n->error_heap_handle);
139 741 : n->n_errors = 0;
140 : }
141 418928 : }
142 :
143 : /* Reserves given number of error codes for given node. */
144 : void
145 417408 : vlib_register_errors (vlib_main_t *vm, u32 node_index, u32 n_errors,
146 : char *error_strings[], vlib_error_desc_t counters[])
147 : {
148 417408 : vlib_error_main_t *em = &vm->error_main;
149 417408 : vlib_node_main_t *nm = &vm->node_main;
150 417408 : vlib_node_t *n = vlib_get_node (vm, node_index);
151 : vlib_error_desc_t *cd;
152 417408 : u32 n_threads = vlib_get_n_threads ();
153 417408 : elog_event_type_t t = {};
154 : uword l;
155 : u64 **sc;
156 :
157 417408 : ASSERT (vlib_get_thread_index () == 0);
158 :
159 417408 : vlib_stats_segment_lock ();
160 :
161 : /* Free up any previous error strings. */
162 417408 : vlib_unregister_errors (vm, node_index);
163 :
164 417408 : n->n_errors = n_errors;
165 417408 : n->error_counters = counters;
166 :
167 417408 : if (n_errors == 0)
168 135616 : goto done;
169 :
170 281792 : n->error_heap_index =
171 281792 : heap_alloc (em->counters_heap, n_errors, n->error_heap_handle);
172 281792 : l = vec_len (em->counters_heap);
173 281792 : cd = vec_elt_at_index (em->counters_heap, n->error_heap_index);
174 :
175 : /* Legacy node */
176 281792 : if (!counters)
177 : {
178 955921 : for (int i = 0; i < n_errors; i++)
179 : {
180 747182 : cd[i].name = error_strings[i];
181 747182 : cd[i].desc = error_strings[i];
182 747182 : cd[i].severity = VL_COUNTER_SEVERITY_ERROR;
183 : }
184 : }
185 : else
186 73053 : clib_memcpy (cd, counters, n_errors * sizeof (counters[0]));
187 :
188 281792 : vec_validate (vm->error_elog_event_types, l - 1);
189 :
190 281792 : if (em->stats_err_entry_index == 0)
191 575 : em->stats_err_entry_index = vlib_stats_add_counter_vector ("/node/errors");
192 :
193 281792 : ASSERT (em->stats_err_entry_index != 0 && em->stats_err_entry_index != ~0);
194 :
195 281792 : vlib_stats_validate (em->stats_err_entry_index, n_threads - 1, l - 1);
196 281792 : sc = vlib_stats_get_entry_data_pointer (em->stats_err_entry_index);
197 :
198 563760 : for (int i = 0; i < n_threads; i++)
199 : {
200 281968 : vlib_main_t *tvm = vlib_get_main_by_index (i);
201 281968 : vlib_error_main_t *tem = &tvm->error_main;
202 281968 : tem->counters = sc[i];
203 :
204 : /* Zero counters for re-registrations of errors. */
205 281968 : if (n->error_heap_index + n_errors <= vec_len (tem->counters_last_clear))
206 0 : clib_memcpy (tem->counters + n->error_heap_index,
207 : tem->counters_last_clear + n->error_heap_index,
208 : n_errors * sizeof (tem->counters[0]));
209 : else
210 281968 : clib_memset (tem->counters + n->error_heap_index, 0,
211 : n_errors * sizeof (tem->counters[0]));
212 : }
213 :
214 : /* Register counter indices in the stat segment directory */
215 2560260 : for (int i = 0; i < n_errors; i++)
216 2278460 : cd[i].stats_entry_index = vlib_stats_add_symlink (
217 2278460 : em->stats_err_entry_index, n->error_heap_index + i, "/err/%v/%U",
218 2278460 : n->name, format_stats_counter_name, cd[i].name);
219 :
220 281792 : vec_validate (nm->node_by_error, n->error_heap_index + n_errors - 1);
221 :
222 2560260 : for (u32 i = 0; i < n_errors; i++)
223 : {
224 2278460 : t.format = (char *) format (0, "%v %s: %%d", n->name, cd[i].name);
225 2278460 : vec_free (vm->error_elog_event_types[n->error_heap_index + i].format);
226 2278460 : vm->error_elog_event_types[n->error_heap_index + i] = t;
227 2278460 : nm->node_by_error[n->error_heap_index + i] = n->index;
228 : }
229 :
230 281792 : done:
231 417408 : vlib_stats_segment_unlock ();
232 417408 : }
233 :
234 : uword
235 4 : unformat_vlib_error (unformat_input_t *input, va_list *args)
236 : {
237 4 : vlib_main_t *vm = va_arg (*args, vlib_main_t *);
238 4 : const vlib_error_main_t *em = &vm->error_main;
239 4 : vlib_error_t *error_index = va_arg (*args, vlib_error_t *);
240 : const vlib_node_t *node;
241 : char *error_name;
242 : u32 node_index;
243 : vlib_error_t i;
244 :
245 4 : if (!unformat (input, "%U.%s", unformat_vlib_node, vm, &node_index,
246 : &error_name))
247 2 : return 0;
248 :
249 2 : node = vlib_get_node (vm, node_index);
250 22 : for (i = 0; i < node->n_errors; i++)
251 : {
252 22 : vlib_error_t ei = node->error_heap_index + i;
253 22 : if (strcmp (em->counters_heap[ei].name, error_name) == 0)
254 : {
255 2 : *error_index = ei;
256 2 : vec_free (error_name);
257 2 : return 1;
258 : }
259 : }
260 :
261 0 : vec_free (error_name);
262 0 : return 0;
263 : }
264 :
265 : static char *
266 54781 : sev2str (enum vl_counter_severity_e s)
267 : {
268 54781 : switch (s)
269 : {
270 30941 : case VL_COUNTER_SEVERITY_ERROR:
271 30941 : return "error";
272 0 : case VL_COUNTER_SEVERITY_WARN:
273 0 : return "warn";
274 23840 : case VL_COUNTER_SEVERITY_INFO:
275 23840 : return "info";
276 0 : default:
277 0 : return "unknown";
278 : }
279 : }
280 :
281 : static clib_error_t *
282 8013 : show_errors (vlib_main_t * vm,
283 : unformat_input_t * input, vlib_cli_command_t * cmd)
284 : {
285 8013 : vlib_error_main_t *em = &vm->error_main;
286 : vlib_node_t *n;
287 : u32 code, i, ni;
288 : u64 c;
289 8013 : int index = 0;
290 8013 : int verbose = 0;
291 8013 : u64 *sums = 0;
292 :
293 8013 : if (unformat (input, "verbose %d", &verbose))
294 : ;
295 8013 : else if (unformat (input, "verbose"))
296 0 : verbose = 1;
297 :
298 8013 : vec_validate (sums, vec_len (em->counters));
299 :
300 8013 : if (verbose)
301 0 : vlib_cli_output (vm, "%=10s%=35s%=35s%=10s%=6s", "Count", "Node",
302 : "Reason", "Severity", "Index");
303 : else
304 8013 : vlib_cli_output (vm, "%=10s%=35s%=35s%=10s", "Count", "Node", "Reason",
305 : "Severity");
306 :
307 16050 : foreach_vlib_main ()
308 : {
309 8037 : em = &this_vlib_main->error_main;
310 :
311 8037 : if (verbose)
312 0 : vlib_cli_output (vm, "Thread %u (%v):", index,
313 0 : vlib_worker_threads[index].name);
314 :
315 5802730 : for (ni = 0; ni < vec_len (this_vlib_main->node_main.nodes); ni++)
316 : {
317 5794690 : n = vlib_get_node (this_vlib_main, ni);
318 37589100 : for (code = 0; code < n->n_errors; code++)
319 : {
320 31794400 : i = n->error_heap_index + code;
321 31794400 : c = em->counters[i];
322 31794400 : if (i < vec_len (em->counters_last_clear))
323 31592600 : c -= em->counters_last_clear[i];
324 31794400 : sums[i] += c;
325 :
326 31794400 : if (c == 0 && verbose < 2)
327 31739600 : continue;
328 :
329 54781 : if (verbose)
330 0 : vlib_cli_output (vm, "%10lu%=35v%=35s%=10s%=6d", c, n->name,
331 0 : em->counters_heap[i].desc,
332 0 : sev2str (em->counters_heap[i].severity), i);
333 : else
334 109562 : vlib_cli_output (vm, "%10lu%=35v%=35s%=10s", c, n->name,
335 54781 : em->counters_heap[i].desc,
336 54781 : sev2str (em->counters_heap[i].severity));
337 : }
338 : }
339 8037 : index++;
340 : }
341 :
342 8013 : if (verbose)
343 0 : vlib_cli_output (vm, "Total:");
344 :
345 5785400 : for (ni = 0; ni < vec_len (vm->node_main.nodes); ni++)
346 : {
347 5777390 : n = vlib_get_node (vm, ni);
348 37476800 : for (code = 0; code < n->n_errors; code++)
349 : {
350 31699400 : i = n->error_heap_index + code;
351 31699400 : if (sums[i])
352 : {
353 54729 : if (verbose)
354 0 : vlib_cli_output (vm, "%10lu%=40v%=20s%=10d", sums[i], n->name,
355 0 : em->counters_heap[i].desc, i);
356 : }
357 : }
358 : }
359 :
360 8013 : vec_free (sums);
361 :
362 8013 : return 0;
363 : }
364 :
365 : /* *INDENT-OFF* */
366 285289 : VLIB_CLI_COMMAND (vlib_cli_show_errors) = {
367 : .path = "show errors",
368 : .short_help = "Show error counts",
369 : .function = show_errors,
370 : };
371 : /* *INDENT-ON* */
372 :
373 : /* *INDENT-OFF* */
374 285289 : VLIB_CLI_COMMAND (cli_show_node_counters, static) = {
375 : .path = "show node counters",
376 : .short_help = "Show node counters",
377 : .function = show_errors,
378 : };
379 : /* *INDENT-ON* */
380 :
381 : static clib_error_t *
382 2942 : clear_error_counters (vlib_main_t * vm,
383 : unformat_input_t * input, vlib_cli_command_t * cmd)
384 : {
385 : vlib_error_main_t *em;
386 : u32 i;
387 :
388 5900 : foreach_vlib_main ()
389 : {
390 2958 : em = &this_vlib_main->error_main;
391 2958 : vec_validate (em->counters_last_clear, vec_len (em->counters) - 1);
392 11704800 : for (i = 0; i < vec_len (em->counters); i++)
393 11701800 : em->counters_last_clear[i] = em->counters[i];
394 : }
395 2942 : return 0;
396 : }
397 :
398 : /* *INDENT-OFF* */
399 285289 : VLIB_CLI_COMMAND (cli_clear_error_counters, static) = {
400 : .path = "clear errors",
401 : .short_help = "Clear error counters",
402 : .function = clear_error_counters,
403 : };
404 : /* *INDENT-ON* */
405 :
406 : /* *INDENT-OFF* */
407 285289 : VLIB_CLI_COMMAND (cli_clear_node_counters, static) = {
408 : .path = "clear node counters",
409 : .short_help = "Clear node counters",
410 : .function = clear_error_counters,
411 : };
412 : /* *INDENT-ON* */
413 :
414 : /*
415 : * fd.io coding-style-patch-verification: ON
416 : *
417 : * Local Variables:
418 : * eval: (c-set-style "gnu")
419 : * End:
420 : */
|