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