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