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