blob: 03f2cdca7a09a8651c29df1b7f4e68b4c537feac [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Damjan Marion152e21d2016-11-29 14:55:43 +010041#include <vnet/feature/feature.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070042
Dave Barachba868bb2016-08-08 09:51:21 -040043typedef struct
44{
Ed Warnickecb9cada2015-12-08 15:45:58 -070045 u32 sw_if_index;
Chris Luke1c9f6ce2016-04-26 10:55:52 -040046 u8 data[128 - sizeof (u32)];
Dave Barachba868bb2016-08-08 09:51:21 -040047}
48interface_output_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
Dave Barachba868bb2016-08-08 09:51:21 -040050u8 *
51format_vnet_interface_output_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070052{
53 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
Dave Barachba868bb2016-08-08 09:51:21 -040054 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;
Ed Warnickecb9cada2015-12-08 15:45:58 -070058 uword indent;
59
Dave Barachba868bb2016-08-08 09:51:21 -040060 if (t->sw_if_index != (u32) ~ 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -070061 {
Ed Warnickecb9cada2015-12-08 15:45:58 -070062 indent = format_get_indent (s);
Dave Barachba868bb2016-08-08 09:51:21 -040063
Neale Ranns177bbdc2016-11-15 09:46:51 +000064 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 }
87 return s;
88}
89
90static void
91vnet_interface_output_trace (vlib_main_t * vm,
92 vlib_node_runtime_t * node,
Dave Barachba868bb2016-08-08 09:51:21 -040093 vlib_frame_t * frame, uword n_buffers)
Ed Warnickecb9cada2015-12-08 15:45:58 -070094{
Dave Barachba868bb2016-08-08 09:51:21 -040095 u32 n_left, *from;
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
97 n_left = n_buffers;
98 from = vlib_frame_args (frame);
Dave Barachba868bb2016-08-08 09:51:21 -040099
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100 while (n_left >= 4)
101 {
102 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400103 vlib_buffer_t *b0, *b1;
104 interface_output_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105
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];
Damjan Marionf1213b82016-03-13 02:22:06 +0100120 clib_memcpy (t0->data, vlib_buffer_get_current (b0),
Dave Barachba868bb2016-08-08 09:51:21 -0400121 sizeof (t0->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122 }
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];
Damjan Marionf1213b82016-03-13 02:22:06 +0100127 clib_memcpy (t1->data, vlib_buffer_get_current (b1),
Dave Barachba868bb2016-08-08 09:51:21 -0400128 sizeof (t1->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129 }
130 from += 2;
131 n_left -= 2;
132 }
133
134 while (n_left >= 1)
135 {
136 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400137 vlib_buffer_t *b0;
138 interface_output_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
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];
Damjan Marionf1213b82016-03-13 02:22:06 +0100148 clib_memcpy (t0->data, vlib_buffer_get_current (b0),
Dave Barachba868bb2016-08-08 09:51:21 -0400149 sizeof (t0->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150 }
151 from += 1;
152 n_left -= 1;
153 }
154}
155
156static never_inline u32
157slow_path (vlib_main_t * vm,
158 u32 bi,
159 vlib_buffer_t * b,
Dave Barachba868bb2016-08-08 09:51:21 -0400160 u32 n_left_to_tx, u32 * to_tx, u32 * n_slow_bytes_result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161{
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
Dave Barachba868bb2016-08-08 09:51:21 -0400175 driver tx function. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176 ASSERT (b->current_length > 0);
177
Dave Barachba868bb2016-08-08 09:51:21 -0400178 if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 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
Dave Barachba868bb2016-08-08 09:51:21 -0400193/*
194 * Increment TX stats. Roll up consecutive increments to the same sw_if_index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 * into one increment.
196 */
Dave Barachba868bb2016-08-08 09:51:21 -0400197static_always_inline void
198incr_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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205
Dave Barachba868bb2016-08-08 09:51:21 -0400206 if (PREDICT_TRUE (sw_if_index == *last_sw_if_index))
207 {
208 *n_packets += 1;
209 *n_bytes += length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210 }
Dave Barachba868bb2016-08-08 09:51:21 -0400211 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227}
228
229
230/* Interface output functions. */
231uword
Damjan Marion8b2247d2016-12-02 08:09:45 +0100232vnet_interface_output_node_flatten (vlib_main_t * vm,
233 vlib_node_runtime_t * node,
234 vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235{
Dave Barachba868bb2016-08-08 09:51:21 -0400236 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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 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)
Dave Barachba868bb2016-08-08 09:51:21 -0400253 return vlib_error_drop_buffers (vm, node, from,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 /* 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);
Dave Barachba868bb2016-08-08 09:51:21 -0400262 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ||
263 !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264 {
Dave Barachba868bb2016-08-08 09:51:21 -0400265 vlib_simple_counter_main_t *cm;
266
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
Dave Barachba868bb2016-08-08 09:51:21 -0400268 VNET_INTERFACE_COUNTER_TX_ERROR);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 vlib_increment_simple_counter (cm, cpu_index,
Dave Barachba868bb2016-08-08 09:51:21 -0400270 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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277 }
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
Dave Barachba868bb2016-08-08 09:51:21 -0400289 than VNET_FRAME_SIZE vectors in it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 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;
Dave Barachba868bb2016-08-08 09:51:21 -0400296 vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297
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
Dave Barachba868bb2016-08-08 09:51:21 -0400318 if (PREDICT_FALSE
319 ((b0->flags | b1->flags) & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320 {
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;
Dave Barachba868bb2016-08-08 09:51:21 -0400332 vlib_buffer_t *b = i ? b1 : b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333
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,
Dave Barachba868bb2016-08-08 09:51:21 -0400345 vnet_buffer (b)->sw_if_index[VLIB_TX],
346 &last_sw_if_index, &n_packets, &n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347 }
Dave Barachba868bb2016-08-08 09:51:21 -0400348 }
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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 }
361
362 while (from + 1 <= from_end && n_left_to_tx >= 1)
363 {
364 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400365 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
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 }
Dave Barachba868bb2016-08-08 09:51:21 -0400399 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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403 }
404
405 put:
Dave Barachba868bb2016-08-08 09:51:21 -0400406 vlib_put_next_frame (vm, node, VNET_INTERFACE_OUTPUT_NEXT_TX,
407 n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408 }
409
410 /* Final update of interface stats. */
Dave Barachba868bb2016-08-08 09:51:21 -0400411 incr_output_stats (vnm, cpu_index, 0, ~0, /* ~0 will flush stats */
412 &last_sw_if_index, &n_packets, &n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413
414 return n_buffers;
415}
416
Damjan Marion8b2247d2016-12-02 08:09:45 +0100417VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node_flatten);
418CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node_flatten);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100420uword
Damjan Marion8b2247d2016-12-02 08:09:45 +0100421vnet_interface_output_node (vlib_main_t * vm,
422 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423{
Dave Barachba868bb2016-08-08 09:51:21 -0400424 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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700429 u32 n_bytes, n_buffers, n_packets;
Damjan Marion363640d2017-03-06 11:53:10 +0100430 u32 n_bytes_b0, n_bytes_b1, n_bytes_b2, n_bytes_b3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431 u32 cpu_index = vm->cpu_index;
Dave Barachba868bb2016-08-08 09:51:21 -0400432 vnet_interface_main_t *im = &vnm->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700433 u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
Damjan Marion152e21d2016-11-29 14:55:43 +0100434 u32 current_config_index = ~0;
435 u8 arc = im->output_feature_arc_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700436
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)
Dave Barachba868bb2016-08-08 09:51:21 -0400445 return vlib_error_drop_buffers (vm, node, from,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700446 /* 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);
Dave Barachba868bb2016-08-08 09:51:21 -0400454 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ||
455 !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700456 {
Dave Barachba868bb2016-08-08 09:51:21 -0400457 vlib_simple_counter_main_t *cm;
458
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
Dave Barachba868bb2016-08-08 09:51:21 -0400460 VNET_INTERFACE_COUNTER_TX_ERROR);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461 vlib_increment_simple_counter (cm, cpu_index,
Dave Barachba868bb2016-08-08 09:51:21 -0400462 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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 }
471
472 from_end = from + n_buffers;
473
474 /* Total byte count of all buffers. */
475 n_bytes = 0;
476 n_packets = 0;
477
Damjan Marion152e21d2016-11-29 14:55:43 +0100478 /* 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
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489 while (from < from_end)
490 {
491 /* Get new next frame since previous incomplete frame may have less
Dave Barachba868bb2016-08-08 09:51:21 -0400492 than VNET_FRAME_SIZE vectors in it. */
493 vlib_get_new_next_frame (vm, node, next_index, to_tx, n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494
Damjan Marion363640d2017-03-06 11:53:10 +0100495 while (from + 8 <= from_end && n_left_to_tx >= 4)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496 {
Damjan Marion363640d2017-03-06 11:53:10 +0100497 u32 bi0, bi1, bi2, bi3;
498 vlib_buffer_t *b0, *b1, *b2, *b3;
499 u32 tx_swif0, tx_swif1, tx_swif2, tx_swif3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500
501 /* Prefetch next iteration. */
Damjan Marion363640d2017-03-06 11:53:10 +0100502 vlib_prefetch_buffer_with_index (vm, from[4], LOAD);
503 vlib_prefetch_buffer_with_index (vm, from[5], LOAD);
504 vlib_prefetch_buffer_with_index (vm, from[6], LOAD);
505 vlib_prefetch_buffer_with_index (vm, from[7], LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506
507 bi0 = from[0];
508 bi1 = from[1];
Damjan Marion363640d2017-03-06 11:53:10 +0100509 bi2 = from[2];
510 bi3 = from[3];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700511 to_tx[0] = bi0;
512 to_tx[1] = bi1;
Damjan Marion363640d2017-03-06 11:53:10 +0100513 to_tx[2] = bi2;
514 to_tx[3] = bi3;
515 from += 4;
516 to_tx += 4;
517 n_left_to_tx -= 4;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
519 b0 = vlib_get_buffer (vm, bi0);
520 b1 = vlib_get_buffer (vm, bi1);
Damjan Marion363640d2017-03-06 11:53:10 +0100521 b2 = vlib_get_buffer (vm, bi2);
522 b3 = vlib_get_buffer (vm, bi3);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523
524 /* Be grumpy about zero length buffers for benefit of
525 driver tx function. */
526 ASSERT (b0->current_length > 0);
527 ASSERT (b1->current_length > 0);
Damjan Marion363640d2017-03-06 11:53:10 +0100528 ASSERT (b2->current_length > 0);
529 ASSERT (b3->current_length > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530
Dave Barachba868bb2016-08-08 09:51:21 -0400531 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
532 n_bytes_b1 = vlib_buffer_length_in_chain (vm, b1);
Damjan Marion363640d2017-03-06 11:53:10 +0100533 n_bytes_b2 = vlib_buffer_length_in_chain (vm, b2);
534 n_bytes_b3 = vlib_buffer_length_in_chain (vm, b3);
Dave Barachba868bb2016-08-08 09:51:21 -0400535 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
536 tx_swif1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
Damjan Marion363640d2017-03-06 11:53:10 +0100537 tx_swif2 = vnet_buffer (b2)->sw_if_index[VLIB_TX];
538 tx_swif3 = vnet_buffer (b3)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539
540 n_bytes += n_bytes_b0 + n_bytes_b1;
Damjan Marion363640d2017-03-06 11:53:10 +0100541 n_bytes += n_bytes_b2 + n_bytes_b3;
542 n_packets += 4;
Dave Barachba868bb2016-08-08 09:51:21 -0400543
Damjan Marion152e21d2016-11-29 14:55:43 +0100544 if (PREDICT_FALSE (current_config_index != ~0))
545 {
546 b0->feature_arc_index = arc;
547 b1->feature_arc_index = arc;
Damjan Marion363640d2017-03-06 11:53:10 +0100548 b2->feature_arc_index = arc;
549 b3->feature_arc_index = arc;
Damjan Marion152e21d2016-11-29 14:55:43 +0100550 b0->current_config_index = current_config_index;
551 b1->current_config_index = current_config_index;
Damjan Marion363640d2017-03-06 11:53:10 +0100552 b2->current_config_index = current_config_index;
553 b3->current_config_index = current_config_index;
Damjan Marion152e21d2016-11-29 14:55:43 +0100554 }
555
Damjan Marion363640d2017-03-06 11:53:10 +0100556 /* update vlan subif tx counts, if required */
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100557 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
Dave Barachba868bb2016-08-08 09:51:21 -0400558 {
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100559 vlib_increment_combined_counter (im->combined_sw_if_counters +
560 VNET_INTERFACE_COUNTER_TX,
561 cpu_index, tx_swif0, 1,
562 n_bytes_b0);
Dave Barachba868bb2016-08-08 09:51:21 -0400563 }
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100564
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100565 if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
566 {
567
568 vlib_increment_combined_counter (im->combined_sw_if_counters +
569 VNET_INTERFACE_COUNTER_TX,
570 cpu_index, tx_swif1, 1,
571 n_bytes_b1);
572 }
Damjan Marion363640d2017-03-06 11:53:10 +0100573
574 if (PREDICT_FALSE (tx_swif2 != rt->sw_if_index))
575 {
576
577 vlib_increment_combined_counter (im->combined_sw_if_counters +
578 VNET_INTERFACE_COUNTER_TX,
579 cpu_index, tx_swif2, 1,
580 n_bytes_b2);
581 }
582 if (PREDICT_FALSE (tx_swif3 != rt->sw_if_index))
583 {
584
585 vlib_increment_combined_counter (im->combined_sw_if_counters +
586 VNET_INTERFACE_COUNTER_TX,
587 cpu_index, tx_swif3, 1,
588 n_bytes_b3);
589 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590 }
591
592 while (from + 1 <= from_end && n_left_to_tx >= 1)
593 {
594 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400595 vlib_buffer_t *b0;
596 u32 tx_swif0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597
598 bi0 = from[0];
599 to_tx[0] = bi0;
600 from += 1;
601 to_tx += 1;
602 n_left_to_tx -= 1;
603
604 b0 = vlib_get_buffer (vm, bi0);
605
606 /* Be grumpy about zero length buffers for benefit of
607 driver tx function. */
608 ASSERT (b0->current_length > 0);
609
Dave Barachba868bb2016-08-08 09:51:21 -0400610 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
611 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612 n_bytes += n_bytes_b0;
613 n_packets += 1;
614
Damjan Marion152e21d2016-11-29 14:55:43 +0100615 if (PREDICT_FALSE (current_config_index != ~0))
616 {
617 b0->feature_arc_index = arc;
618 b0->current_config_index = current_config_index;
619 }
620
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100621 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
Dave Barachba868bb2016-08-08 09:51:21 -0400622 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100624 vlib_increment_combined_counter (im->combined_sw_if_counters +
625 VNET_INTERFACE_COUNTER_TX,
626 cpu_index, tx_swif0, 1,
627 n_bytes_b0);
Dave Barachba868bb2016-08-08 09:51:21 -0400628 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629 }
630
Dave Barachba868bb2016-08-08 09:51:21 -0400631 vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 }
633
634 /* Update main interface stats. */
635 vlib_increment_combined_counter (im->combined_sw_if_counters
Dave Barachba868bb2016-08-08 09:51:21 -0400636 + VNET_INTERFACE_COUNTER_TX,
637 cpu_index,
638 rt->sw_if_index, n_packets, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639 return n_buffers;
640}
641
Damjan Marion8b2247d2016-12-02 08:09:45 +0100642VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
643CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
645/* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
646static uword
647vnet_per_buffer_interface_output (vlib_main_t * vm,
648 vlib_node_runtime_t * node,
649 vlib_frame_t * frame)
650{
Dave Barachba868bb2016-08-08 09:51:21 -0400651 vnet_main_t *vnm = vnet_get_main ();
652 u32 n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653 u32 n_left_from, next_index;
654
655 n_left_from = frame->n_vectors;
656
657 from = vlib_frame_args (frame);
658 next_index = node->cached_next_index;
659
660 while (n_left_from > 0)
661 {
662 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
663
664 while (n_left_from >= 4 && n_left_to_next >= 2)
665 {
666 u32 bi0, bi1, next0, next1;
Dave Barachba868bb2016-08-08 09:51:21 -0400667 vlib_buffer_t *b0, *b1;
668 vnet_hw_interface_t *hi0, *hi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669
670 /* Prefetch next iteration. */
671 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
672 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
673
674 bi0 = from[0];
675 bi1 = from[1];
676 to_next[0] = bi0;
677 to_next[1] = bi1;
678 from += 2;
679 to_next += 2;
680 n_left_to_next -= 2;
681 n_left_from -= 2;
682
683 b0 = vlib_get_buffer (vm, bi0);
684 b1 = vlib_get_buffer (vm, bi1);
685
Dave Barachba868bb2016-08-08 09:51:21 -0400686 hi0 =
687 vnet_get_sup_hw_interface (vnm,
688 vnet_buffer (b0)->sw_if_index
689 [VLIB_TX]);
690 hi1 =
691 vnet_get_sup_hw_interface (vnm,
692 vnet_buffer (b1)->sw_if_index
693 [VLIB_TX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700694
695 next0 = hi0->hw_if_index;
696 next1 = hi1->hw_if_index;
697
Dave Barachba868bb2016-08-08 09:51:21 -0400698 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
699 n_left_to_next, bi0, bi1, next0,
700 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700701 }
702
703 while (n_left_from > 0 && n_left_to_next > 0)
704 {
705 u32 bi0, next0;
Dave Barachba868bb2016-08-08 09:51:21 -0400706 vlib_buffer_t *b0;
707 vnet_hw_interface_t *hi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708
709 bi0 = from[0];
710 to_next[0] = bi0;
711 from += 1;
712 to_next += 1;
713 n_left_to_next -= 1;
714 n_left_from -= 1;
715
716 b0 = vlib_get_buffer (vm, bi0);
717
Dave Barachba868bb2016-08-08 09:51:21 -0400718 hi0 =
719 vnet_get_sup_hw_interface (vnm,
720 vnet_buffer (b0)->sw_if_index
721 [VLIB_TX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722
723 next0 = hi0->hw_if_index;
724
Dave Barachba868bb2016-08-08 09:51:21 -0400725 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
726 n_left_to_next, bi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727 }
728
729 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
730 }
731
732 return frame->n_vectors;
733}
734
735always_inline u32
736counter_index (vlib_main_t * vm, vlib_error_t e)
737{
Dave Barachba868bb2016-08-08 09:51:21 -0400738 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 u32 ci, ni;
740
741 ni = vlib_error_get_node (e);
742 n = vlib_get_node (vm, ni);
743
744 ci = vlib_error_get_code (e);
745 ASSERT (ci < n->n_errors);
746
747 ci += n->error_heap_index;
748
749 return ci;
750}
751
Dave Barachba868bb2016-08-08 09:51:21 -0400752static u8 *
753format_vnet_error_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754{
Dave Barachba868bb2016-08-08 09:51:21 -0400755 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
Dave Barachba868bb2016-08-08 09:51:21 -0400757 vlib_error_t *e = va_arg (*va, vlib_error_t *);
758 vlib_node_t *error_node;
759 vlib_error_main_t *em = &vm->error_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760 u32 i;
761
762 error_node = vlib_get_node (vm, vlib_error_get_node (e[0]));
763 i = counter_index (vm, e[0]);
764 s = format (s, "%v: %s", error_node->name, em->error_strings_heap[i]);
765
766 return s;
767}
768
769static void
770trace_errors_with_buffers (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400771 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700772{
Dave Barachba868bb2016-08-08 09:51:21 -0400773 u32 n_left, *buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774
775 buffers = vlib_frame_vector_args (frame);
776 n_left = frame->n_vectors;
Dave Barachba868bb2016-08-08 09:51:21 -0400777
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778 while (n_left >= 4)
779 {
780 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400781 vlib_buffer_t *b0, *b1;
782 vlib_error_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783
784 /* Prefetch next iteration. */
785 vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
786 vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
787
788 bi0 = buffers[0];
789 bi1 = buffers[1];
790
791 b0 = vlib_get_buffer (vm, bi0);
792 b1 = vlib_get_buffer (vm, bi1);
793
794 if (b0->flags & VLIB_BUFFER_IS_TRACED)
795 {
796 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
797 t0[0] = b0->error;
798 }
799 if (b1->flags & VLIB_BUFFER_IS_TRACED)
800 {
801 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
802 t1[0] = b1->error;
803 }
804 buffers += 2;
805 n_left -= 2;
806 }
807
808 while (n_left >= 1)
809 {
810 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400811 vlib_buffer_t *b0;
812 vlib_error_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813
814 bi0 = buffers[0];
815
816 b0 = vlib_get_buffer (vm, bi0);
817
818 if (b0->flags & VLIB_BUFFER_IS_TRACED)
819 {
820 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
821 t0[0] = b0->error;
822 }
823 buffers += 1;
824 n_left -= 1;
825 }
826}
827
828static u8 *
829validate_error (vlib_main_t * vm, vlib_error_t * e, u32 index)
830{
831 uword node_index = vlib_error_get_node (e[0]);
832 uword code = vlib_error_get_code (e[0]);
Dave Barachba868bb2016-08-08 09:51:21 -0400833 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
835 if (node_index >= vec_len (vm->node_main.nodes))
836 return format (0, "[%d], node index out of range 0x%x, error 0x%x",
837 index, node_index, e[0]);
838
839 n = vlib_get_node (vm, node_index);
840 if (code >= n->n_errors)
841 return format (0, "[%d], code %d out of range for node %v",
842 index, code, n->name);
843
844 return 0;
845}
846
847static u8 *
848validate_error_frame (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400849 vlib_node_runtime_t * node, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700850{
Dave Barachba868bb2016-08-08 09:51:21 -0400851 u32 *buffers = vlib_frame_args (f);
852 vlib_buffer_t *b;
853 u8 *msg = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854 uword i;
855
856 for (i = 0; i < f->n_vectors; i++)
857 {
858 b = vlib_get_buffer (vm, buffers[i]);
859 msg = validate_error (vm, &b->error, i);
860 if (msg)
861 return msg;
862 }
863
864 return msg;
865}
866
Dave Barachba868bb2016-08-08 09:51:21 -0400867typedef enum
868{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869 VNET_ERROR_DISPOSITION_DROP,
870 VNET_ERROR_DISPOSITION_PUNT,
871 VNET_ERROR_N_DISPOSITION,
872} vnet_error_disposition_t;
873
874always_inline void
875do_packet (vlib_main_t * vm, vlib_error_t a)
876{
Dave Barachba868bb2016-08-08 09:51:21 -0400877 vlib_error_main_t *em = &vm->error_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700878 u32 i = counter_index (vm, a);
879 em->counters[i] += 1;
880 vlib_error_elog_count (vm, i, 1);
881}
Dave Barachba868bb2016-08-08 09:51:21 -0400882
Ed Warnickecb9cada2015-12-08 15:45:58 -0700883static_always_inline uword
884process_drop_punt (vlib_main_t * vm,
885 vlib_node_runtime_t * node,
Dave Barachba868bb2016-08-08 09:51:21 -0400886 vlib_frame_t * frame, vnet_error_disposition_t disposition)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700887{
Dave Barachba868bb2016-08-08 09:51:21 -0400888 vnet_main_t *vnm = vnet_get_main ();
889 vlib_error_main_t *em = &vm->error_main;
890 u32 *buffers, *first_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700891 vlib_error_t current_error;
892 u32 current_counter_index, n_errors_left;
893 u32 current_sw_if_index, n_errors_current_sw_if_index;
894 u64 current_counter;
Dave Barachba868bb2016-08-08 09:51:21 -0400895 vlib_simple_counter_main_t *cm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896 u32 cpu_index = vm->cpu_index;
897
898 static vlib_error_t memory[VNET_ERROR_N_DISPOSITION];
899 static char memory_init[VNET_ERROR_N_DISPOSITION];
900
901 buffers = vlib_frame_args (frame);
902 first_buffer = buffers;
903
904 {
Dave Barachba868bb2016-08-08 09:51:21 -0400905 vlib_buffer_t *b = vlib_get_buffer (vm, first_buffer[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700906
Dave Barachba868bb2016-08-08 09:51:21 -0400907 if (!memory_init[disposition])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908 {
909 memory_init[disposition] = 1;
910 memory[disposition] = b->error;
911 }
912
913 current_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
914 n_errors_current_sw_if_index = 0;
915 }
916
917 current_error = memory[disposition];
918 current_counter_index = counter_index (vm, memory[disposition]);
919 current_counter = em->counters[current_counter_index];
920
921 if (node->flags & VLIB_NODE_FLAG_TRACE)
922 trace_errors_with_buffers (vm, node, frame);
Dave Barachba868bb2016-08-08 09:51:21 -0400923
Ed Warnickecb9cada2015-12-08 15:45:58 -0700924 n_errors_left = frame->n_vectors;
925 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
926 (disposition == VNET_ERROR_DISPOSITION_PUNT
927 ? VNET_INTERFACE_COUNTER_PUNT
928 : VNET_INTERFACE_COUNTER_DROP));
929
930 while (n_errors_left >= 2)
931 {
Dave Barachba868bb2016-08-08 09:51:21 -0400932 vlib_buffer_t *b0, *b1;
933 vnet_sw_interface_t *sw_if0, *sw_if1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934 vlib_error_t e0, e1;
935 u32 bi0, bi1;
936 u32 sw_if_index0, sw_if_index1;
937
938 bi0 = buffers[0];
939 bi1 = buffers[1];
940
941 buffers += 2;
942 n_errors_left -= 2;
943
944 b0 = vlib_get_buffer (vm, bi0);
945 b1 = vlib_get_buffer (vm, bi1);
946
947 e0 = b0->error;
948 e1 = b1->error;
949
950 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
951 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
952
953 /* Speculate that sw_if_index == sw_if_index[01]. */
954 n_errors_current_sw_if_index += 2;
955
956 /* Speculatively assume all 2 (node, code) pairs are equal
Dave Barachba868bb2016-08-08 09:51:21 -0400957 to current (node, code). */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958 current_counter += 2;
959
960 if (PREDICT_FALSE (e0 != current_error
961 || e1 != current_error
962 || sw_if_index0 != current_sw_if_index
963 || sw_if_index1 != current_sw_if_index))
964 {
965 current_counter -= 2;
966 n_errors_current_sw_if_index -= 2;
967
968 vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
969 vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1);
970
971 /* Increment super-interface drop/punt counters for
972 sub-interfaces. */
973 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
974 vlib_increment_simple_counter
Dave Barachba868bb2016-08-08 09:51:21 -0400975 (cm, cpu_index, sw_if0->sup_sw_if_index,
976 sw_if0->sup_sw_if_index != sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977
978 sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1);
979 vlib_increment_simple_counter
Dave Barachba868bb2016-08-08 09:51:21 -0400980 (cm, cpu_index, sw_if1->sup_sw_if_index,
981 sw_if1->sup_sw_if_index != sw_if_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982
983 em->counters[current_counter_index] = current_counter;
984 do_packet (vm, e0);
985 do_packet (vm, e1);
986
987 /* For 2 repeated errors, change current error. */
988 if (e0 == e1 && e1 != current_error)
989 {
990 current_error = e0;
991 current_counter_index = counter_index (vm, e0);
992 }
993 current_counter = em->counters[current_counter_index];
994 }
995 }
996
997 while (n_errors_left >= 1)
998 {
Dave Barachba868bb2016-08-08 09:51:21 -0400999 vlib_buffer_t *b0;
1000 vnet_sw_interface_t *sw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001001 vlib_error_t e0;
1002 u32 bi0, sw_if_index0;
1003
1004 bi0 = buffers[0];
1005
1006 buffers += 1;
1007 n_errors_left -= 1;
1008 current_counter += 1;
1009
1010 b0 = vlib_get_buffer (vm, bi0);
1011 e0 = b0->error;
1012
1013 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1014
1015 /* Increment drop/punt counters. */
1016 vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
1017
1018 /* Increment super-interface drop/punt counters for sub-interfaces. */
1019 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
Dave Barachba868bb2016-08-08 09:51:21 -04001020 vlib_increment_simple_counter (cm, cpu_index, sw_if0->sup_sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 sw_if0->sup_sw_if_index != sw_if_index0);
1022
1023 if (PREDICT_FALSE (e0 != current_error))
1024 {
1025 current_counter -= 1;
1026
1027 vlib_error_elog_count (vm, current_counter_index,
1028 (current_counter
1029 - em->counters[current_counter_index]));
Dave Barachba868bb2016-08-08 09:51:21 -04001030
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 em->counters[current_counter_index] = current_counter;
1032
1033 do_packet (vm, e0);
1034 current_error = e0;
1035 current_counter_index = counter_index (vm, e0);
1036 current_counter = em->counters[current_counter_index];
1037 }
1038 }
1039
1040 if (n_errors_current_sw_if_index > 0)
1041 {
Dave Barachba868bb2016-08-08 09:51:21 -04001042 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043
1044 vlib_increment_simple_counter (cm, cpu_index, current_sw_if_index,
1045 n_errors_current_sw_if_index);
1046
1047 si = vnet_get_sw_interface (vnm, current_sw_if_index);
1048 if (si->sup_sw_if_index != current_sw_if_index)
Dave Barachba868bb2016-08-08 09:51:21 -04001049 vlib_increment_simple_counter (cm, cpu_index, si->sup_sw_if_index,
1050 n_errors_current_sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 }
1052
1053 vlib_error_elog_count (vm, current_counter_index,
1054 (current_counter
1055 - em->counters[current_counter_index]));
1056
1057 /* Return cached counter. */
1058 em->counters[current_counter_index] = current_counter;
1059
1060 /* Save memory for next iteration. */
1061 memory[disposition] = current_error;
1062
Dave Barachba868bb2016-08-08 09:51:21 -04001063 if (disposition == VNET_ERROR_DISPOSITION_DROP || !vm->os_punt_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001064 {
Dave Barachba868bb2016-08-08 09:51:21 -04001065 vlib_buffer_free (vm, first_buffer, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066
1067 /* If there is no punt function, free the frame as well. */
Dave Barachba868bb2016-08-08 09:51:21 -04001068 if (disposition == VNET_ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069 vlib_frame_free (vm, node, frame);
1070 }
1071 else
1072 vm->os_punt_frame (vm, node, frame);
1073
1074 return frame->n_vectors;
1075}
1076
Dave Barachba868bb2016-08-08 09:51:21 -04001077static inline void
1078pcap_drop_trace (vlib_main_t * vm,
1079 vnet_interface_main_t * im, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080{
Dave Barachba868bb2016-08-08 09:51:21 -04001081 u32 *from;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082 u32 n_left = f->n_vectors;
Dave Barachba868bb2016-08-08 09:51:21 -04001083 vlib_buffer_t *b0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 u32 bi0;
1085 i16 save_current_data;
1086 u16 save_current_length;
1087
1088 from = vlib_frame_vector_args (f);
1089
1090 while (n_left > 0)
1091 {
1092 if (PREDICT_TRUE (n_left > 1))
Dave Barachba868bb2016-08-08 09:51:21 -04001093 {
1094 p1 = vlib_get_buffer (vm, from[1]);
1095 vlib_prefetch_buffer_header (p1, LOAD);
1096 }
1097
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098 bi0 = from[0];
1099 b0 = vlib_get_buffer (vm, bi0);
1100 from++;
1101 n_left--;
Dave Barachba868bb2016-08-08 09:51:21 -04001102
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103 /* See if we're pointedly ignoring this specific error */
Dave Barachba868bb2016-08-08 09:51:21 -04001104 if (im->pcap_drop_filter_hash
1105 && hash_get (im->pcap_drop_filter_hash, b0->error))
1106 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001107
1108 /* Trace all drops, or drops received on a specific interface */
1109 if (im->pcap_sw_if_index == 0 ||
Dave Barachba868bb2016-08-08 09:51:21 -04001110 im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
1111 {
1112 save_current_data = b0->current_data;
1113 save_current_length = b0->current_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114
Dave Barachba868bb2016-08-08 09:51:21 -04001115 /*
1116 * Typically, we'll need to rewind the buffer
1117 */
1118 if (b0->current_data > 0)
1119 vlib_buffer_advance (b0, (word) - b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120
Dave Barachba868bb2016-08-08 09:51:21 -04001121 pcap_add_buffer (&im->pcap_main, vm, bi0, 512);
1122
1123 b0->current_data = save_current_data;
1124 b0->current_length = save_current_length;
1125 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001126 }
1127}
1128
Dave Barachba868bb2016-08-08 09:51:21 -04001129void
1130vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001131{
Dave Barachba868bb2016-08-08 09:51:21 -04001132 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001133
1134 if (im->pcap_drop_filter_hash == 0)
Dave Barachba868bb2016-08-08 09:51:21 -04001135 im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001136
1137 if (is_add)
1138 hash_set (im->pcap_drop_filter_hash, error_index, 1);
1139 else
1140 hash_unset (im->pcap_drop_filter_hash, error_index);
1141}
1142
1143static uword
1144process_drop (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001145 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146{
Dave Barachba868bb2016-08-08 09:51:21 -04001147 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148
1149 if (PREDICT_FALSE (im->drop_pcap_enable))
1150 pcap_drop_trace (vm, im, frame);
1151
1152 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
1153}
1154
1155static uword
1156process_punt (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001157 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001158{
1159 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
1160}
1161
Dave Barachba868bb2016-08-08 09:51:21 -04001162/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163VLIB_REGISTER_NODE (drop_buffers,static) = {
1164 .function = process_drop,
1165 .name = "error-drop",
1166 .flags = VLIB_NODE_FLAG_IS_DROP,
1167 .vector_size = sizeof (u32),
1168 .format_trace = format_vnet_error_trace,
1169 .validate_frame = validate_error_frame,
1170};
Dave Barachba868bb2016-08-08 09:51:21 -04001171/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
Dave Barachba868bb2016-08-08 09:51:21 -04001173VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001174
Dave Barachba868bb2016-08-08 09:51:21 -04001175/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176VLIB_REGISTER_NODE (punt_buffers,static) = {
1177 .function = process_punt,
1178 .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
1179 | VLIB_NODE_FLAG_IS_PUNT),
1180 .name = "error-punt",
1181 .vector_size = sizeof (u32),
1182 .format_trace = format_vnet_error_trace,
1183 .validate_frame = validate_error_frame,
1184};
Dave Barachba868bb2016-08-08 09:51:21 -04001185/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186
Dave Barachba868bb2016-08-08 09:51:21 -04001187VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001188
Dave Barachba868bb2016-08-08 09:51:21 -04001189/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001190VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
1191 .function = vnet_per_buffer_interface_output,
1192 .name = "interface-output",
1193 .vector_size = sizeof (u32),
1194};
Dave Barachba868bb2016-08-08 09:51:21 -04001195/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001196
Dave Barachba868bb2016-08-08 09:51:21 -04001197VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
1198 vnet_per_buffer_interface_output);
Damjan Marion1c80e832016-05-11 23:07:18 +02001199
Damjan Marion152e21d2016-11-29 14:55:43 +01001200static uword
1201interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1202 vlib_frame_t * from_frame)
1203{
1204 vnet_main_t *vnm = vnet_get_main ();
1205 u32 last_sw_if_index = ~0;
1206 vlib_frame_t *to_frame = 0;
1207 vnet_hw_interface_t *hw = 0;
1208 u32 *from, *to_next = 0;
1209 u32 n_left_from;
1210
1211 from = vlib_frame_vector_args (from_frame);
1212 n_left_from = from_frame->n_vectors;
1213 while (n_left_from > 0)
1214 {
1215 u32 bi0;
1216 vlib_buffer_t *b0;
1217 u32 sw_if_index0;
1218
1219 bi0 = from[0];
1220 from++;
1221 n_left_from--;
1222 b0 = vlib_get_buffer (vm, bi0);
1223 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1224
1225 if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
1226 {
1227 if (to_frame)
1228 {
1229 hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
1230 vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1231 }
1232 last_sw_if_index = sw_if_index0;
1233 hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1234 to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
1235 to_next = vlib_frame_vector_args (to_frame);
1236 }
1237
1238 to_next[0] = bi0;
1239 to_next++;
1240 to_frame->n_vectors++;
1241 }
1242 vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1243 return from_frame->n_vectors;
1244}
1245
1246/* *INDENT-OFF* */
1247VLIB_REGISTER_NODE (interface_tx, static) = {
1248 .function = interface_tx_node_fn,
1249 .name = "interface-tx",
1250 .vector_size = sizeof (u32),
1251 .n_next_nodes = 1,
1252 .next_nodes = {
1253 [0] = "error-drop",
1254 },
1255};
1256
1257VNET_FEATURE_ARC_INIT (interface_output, static) =
1258{
1259 .arc_name = "interface-output",
1260 .start_nodes = VNET_FEATURES (0),
1261 .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1262};
1263
Pavel Kotucek3a2a1c42016-12-06 10:10:10 +01001264VNET_FEATURE_INIT (span_tx, static) = {
1265 .arc_name = "interface-output",
1266 .node_name = "span-output",
1267 .runs_before = VNET_FEATURES ("interface-tx"),
1268};
1269
Damjan Marion152e21d2016-11-29 14:55:43 +01001270VNET_FEATURE_INIT (interface_tx, static) = {
1271 .arc_name = "interface-output",
1272 .node_name = "interface-tx",
1273 .runs_before = 0,
1274};
1275/* *INDENT-ON* */
1276
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277clib_error_t *
1278vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1279 u32 hw_if_index,
1280 u32 is_create)
1281{
Dave Barachba868bb2016-08-08 09:51:21 -04001282 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 u32 next_index;
1284
1285 next_index = vlib_node_add_next_with_slot
1286 (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1287 hi->output_node_index,
1288 /* next_index */ hw_if_index);
1289
1290 ASSERT (next_index == hw_if_index);
1291
1292 return 0;
1293}
1294
Dave Barachba868bb2016-08-08 09:51:21 -04001295VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1296 (vnet_per_buffer_interface_output_hw_interface_add_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001297
1298static clib_error_t *
1299pcap_drop_trace_command_fn (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001300 unformat_input_t * input,
1301 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302{
Dave Barachba868bb2016-08-08 09:51:21 -04001303 vnet_main_t *vnm = vnet_get_main ();
1304 vnet_interface_main_t *im = &vnm->interface_main;
1305 u8 *filename;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 u32 max;
1307 int matched = 0;
Dave Barachba868bb2016-08-08 09:51:21 -04001308 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001309
Dave Barachba868bb2016-08-08 09:51:21 -04001310 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001311 {
1312 if (unformat (input, "on"))
Dave Barachba868bb2016-08-08 09:51:21 -04001313 {
1314 if (im->drop_pcap_enable == 0)
1315 {
1316 if (im->pcap_filename == 0)
1317 im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001318
Dave Barachba868bb2016-08-08 09:51:21 -04001319 memset (&im->pcap_main, 0, sizeof (im->pcap_main));
1320 im->pcap_main.file_name = (char *) im->pcap_filename;
1321 im->pcap_main.n_packets_to_capture = 100;
1322 if (im->pcap_pkts_to_capture)
1323 im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture;
1324
1325 im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
1326 im->drop_pcap_enable = 1;
1327 matched = 1;
1328 vlib_cli_output (vm, "pcap drop capture on...");
1329 }
1330 else
1331 {
1332 vlib_cli_output (vm, "pcap drop capture already on...");
1333 }
1334 matched = 1;
1335 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001336 else if (unformat (input, "off"))
Dave Barachba868bb2016-08-08 09:51:21 -04001337 {
1338 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339
Dave Barachba868bb2016-08-08 09:51:21 -04001340 if (im->drop_pcap_enable)
1341 {
1342 vlib_cli_output (vm, "captured %d pkts...",
1343 im->pcap_main.n_packets_captured);
1344 if (im->pcap_main.n_packets_captured)
1345 {
1346 im->pcap_main.n_packets_to_capture =
1347 im->pcap_main.n_packets_captured;
1348 error = pcap_write (&im->pcap_main);
1349 if (error)
1350 clib_error_report (error);
1351 else
1352 vlib_cli_output (vm, "saved to %s...", im->pcap_filename);
1353 }
1354 }
1355 else
1356 {
1357 vlib_cli_output (vm, "pcap drop capture already off...");
1358 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359
Dave Barachba868bb2016-08-08 09:51:21 -04001360 im->drop_pcap_enable = 0;
1361 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362 else if (unformat (input, "max %d", &max))
Dave Barachba868bb2016-08-08 09:51:21 -04001363 {
1364 im->pcap_pkts_to_capture = max;
1365 matched = 1;
1366 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001367
Dave Barachba868bb2016-08-08 09:51:21 -04001368 else if (unformat (input, "intfc %U",
1369 unformat_vnet_sw_interface, vnm,
1370 &im->pcap_sw_if_index))
1371 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372 else if (unformat (input, "intfc any"))
Dave Barachba868bb2016-08-08 09:51:21 -04001373 {
1374 im->pcap_sw_if_index = 0;
1375 matched = 1;
1376 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001377 else if (unformat (input, "file %s", &filename))
Dave Barachba868bb2016-08-08 09:51:21 -04001378 {
1379 u8 *chroot_filename;
1380 /* Brain-police user path input */
1381 if (strstr ((char *) filename, "..")
1382 || index ((char *) filename, '/'))
1383 {
1384 vlib_cli_output (vm, "illegal characters in filename '%s'",
1385 filename);
1386 continue;
1387 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388
Dave Barachba868bb2016-08-08 09:51:21 -04001389 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1390 vec_free (filename);
1391
1392 if (im->pcap_filename)
1393 vec_free (im->pcap_filename);
1394 vec_add1 (filename, 0);
1395 im->pcap_filename = chroot_filename;
1396 matched = 1;
1397 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001398 else if (unformat (input, "status"))
Dave Barachba868bb2016-08-08 09:51:21 -04001399 {
1400 if (im->drop_pcap_enable == 0)
1401 {
1402 vlib_cli_output (vm, "pcap drop capture is off...");
1403 continue;
1404 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405
Dave Barachba868bb2016-08-08 09:51:21 -04001406 vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...",
1407 im->pcap_main.n_packets_captured,
1408 im->pcap_main.n_packets_to_capture);
1409 matched = 1;
1410 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411
1412 else
Dave Barachba868bb2016-08-08 09:51:21 -04001413 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001414 }
1415
1416 if (matched == 0)
Dave Barachba868bb2016-08-08 09:51:21 -04001417 return clib_error_return (0, "unknown input `%U'",
1418 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001419
1420 return 0;
1421}
1422
Dave Barachba868bb2016-08-08 09:51:21 -04001423/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424VLIB_CLI_COMMAND (pcap_trace_command, static) = {
Dave Barachba868bb2016-08-08 09:51:21 -04001425 .path = "pcap drop trace",
1426 .short_help =
1427 "pcap drop trace on off max <nn> intfc <intfc> file <name> status",
1428 .function = pcap_drop_trace_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001429};
Dave Barachba868bb2016-08-08 09:51:21 -04001430/* *INDENT-ON* */
1431
1432/*
1433 * fd.io coding-style-patch-verification: ON
1434 *
1435 * Local Variables:
1436 * eval: (c-set-style "gnu")
1437 * End:
1438 */