cdf18738193b5bc54241ca893ccf3b228897e84a
[vpp.git] / src / vnet / interface_output.c
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  * interface_output.c: interface output node
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 <vnet/vnet.h>
41 #include <vnet/feature/feature.h>
42
43 typedef struct
44 {
45   u32 sw_if_index;
46   u8 data[128 - sizeof (u32)];
47 }
48 interface_output_trace_t;
49
50 u8 *
51 format_vnet_interface_output_trace (u8 * s, va_list * va)
52 {
53   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
54   vlib_node_t *node = va_arg (*va, vlib_node_t *);
55   interface_output_trace_t *t = va_arg (*va, interface_output_trace_t *);
56   vnet_main_t *vnm = vnet_get_main ();
57   vnet_sw_interface_t *si;
58   uword indent;
59
60   if (t->sw_if_index != (u32) ~ 0)
61     {
62       indent = format_get_indent (s);
63
64       if (pool_is_free_index
65           (vnm->interface_main.sw_interfaces, t->sw_if_index))
66         {
67           /* the interface may have been deleted by the time the trace is printed */
68           s = format (s, "sw_if_index: %d\n%U%U",
69                       t->sw_if_index,
70                       format_white_space, indent,
71                       node->format_buffer ? node->
72                       format_buffer : format_hex_bytes, t->data,
73                       sizeof (t->data));
74         }
75       else
76         {
77           si = vnet_get_sw_interface (vnm, t->sw_if_index);
78
79           s = format (s, "%U\n%U%U",
80                       format_vnet_sw_interface_name, vnm, si,
81                       format_white_space, indent,
82                       node->format_buffer ? node->
83                       format_buffer : format_hex_bytes, t->data,
84                       sizeof (t->data));
85         }
86     }
87   return s;
88 }
89
90 static void
91 vnet_interface_output_trace (vlib_main_t * vm,
92                              vlib_node_runtime_t * node,
93                              vlib_frame_t * frame, uword n_buffers)
94 {
95   u32 n_left, *from;
96
97   n_left = n_buffers;
98   from = vlib_frame_args (frame);
99
100   while (n_left >= 4)
101     {
102       u32 bi0, bi1;
103       vlib_buffer_t *b0, *b1;
104       interface_output_trace_t *t0, *t1;
105
106       /* Prefetch next iteration. */
107       vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
108       vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
109
110       bi0 = from[0];
111       bi1 = from[1];
112
113       b0 = vlib_get_buffer (vm, bi0);
114       b1 = vlib_get_buffer (vm, bi1);
115
116       if (b0->flags & VLIB_BUFFER_IS_TRACED)
117         {
118           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
119           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
120           clib_memcpy (t0->data, vlib_buffer_get_current (b0),
121                        sizeof (t0->data));
122         }
123       if (b1->flags & VLIB_BUFFER_IS_TRACED)
124         {
125           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
126           t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX];
127           clib_memcpy (t1->data, vlib_buffer_get_current (b1),
128                        sizeof (t1->data));
129         }
130       from += 2;
131       n_left -= 2;
132     }
133
134   while (n_left >= 1)
135     {
136       u32 bi0;
137       vlib_buffer_t *b0;
138       interface_output_trace_t *t0;
139
140       bi0 = from[0];
141
142       b0 = vlib_get_buffer (vm, bi0);
143
144       if (b0->flags & VLIB_BUFFER_IS_TRACED)
145         {
146           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
147           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
148           clib_memcpy (t0->data, vlib_buffer_get_current (b0),
149                        sizeof (t0->data));
150         }
151       from += 1;
152       n_left -= 1;
153     }
154 }
155
156 uword
157 vnet_interface_output_node (vlib_main_t * vm,
158                             vlib_node_runtime_t * node, vlib_frame_t * frame)
159 {
160   vnet_main_t *vnm = vnet_get_main ();
161   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
162   vnet_sw_interface_t *si;
163   vnet_hw_interface_t *hi;
164   u32 n_left_to_tx, *from, *from_end, *to_tx;
165   u32 n_bytes, n_buffers, n_packets;
166   u32 n_bytes_b0, n_bytes_b1, n_bytes_b2, n_bytes_b3;
167   u32 thread_index = vm->thread_index;
168   vnet_interface_main_t *im = &vnm->interface_main;
169   u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
170   u32 current_config_index = ~0;
171   u8 arc = im->output_feature_arc_index;
172
173   n_buffers = frame->n_vectors;
174
175   if (node->flags & VLIB_NODE_FLAG_TRACE)
176     vnet_interface_output_trace (vm, node, frame, n_buffers);
177
178   from = vlib_frame_args (frame);
179
180   if (rt->is_deleted)
181     return vlib_error_drop_buffers (vm, node, from,
182                                     /* buffer stride */ 1,
183                                     n_buffers,
184                                     VNET_INTERFACE_OUTPUT_NEXT_DROP,
185                                     node->node_index,
186                                     VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
187
188   si = vnet_get_sw_interface (vnm, rt->sw_if_index);
189   hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
190   if (!(si->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP |
191                      VNET_SW_INTERFACE_FLAG_BOND_SLAVE)) ||
192       !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
193     {
194       vlib_simple_counter_main_t *cm;
195
196       cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
197                              VNET_INTERFACE_COUNTER_TX_ERROR);
198       vlib_increment_simple_counter (cm, thread_index,
199                                      rt->sw_if_index, n_buffers);
200
201       return vlib_error_drop_buffers (vm, node, from,
202                                       /* buffer stride */ 1,
203                                       n_buffers,
204                                       VNET_INTERFACE_OUTPUT_NEXT_DROP,
205                                       node->node_index,
206                                       VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
207     }
208
209   from_end = from + n_buffers;
210
211   /* Total byte count of all buffers. */
212   n_bytes = 0;
213   n_packets = 0;
214
215   /* interface-output feature arc handling */
216   if (PREDICT_FALSE (vnet_have_features (arc, rt->sw_if_index)))
217     {
218       vnet_feature_config_main_t *fcm;
219       fcm = vnet_feature_get_config_main (arc);
220       current_config_index = vnet_get_feature_config_index (arc,
221                                                             rt->sw_if_index);
222       vnet_get_config_data (&fcm->config_main, &current_config_index,
223                             &next_index, 0);
224     }
225
226   while (from < from_end)
227     {
228       /* Get new next frame since previous incomplete frame may have less
229          than VNET_FRAME_SIZE vectors in it. */
230       vlib_get_new_next_frame (vm, node, next_index, to_tx, n_left_to_tx);
231
232       while (from + 8 <= from_end && n_left_to_tx >= 4)
233         {
234           u32 bi0, bi1, bi2, bi3;
235           vlib_buffer_t *b0, *b1, *b2, *b3;
236           u32 tx_swif0, tx_swif1, tx_swif2, tx_swif3;
237
238           /* Prefetch next iteration. */
239           vlib_prefetch_buffer_with_index (vm, from[4], LOAD);
240           vlib_prefetch_buffer_with_index (vm, from[5], LOAD);
241           vlib_prefetch_buffer_with_index (vm, from[6], LOAD);
242           vlib_prefetch_buffer_with_index (vm, from[7], LOAD);
243
244           bi0 = from[0];
245           bi1 = from[1];
246           bi2 = from[2];
247           bi3 = from[3];
248           to_tx[0] = bi0;
249           to_tx[1] = bi1;
250           to_tx[2] = bi2;
251           to_tx[3] = bi3;
252           from += 4;
253           to_tx += 4;
254           n_left_to_tx -= 4;
255
256           b0 = vlib_get_buffer (vm, bi0);
257           b1 = vlib_get_buffer (vm, bi1);
258           b2 = vlib_get_buffer (vm, bi2);
259           b3 = vlib_get_buffer (vm, bi3);
260
261           /* Be grumpy about zero length buffers for benefit of
262              driver tx function. */
263           ASSERT (b0->current_length > 0);
264           ASSERT (b1->current_length > 0);
265           ASSERT (b2->current_length > 0);
266           ASSERT (b3->current_length > 0);
267
268           n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
269           n_bytes_b1 = vlib_buffer_length_in_chain (vm, b1);
270           n_bytes_b2 = vlib_buffer_length_in_chain (vm, b2);
271           n_bytes_b3 = vlib_buffer_length_in_chain (vm, b3);
272           tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
273           tx_swif1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
274           tx_swif2 = vnet_buffer (b2)->sw_if_index[VLIB_TX];
275           tx_swif3 = vnet_buffer (b3)->sw_if_index[VLIB_TX];
276
277           n_bytes += n_bytes_b0 + n_bytes_b1;
278           n_bytes += n_bytes_b2 + n_bytes_b3;
279           n_packets += 4;
280
281           if (PREDICT_FALSE (current_config_index != ~0))
282             {
283               b0->feature_arc_index = arc;
284               b1->feature_arc_index = arc;
285               b2->feature_arc_index = arc;
286               b3->feature_arc_index = arc;
287               b0->current_config_index = current_config_index;
288               b1->current_config_index = current_config_index;
289               b2->current_config_index = current_config_index;
290               b3->current_config_index = current_config_index;
291             }
292
293           /* update vlan subif tx counts, if required */
294           if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
295             {
296               vlib_increment_combined_counter (im->combined_sw_if_counters +
297                                                VNET_INTERFACE_COUNTER_TX,
298                                                thread_index, tx_swif0, 1,
299                                                n_bytes_b0);
300             }
301
302           if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
303             {
304
305               vlib_increment_combined_counter (im->combined_sw_if_counters +
306                                                VNET_INTERFACE_COUNTER_TX,
307                                                thread_index, tx_swif1, 1,
308                                                n_bytes_b1);
309             }
310
311           if (PREDICT_FALSE (tx_swif2 != rt->sw_if_index))
312             {
313
314               vlib_increment_combined_counter (im->combined_sw_if_counters +
315                                                VNET_INTERFACE_COUNTER_TX,
316                                                thread_index, tx_swif2, 1,
317                                                n_bytes_b2);
318             }
319           if (PREDICT_FALSE (tx_swif3 != rt->sw_if_index))
320             {
321
322               vlib_increment_combined_counter (im->combined_sw_if_counters +
323                                                VNET_INTERFACE_COUNTER_TX,
324                                                thread_index, tx_swif3, 1,
325                                                n_bytes_b3);
326             }
327         }
328
329       while (from + 1 <= from_end && n_left_to_tx >= 1)
330         {
331           u32 bi0;
332           vlib_buffer_t *b0;
333           u32 tx_swif0;
334
335           bi0 = from[0];
336           to_tx[0] = bi0;
337           from += 1;
338           to_tx += 1;
339           n_left_to_tx -= 1;
340
341           b0 = vlib_get_buffer (vm, bi0);
342
343           /* Be grumpy about zero length buffers for benefit of
344              driver tx function. */
345           ASSERT (b0->current_length > 0);
346
347           n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
348           tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
349           n_bytes += n_bytes_b0;
350           n_packets += 1;
351
352           if (PREDICT_FALSE (current_config_index != ~0))
353             {
354               b0->feature_arc_index = arc;
355               b0->current_config_index = current_config_index;
356             }
357
358           if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
359             {
360
361               vlib_increment_combined_counter (im->combined_sw_if_counters +
362                                                VNET_INTERFACE_COUNTER_TX,
363                                                thread_index, tx_swif0, 1,
364                                                n_bytes_b0);
365             }
366         }
367
368       vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
369     }
370
371   /* Update main interface stats. */
372   vlib_increment_combined_counter (im->combined_sw_if_counters
373                                    + VNET_INTERFACE_COUNTER_TX,
374                                    thread_index,
375                                    rt->sw_if_index, n_packets, n_bytes);
376   return n_buffers;
377 }
378
379 VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
380 CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
381
382 /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
383 static uword
384 vnet_per_buffer_interface_output (vlib_main_t * vm,
385                                   vlib_node_runtime_t * node,
386                                   vlib_frame_t * frame)
387 {
388   vnet_main_t *vnm = vnet_get_main ();
389   u32 n_left_to_next, *from, *to_next;
390   u32 n_left_from, next_index;
391
392   n_left_from = frame->n_vectors;
393
394   from = vlib_frame_args (frame);
395   next_index = node->cached_next_index;
396
397   while (n_left_from > 0)
398     {
399       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
400
401       while (n_left_from >= 4 && n_left_to_next >= 2)
402         {
403           u32 bi0, bi1, next0, next1;
404           vlib_buffer_t *b0, *b1;
405           vnet_hw_interface_t *hi0, *hi1;
406
407           /* Prefetch next iteration. */
408           vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
409           vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
410
411           bi0 = from[0];
412           bi1 = from[1];
413           to_next[0] = bi0;
414           to_next[1] = bi1;
415           from += 2;
416           to_next += 2;
417           n_left_to_next -= 2;
418           n_left_from -= 2;
419
420           b0 = vlib_get_buffer (vm, bi0);
421           b1 = vlib_get_buffer (vm, bi1);
422
423           hi0 =
424             vnet_get_sup_hw_interface (vnm,
425                                        vnet_buffer (b0)->sw_if_index
426                                        [VLIB_TX]);
427           hi1 =
428             vnet_get_sup_hw_interface (vnm,
429                                        vnet_buffer (b1)->sw_if_index
430                                        [VLIB_TX]);
431
432           next0 = hi0->hw_if_index;
433           next1 = hi1->hw_if_index;
434
435           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
436                                            n_left_to_next, bi0, bi1, next0,
437                                            next1);
438         }
439
440       while (n_left_from > 0 && n_left_to_next > 0)
441         {
442           u32 bi0, next0;
443           vlib_buffer_t *b0;
444           vnet_hw_interface_t *hi0;
445
446           bi0 = from[0];
447           to_next[0] = bi0;
448           from += 1;
449           to_next += 1;
450           n_left_to_next -= 1;
451           n_left_from -= 1;
452
453           b0 = vlib_get_buffer (vm, bi0);
454
455           hi0 =
456             vnet_get_sup_hw_interface (vnm,
457                                        vnet_buffer (b0)->sw_if_index
458                                        [VLIB_TX]);
459
460           next0 = hi0->hw_if_index;
461
462           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
463                                            n_left_to_next, bi0, next0);
464         }
465
466       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
467     }
468
469   return frame->n_vectors;
470 }
471
472 always_inline u32
473 counter_index (vlib_main_t * vm, vlib_error_t e)
474 {
475   vlib_node_t *n;
476   u32 ci, ni;
477
478   ni = vlib_error_get_node (e);
479   n = vlib_get_node (vm, ni);
480
481   ci = vlib_error_get_code (e);
482   ASSERT (ci < n->n_errors);
483
484   ci += n->error_heap_index;
485
486   return ci;
487 }
488
489 static u8 *
490 format_vnet_error_trace (u8 * s, va_list * va)
491 {
492   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
493   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
494   vlib_error_t *e = va_arg (*va, vlib_error_t *);
495   vlib_node_t *error_node;
496   vlib_error_main_t *em = &vm->error_main;
497   u32 i;
498
499   error_node = vlib_get_node (vm, vlib_error_get_node (e[0]));
500   i = counter_index (vm, e[0]);
501   s = format (s, "%v: %s", error_node->name, em->error_strings_heap[i]);
502
503   return s;
504 }
505
506 static void
507 trace_errors_with_buffers (vlib_main_t * vm,
508                            vlib_node_runtime_t * node, vlib_frame_t * frame)
509 {
510   u32 n_left, *buffers;
511
512   buffers = vlib_frame_vector_args (frame);
513   n_left = frame->n_vectors;
514
515   while (n_left >= 4)
516     {
517       u32 bi0, bi1;
518       vlib_buffer_t *b0, *b1;
519       vlib_error_t *t0, *t1;
520
521       /* Prefetch next iteration. */
522       vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
523       vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
524
525       bi0 = buffers[0];
526       bi1 = buffers[1];
527
528       b0 = vlib_get_buffer (vm, bi0);
529       b1 = vlib_get_buffer (vm, bi1);
530
531       if (b0->flags & VLIB_BUFFER_IS_TRACED)
532         {
533           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
534           t0[0] = b0->error;
535         }
536       if (b1->flags & VLIB_BUFFER_IS_TRACED)
537         {
538           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
539           t1[0] = b1->error;
540         }
541       buffers += 2;
542       n_left -= 2;
543     }
544
545   while (n_left >= 1)
546     {
547       u32 bi0;
548       vlib_buffer_t *b0;
549       vlib_error_t *t0;
550
551       bi0 = buffers[0];
552
553       b0 = vlib_get_buffer (vm, bi0);
554
555       if (b0->flags & VLIB_BUFFER_IS_TRACED)
556         {
557           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
558           t0[0] = b0->error;
559         }
560       buffers += 1;
561       n_left -= 1;
562     }
563 }
564
565 static u8 *
566 validate_error (vlib_main_t * vm, vlib_error_t * e, u32 index)
567 {
568   uword node_index = vlib_error_get_node (e[0]);
569   uword code = vlib_error_get_code (e[0]);
570   vlib_node_t *n;
571
572   if (node_index >= vec_len (vm->node_main.nodes))
573     return format (0, "[%d], node index out of range 0x%x, error 0x%x",
574                    index, node_index, e[0]);
575
576   n = vlib_get_node (vm, node_index);
577   if (code >= n->n_errors)
578     return format (0, "[%d], code %d out of range for node %v",
579                    index, code, n->name);
580
581   return 0;
582 }
583
584 static u8 *
585 validate_error_frame (vlib_main_t * vm,
586                       vlib_node_runtime_t * node, vlib_frame_t * f)
587 {
588   u32 *buffers = vlib_frame_args (f);
589   vlib_buffer_t *b;
590   u8 *msg = 0;
591   uword i;
592
593   for (i = 0; i < f->n_vectors; i++)
594     {
595       b = vlib_get_buffer (vm, buffers[i]);
596       msg = validate_error (vm, &b->error, i);
597       if (msg)
598         return msg;
599     }
600
601   return msg;
602 }
603
604 typedef enum
605 {
606   VNET_ERROR_DISPOSITION_DROP,
607   VNET_ERROR_DISPOSITION_PUNT,
608   VNET_ERROR_N_DISPOSITION,
609 } vnet_error_disposition_t;
610
611 always_inline void
612 do_packet (vlib_main_t * vm, vlib_error_t a)
613 {
614   vlib_error_main_t *em = &vm->error_main;
615   u32 i = counter_index (vm, a);
616   em->counters[i] += 1;
617   vlib_error_elog_count (vm, i, 1);
618 }
619
620 static_always_inline uword
621 process_drop_punt (vlib_main_t * vm,
622                    vlib_node_runtime_t * node,
623                    vlib_frame_t * frame, vnet_error_disposition_t disposition)
624 {
625   vnet_main_t *vnm = vnet_get_main ();
626   vlib_error_main_t *em = &vm->error_main;
627   u32 *buffers, *first_buffer;
628   vlib_error_t current_error;
629   u32 current_counter_index, n_errors_left;
630   u32 current_sw_if_index, n_errors_current_sw_if_index;
631   u64 current_counter;
632   vlib_simple_counter_main_t *cm;
633   u32 thread_index = vm->thread_index;
634
635   static vlib_error_t memory[VNET_ERROR_N_DISPOSITION];
636   static char memory_init[VNET_ERROR_N_DISPOSITION];
637
638   buffers = vlib_frame_args (frame);
639   first_buffer = buffers;
640
641   {
642     vlib_buffer_t *b = vlib_get_buffer (vm, first_buffer[0]);
643
644     if (!memory_init[disposition])
645       {
646         memory_init[disposition] = 1;
647         memory[disposition] = b->error;
648       }
649
650     current_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
651     n_errors_current_sw_if_index = 0;
652   }
653
654   current_error = memory[disposition];
655   current_counter_index = counter_index (vm, memory[disposition]);
656   current_counter = em->counters[current_counter_index];
657
658   if (node->flags & VLIB_NODE_FLAG_TRACE)
659     trace_errors_with_buffers (vm, node, frame);
660
661   n_errors_left = frame->n_vectors;
662   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
663                          (disposition == VNET_ERROR_DISPOSITION_PUNT
664                           ? VNET_INTERFACE_COUNTER_PUNT
665                           : VNET_INTERFACE_COUNTER_DROP));
666
667   while (n_errors_left >= 2)
668     {
669       vlib_buffer_t *b0, *b1;
670       vnet_sw_interface_t *sw_if0, *sw_if1;
671       vlib_error_t e0, e1;
672       u32 bi0, bi1;
673       u32 sw_if_index0, sw_if_index1;
674
675       bi0 = buffers[0];
676       bi1 = buffers[1];
677
678       buffers += 2;
679       n_errors_left -= 2;
680
681       b0 = vlib_get_buffer (vm, bi0);
682       b1 = vlib_get_buffer (vm, bi1);
683
684       e0 = b0->error;
685       e1 = b1->error;
686
687       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
688       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
689
690       /* Speculate that sw_if_index == sw_if_index[01]. */
691       n_errors_current_sw_if_index += 2;
692
693       /* Speculatively assume all 2 (node, code) pairs are equal
694          to current (node, code). */
695       current_counter += 2;
696
697       if (PREDICT_FALSE (e0 != current_error
698                          || e1 != current_error
699                          || sw_if_index0 != current_sw_if_index
700                          || sw_if_index1 != current_sw_if_index))
701         {
702           current_counter -= 2;
703           n_errors_current_sw_if_index -= 2;
704
705           vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
706           vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
707
708           /* Increment super-interface drop/punt counters for
709              sub-interfaces. */
710           sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
711           vlib_increment_simple_counter
712             (cm, thread_index, sw_if0->sup_sw_if_index,
713              sw_if0->sup_sw_if_index != sw_if_index0);
714
715           sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1);
716           vlib_increment_simple_counter
717             (cm, thread_index, sw_if1->sup_sw_if_index,
718              sw_if1->sup_sw_if_index != sw_if_index1);
719
720           em->counters[current_counter_index] = current_counter;
721           do_packet (vm, e0);
722           do_packet (vm, e1);
723
724           /* For 2 repeated errors, change current error. */
725           if (e0 == e1 && e1 != current_error)
726             {
727               current_error = e0;
728               current_counter_index = counter_index (vm, e0);
729             }
730           current_counter = em->counters[current_counter_index];
731         }
732     }
733
734   while (n_errors_left >= 1)
735     {
736       vlib_buffer_t *b0;
737       vnet_sw_interface_t *sw_if0;
738       vlib_error_t e0;
739       u32 bi0, sw_if_index0;
740
741       bi0 = buffers[0];
742
743       buffers += 1;
744       n_errors_left -= 1;
745       current_counter += 1;
746
747       b0 = vlib_get_buffer (vm, bi0);
748       e0 = b0->error;
749
750       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
751
752       /* Increment drop/punt counters. */
753       vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
754
755       /* Increment super-interface drop/punt counters for sub-interfaces. */
756       sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
757       vlib_increment_simple_counter (cm, thread_index,
758                                      sw_if0->sup_sw_if_index,
759                                      sw_if0->sup_sw_if_index != sw_if_index0);
760
761       if (PREDICT_FALSE (e0 != current_error))
762         {
763           current_counter -= 1;
764
765           vlib_error_elog_count (vm, current_counter_index,
766                                  (current_counter
767                                   - em->counters[current_counter_index]));
768
769           em->counters[current_counter_index] = current_counter;
770
771           do_packet (vm, e0);
772           current_error = e0;
773           current_counter_index = counter_index (vm, e0);
774           current_counter = em->counters[current_counter_index];
775         }
776     }
777
778   if (n_errors_current_sw_if_index > 0)
779     {
780       vnet_sw_interface_t *si;
781
782       vlib_increment_simple_counter (cm, thread_index, current_sw_if_index,
783                                      n_errors_current_sw_if_index);
784
785       si = vnet_get_sw_interface (vnm, current_sw_if_index);
786       if (si->sup_sw_if_index != current_sw_if_index)
787         vlib_increment_simple_counter (cm, thread_index, si->sup_sw_if_index,
788                                        n_errors_current_sw_if_index);
789     }
790
791   vlib_error_elog_count (vm, current_counter_index,
792                          (current_counter
793                           - em->counters[current_counter_index]));
794
795   /* Return cached counter. */
796   em->counters[current_counter_index] = current_counter;
797
798   /* Save memory for next iteration. */
799   memory[disposition] = current_error;
800
801   if (disposition == VNET_ERROR_DISPOSITION_DROP || !vm->os_punt_frame)
802     {
803       vlib_buffer_free (vm, first_buffer, frame->n_vectors);
804
805       /* If there is no punt function, free the frame as well. */
806       if (disposition == VNET_ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
807         vlib_frame_free (vm, node, frame);
808     }
809   else
810     vm->os_punt_frame (vm, node, frame);
811
812   return frame->n_vectors;
813 }
814
815 static inline void
816 pcap_drop_trace (vlib_main_t * vm,
817                  vnet_interface_main_t * im, vlib_frame_t * f)
818 {
819   u32 *from;
820   u32 n_left = f->n_vectors;
821   vlib_buffer_t *b0, *p1;
822   u32 bi0;
823   i16 save_current_data;
824   u16 save_current_length;
825
826   from = vlib_frame_vector_args (f);
827
828   while (n_left > 0)
829     {
830       if (PREDICT_TRUE (n_left > 1))
831         {
832           p1 = vlib_get_buffer (vm, from[1]);
833           vlib_prefetch_buffer_header (p1, LOAD);
834         }
835
836       bi0 = from[0];
837       b0 = vlib_get_buffer (vm, bi0);
838       from++;
839       n_left--;
840
841       /* See if we're pointedly ignoring this specific error */
842       if (im->pcap_drop_filter_hash
843           && hash_get (im->pcap_drop_filter_hash, b0->error))
844         continue;
845
846       /* Trace all drops, or drops received on a specific interface */
847       if (im->pcap_sw_if_index == 0 ||
848           im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
849         {
850           save_current_data = b0->current_data;
851           save_current_length = b0->current_length;
852
853           /*
854            * Typically, we'll need to rewind the buffer
855            */
856           if (b0->current_data > 0)
857             vlib_buffer_advance (b0, (word) - b0->current_data);
858
859           pcap_add_buffer (&im->pcap_main, vm, bi0, 512);
860
861           b0->current_data = save_current_data;
862           b0->current_length = save_current_length;
863         }
864     }
865 }
866
867 void
868 vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
869 {
870   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
871
872   if (im->pcap_drop_filter_hash == 0)
873     im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
874
875   if (is_add)
876     hash_set (im->pcap_drop_filter_hash, error_index, 1);
877   else
878     hash_unset (im->pcap_drop_filter_hash, error_index);
879 }
880
881 static uword
882 process_drop (vlib_main_t * vm,
883               vlib_node_runtime_t * node, vlib_frame_t * frame)
884 {
885   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
886
887   if (PREDICT_FALSE (im->drop_pcap_enable))
888     pcap_drop_trace (vm, im, frame);
889
890   return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
891 }
892
893 static uword
894 process_punt (vlib_main_t * vm,
895               vlib_node_runtime_t * node, vlib_frame_t * frame)
896 {
897   return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
898 }
899
900 /* *INDENT-OFF* */
901 VLIB_REGISTER_NODE (drop_buffers,static) = {
902   .function = process_drop,
903   .name = "error-drop",
904   .flags = VLIB_NODE_FLAG_IS_DROP,
905   .vector_size = sizeof (u32),
906   .format_trace = format_vnet_error_trace,
907   .validate_frame = validate_error_frame,
908 };
909 /* *INDENT-ON* */
910
911 VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop);
912
913 /* *INDENT-OFF* */
914 VLIB_REGISTER_NODE (punt_buffers,static) = {
915   .function = process_punt,
916   .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
917             | VLIB_NODE_FLAG_IS_PUNT),
918   .name = "error-punt",
919   .vector_size = sizeof (u32),
920   .format_trace = format_vnet_error_trace,
921   .validate_frame = validate_error_frame,
922 };
923 /* *INDENT-ON* */
924
925 VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt);
926
927 /* *INDENT-OFF* */
928 VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
929   .function = vnet_per_buffer_interface_output,
930   .name = "interface-output",
931   .vector_size = sizeof (u32),
932 };
933 /* *INDENT-ON* */
934
935 VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
936                               vnet_per_buffer_interface_output);
937
938 static uword
939 interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
940                       vlib_frame_t * from_frame)
941 {
942   vnet_main_t *vnm = vnet_get_main ();
943   u32 last_sw_if_index = ~0;
944   vlib_frame_t *to_frame = 0;
945   vnet_hw_interface_t *hw = 0;
946   u32 *from, *to_next = 0;
947   u32 n_left_from;
948
949   from = vlib_frame_vector_args (from_frame);
950   n_left_from = from_frame->n_vectors;
951   while (n_left_from > 0)
952     {
953       u32 bi0;
954       vlib_buffer_t *b0;
955       u32 sw_if_index0;
956
957       bi0 = from[0];
958       from++;
959       n_left_from--;
960       b0 = vlib_get_buffer (vm, bi0);
961       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
962
963       if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
964         {
965           if (to_frame)
966             {
967               hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
968               vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
969             }
970           last_sw_if_index = sw_if_index0;
971           hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
972           to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
973           to_next = vlib_frame_vector_args (to_frame);
974         }
975
976       to_next[0] = bi0;
977       to_next++;
978       to_frame->n_vectors++;
979     }
980   vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
981   return from_frame->n_vectors;
982 }
983
984 /* *INDENT-OFF* */
985 VLIB_REGISTER_NODE (interface_tx, static) = {
986   .function = interface_tx_node_fn,
987   .name = "interface-tx",
988   .vector_size = sizeof (u32),
989   .n_next_nodes = 1,
990   .next_nodes = {
991     [0] = "error-drop",
992   },
993 };
994
995 VNET_FEATURE_ARC_INIT (interface_output, static) =
996 {
997   .arc_name  = "interface-output",
998   .start_nodes = VNET_FEATURES (0),
999   .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1000 };
1001
1002 VNET_FEATURE_INIT (span_tx, static) = {
1003   .arc_name = "interface-output",
1004   .node_name = "span-output",
1005   .runs_before = VNET_FEATURES ("interface-tx"),
1006 };
1007
1008 VNET_FEATURE_INIT (interface_tx, static) = {
1009   .arc_name = "interface-output",
1010   .node_name = "interface-tx",
1011   .runs_before = 0,
1012 };
1013 /* *INDENT-ON* */
1014
1015 clib_error_t *
1016 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1017                                                        u32 hw_if_index,
1018                                                        u32 is_create)
1019 {
1020   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1021   u32 next_index;
1022
1023   next_index = vlib_node_add_next_with_slot
1024     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1025      hi->output_node_index,
1026      /* next_index */ hw_if_index);
1027
1028   ASSERT (next_index == hw_if_index);
1029
1030   return 0;
1031 }
1032
1033 VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1034   (vnet_per_buffer_interface_output_hw_interface_add_del);
1035
1036 static clib_error_t *
1037 pcap_drop_trace_command_fn (vlib_main_t * vm,
1038                             unformat_input_t * input,
1039                             vlib_cli_command_t * cmd)
1040 {
1041   vnet_main_t *vnm = vnet_get_main ();
1042   vnet_interface_main_t *im = &vnm->interface_main;
1043   u8 *filename;
1044   u32 max;
1045   int matched = 0;
1046   clib_error_t *error = 0;
1047
1048   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1049     {
1050       if (unformat (input, "on"))
1051         {
1052           if (im->drop_pcap_enable == 0)
1053             {
1054               if (im->pcap_filename == 0)
1055                 im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0);
1056
1057               memset (&im->pcap_main, 0, sizeof (im->pcap_main));
1058               im->pcap_main.file_name = (char *) im->pcap_filename;
1059               im->pcap_main.n_packets_to_capture = 100;
1060               if (im->pcap_pkts_to_capture)
1061                 im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture;
1062
1063               im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
1064               im->drop_pcap_enable = 1;
1065               matched = 1;
1066               vlib_cli_output (vm, "pcap drop capture on...");
1067             }
1068           else
1069             {
1070               vlib_cli_output (vm, "pcap drop capture already on...");
1071             }
1072           matched = 1;
1073         }
1074       else if (unformat (input, "off"))
1075         {
1076           matched = 1;
1077
1078           if (im->drop_pcap_enable)
1079             {
1080               vlib_cli_output (vm, "captured %d pkts...",
1081                                im->pcap_main.n_packets_captured);
1082               if (im->pcap_main.n_packets_captured)
1083                 {
1084                   im->pcap_main.n_packets_to_capture =
1085                     im->pcap_main.n_packets_captured;
1086                   error = pcap_write (&im->pcap_main);
1087                   if (error)
1088                     clib_error_report (error);
1089                   else
1090                     vlib_cli_output (vm, "saved to %s...", im->pcap_filename);
1091                 }
1092             }
1093           else
1094             {
1095               vlib_cli_output (vm, "pcap drop capture already off...");
1096             }
1097
1098           im->drop_pcap_enable = 0;
1099         }
1100       else if (unformat (input, "max %d", &max))
1101         {
1102           im->pcap_pkts_to_capture = max;
1103           matched = 1;
1104         }
1105
1106       else if (unformat (input, "intfc %U",
1107                          unformat_vnet_sw_interface, vnm,
1108                          &im->pcap_sw_if_index))
1109         matched = 1;
1110       else if (unformat (input, "intfc any"))
1111         {
1112           im->pcap_sw_if_index = 0;
1113           matched = 1;
1114         }
1115       else if (unformat (input, "file %s", &filename))
1116         {
1117           u8 *chroot_filename;
1118           /* Brain-police user path input */
1119           if (strstr ((char *) filename, "..")
1120               || index ((char *) filename, '/'))
1121             {
1122               vlib_cli_output (vm, "illegal characters in filename '%s'",
1123                                filename);
1124               continue;
1125             }
1126
1127           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1128           vec_free (filename);
1129
1130           if (im->pcap_filename)
1131             vec_free (im->pcap_filename);
1132           im->pcap_filename = chroot_filename;
1133           im->pcap_main.file_name = (char *) im->pcap_filename;
1134           matched = 1;
1135         }
1136       else if (unformat (input, "status"))
1137         {
1138           if (im->drop_pcap_enable == 0)
1139             {
1140               vlib_cli_output (vm, "pcap drop capture is off...");
1141               continue;
1142             }
1143
1144           vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...",
1145                            im->pcap_main.n_packets_captured,
1146                            im->pcap_main.n_packets_to_capture);
1147           matched = 1;
1148         }
1149
1150       else
1151         break;
1152     }
1153
1154   if (matched == 0)
1155     return clib_error_return (0, "unknown input `%U'",
1156                               format_unformat_error, input);
1157
1158   return 0;
1159 }
1160
1161 /* *INDENT-OFF* */
1162 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
1163   .path = "pcap drop trace",
1164   .short_help =
1165   "pcap drop trace on off max <nn> intfc <intfc> file <name> status",
1166   .function = pcap_drop_trace_command_fn,
1167 };
1168 /* *INDENT-ON* */
1169
1170 /*
1171  * fd.io coding-style-patch-verification: ON
1172  *
1173  * Local Variables:
1174  * eval: (c-set-style "gnu")
1175  * End:
1176  */