blob: 173bb75cf1c08607d2d6def18e1510cbc76cd515 [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>
41
Dave Barachba868bb2016-08-08 09:51:21 -040042typedef struct
43{
Ed Warnickecb9cada2015-12-08 15:45:58 -070044 u32 sw_if_index;
Chris Luke1c9f6ce2016-04-26 10:55:52 -040045 u8 data[128 - sizeof (u32)];
Dave Barachba868bb2016-08-08 09:51:21 -040046}
47interface_output_trace_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Dave Barachba868bb2016-08-08 09:51:21 -040049u8 *
50format_vnet_interface_output_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -070051{
52 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
Dave Barachba868bb2016-08-08 09:51:21 -040053 vlib_node_t *node = va_arg (*va, vlib_node_t *);
54 interface_output_trace_t *t = va_arg (*va, interface_output_trace_t *);
55 vnet_main_t *vnm = vnet_get_main ();
56 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -070057 uword indent;
58
Dave Barachba868bb2016-08-08 09:51:21 -040059 if (t->sw_if_index != (u32) ~ 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -070060 {
61 si = vnet_get_sw_interface (vnm, t->sw_if_index);
62 indent = format_get_indent (s);
Dave Barachba868bb2016-08-08 09:51:21 -040063
Ed Warnickecb9cada2015-12-08 15:45:58 -070064 s = format (s, "%U\n%U%U",
Dave Barachba868bb2016-08-08 09:51:21 -040065 format_vnet_sw_interface_name, vnm, si,
66 format_white_space, indent,
67 node->format_buffer ? node->
68 format_buffer : format_hex_bytes, t->data,
69 sizeof (t->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -070070 }
71 return s;
72}
73
74static void
75vnet_interface_output_trace (vlib_main_t * vm,
76 vlib_node_runtime_t * node,
Dave Barachba868bb2016-08-08 09:51:21 -040077 vlib_frame_t * frame, uword n_buffers)
Ed Warnickecb9cada2015-12-08 15:45:58 -070078{
Dave Barachba868bb2016-08-08 09:51:21 -040079 u32 n_left, *from;
Ed Warnickecb9cada2015-12-08 15:45:58 -070080
81 n_left = n_buffers;
82 from = vlib_frame_args (frame);
Dave Barachba868bb2016-08-08 09:51:21 -040083
Ed Warnickecb9cada2015-12-08 15:45:58 -070084 while (n_left >= 4)
85 {
86 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -040087 vlib_buffer_t *b0, *b1;
88 interface_output_trace_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070089
90 /* Prefetch next iteration. */
91 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
92 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
93
94 bi0 = from[0];
95 bi1 = from[1];
96
97 b0 = vlib_get_buffer (vm, bi0);
98 b1 = vlib_get_buffer (vm, bi1);
99
100 if (b0->flags & VLIB_BUFFER_IS_TRACED)
101 {
102 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
103 t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Damjan Marionf1213b82016-03-13 02:22:06 +0100104 clib_memcpy (t0->data, vlib_buffer_get_current (b0),
Dave Barachba868bb2016-08-08 09:51:21 -0400105 sizeof (t0->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106 }
107 if (b1->flags & VLIB_BUFFER_IS_TRACED)
108 {
109 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
110 t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX];
Damjan Marionf1213b82016-03-13 02:22:06 +0100111 clib_memcpy (t1->data, vlib_buffer_get_current (b1),
Dave Barachba868bb2016-08-08 09:51:21 -0400112 sizeof (t1->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113 }
114 from += 2;
115 n_left -= 2;
116 }
117
118 while (n_left >= 1)
119 {
120 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400121 vlib_buffer_t *b0;
122 interface_output_trace_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
124 bi0 = from[0];
125
126 b0 = vlib_get_buffer (vm, bi0);
127
128 if (b0->flags & VLIB_BUFFER_IS_TRACED)
129 {
130 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
131 t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Damjan Marionf1213b82016-03-13 02:22:06 +0100132 clib_memcpy (t0->data, vlib_buffer_get_current (b0),
Dave Barachba868bb2016-08-08 09:51:21 -0400133 sizeof (t0->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 }
135 from += 1;
136 n_left -= 1;
137 }
138}
139
140static never_inline u32
141slow_path (vlib_main_t * vm,
142 u32 bi,
143 vlib_buffer_t * b,
Dave Barachba868bb2016-08-08 09:51:21 -0400144 u32 n_left_to_tx, u32 * to_tx, u32 * n_slow_bytes_result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145{
146 /* We've already enqueued a single buffer. */
147 u32 n_buffers = 0;
148 u32 n_slow_bytes = 0;
149
150 while (n_left_to_tx > 0)
151 {
152 to_tx[0] = bi;
153 to_tx += 1;
154 n_left_to_tx -= 1;
155 n_buffers += 1;
156 n_slow_bytes += vlib_buffer_length_in_chain (vm, b);
157
158 /* Be grumpy about zero length buffers for benefit of
Dave Barachba868bb2016-08-08 09:51:21 -0400159 driver tx function. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 ASSERT (b->current_length > 0);
161
Dave Barachba868bb2016-08-08 09:51:21 -0400162 if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 break;
164
165 bi = b->next_buffer;
166 b = vlib_get_buffer (vm, bi);
167 }
168
169 /* Ran out of space in next frame trying to enqueue buffers? */
170 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
171 return 0;
172
173 *n_slow_bytes_result = n_slow_bytes;
174 return n_buffers;
175}
176
Dave Barachba868bb2016-08-08 09:51:21 -0400177/*
178 * Increment TX stats. Roll up consecutive increments to the same sw_if_index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 * into one increment.
180 */
Dave Barachba868bb2016-08-08 09:51:21 -0400181static_always_inline void
182incr_output_stats (vnet_main_t * vnm,
183 u32 cpu_index,
184 u32 length,
185 u32 sw_if_index,
186 u32 * last_sw_if_index, u32 * n_packets, u32 * n_bytes)
187{
188 vnet_interface_main_t *im;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189
Dave Barachba868bb2016-08-08 09:51:21 -0400190 if (PREDICT_TRUE (sw_if_index == *last_sw_if_index))
191 {
192 *n_packets += 1;
193 *n_bytes += length;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194 }
Dave Barachba868bb2016-08-08 09:51:21 -0400195 else
196 {
197 if (PREDICT_TRUE (*last_sw_if_index != ~0))
198 {
199 im = &vnm->interface_main;
200
201 vlib_increment_combined_counter (im->combined_sw_if_counters
202 + VNET_INTERFACE_COUNTER_TX,
203 cpu_index,
204 *last_sw_if_index,
205 *n_packets, *n_bytes);
206 }
207 *last_sw_if_index = sw_if_index;
208 *n_packets = 1;
209 *n_bytes = length;
210 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211}
212
213
214/* Interface output functions. */
215uword
216vnet_interface_output_node (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400217 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218{
Dave Barachba868bb2016-08-08 09:51:21 -0400219 vnet_main_t *vnm = vnet_get_main ();
220 vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
221 vnet_sw_interface_t *si;
222 vnet_hw_interface_t *hi;
223 u32 n_left_to_tx, *from, *from_end, *to_tx;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 u32 n_bytes, n_buffers, n_packets;
225 u32 last_sw_if_index;
226 u32 cpu_index = vm->cpu_index;
227
228 n_buffers = frame->n_vectors;
229
230 if (node->flags & VLIB_NODE_FLAG_TRACE)
231 vnet_interface_output_trace (vm, node, frame, n_buffers);
232
233 from = vlib_frame_args (frame);
234
235 if (rt->is_deleted)
Dave Barachba868bb2016-08-08 09:51:21 -0400236 return vlib_error_drop_buffers (vm, node, from,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 /* buffer stride */ 1,
238 n_buffers,
239 VNET_INTERFACE_OUTPUT_NEXT_DROP,
240 node->node_index,
241 VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
242
243 si = vnet_get_sw_interface (vnm, rt->sw_if_index);
244 hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
Dave Barachba868bb2016-08-08 09:51:21 -0400245 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ||
246 !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 {
Dave Barachba868bb2016-08-08 09:51:21 -0400248 vlib_simple_counter_main_t *cm;
249
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
Dave Barachba868bb2016-08-08 09:51:21 -0400251 VNET_INTERFACE_COUNTER_TX_ERROR);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 vlib_increment_simple_counter (cm, cpu_index,
Dave Barachba868bb2016-08-08 09:51:21 -0400253 rt->sw_if_index, n_buffers);
254 return vlib_error_drop_buffers (vm, node, from,
255 /* buffer stride */ 1,
256 n_buffers,
257 VNET_INTERFACE_OUTPUT_NEXT_DROP,
258 node->node_index,
259 VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 }
261
262 from_end = from + n_buffers;
263
264 /* Total byte count of all buffers. */
265 n_bytes = 0;
266 n_packets = 0;
267 last_sw_if_index = ~0;
268
269 while (from < from_end)
270 {
271 /* Get new next frame since previous incomplete frame may have less
Dave Barachba868bb2016-08-08 09:51:21 -0400272 than VNET_FRAME_SIZE vectors in it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273 vlib_get_new_next_frame (vm, node, VNET_INTERFACE_OUTPUT_NEXT_TX,
274 to_tx, n_left_to_tx);
275
276 while (from + 4 <= from_end && n_left_to_tx >= 2)
277 {
278 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400279 vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280
281 /* Prefetch next iteration. */
282 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
283 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
284
285 bi0 = from[0];
286 bi1 = from[1];
287 to_tx[0] = bi0;
288 to_tx[1] = bi1;
289 from += 2;
290 to_tx += 2;
291 n_left_to_tx -= 2;
292
293 b0 = vlib_get_buffer (vm, bi0);
294 b1 = vlib_get_buffer (vm, bi1);
295
296 /* Be grumpy about zero length buffers for benefit of
297 driver tx function. */
298 ASSERT (b0->current_length > 0);
299 ASSERT (b1->current_length > 0);
300
Dave Barachba868bb2016-08-08 09:51:21 -0400301 if (PREDICT_FALSE
302 ((b0->flags | b1->flags) & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303 {
304 u32 n_buffers, n_slow_bytes, i;
305
306 /* Undo. */
307 from -= 2;
308 to_tx -= 2;
309 n_left_to_tx += 2;
310
311 /* Do slow path two times. */
312 for (i = 0; i < 2; i++)
313 {
314 u32 bi = i ? bi1 : bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400315 vlib_buffer_t *b = i ? b1 : b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316
317 n_buffers = slow_path (vm, bi, b,
318 n_left_to_tx, to_tx, &n_slow_bytes);
319
320 /* Not enough room for single packet? */
321 if (n_buffers == 0)
322 goto put;
323
324 from += 1;
325 to_tx += n_buffers;
326 n_left_to_tx -= n_buffers;
327 incr_output_stats (vnm, cpu_index, n_slow_bytes,
Dave Barachba868bb2016-08-08 09:51:21 -0400328 vnet_buffer (b)->sw_if_index[VLIB_TX],
329 &last_sw_if_index, &n_packets, &n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 }
Dave Barachba868bb2016-08-08 09:51:21 -0400331 }
332 else
333 {
334 incr_output_stats (vnm, cpu_index,
335 vlib_buffer_length_in_chain (vm, b0),
336 vnet_buffer (b0)->sw_if_index[VLIB_TX],
337 &last_sw_if_index, &n_packets, &n_bytes);
338 incr_output_stats (vnm, cpu_index,
339 vlib_buffer_length_in_chain (vm, b0),
340 vnet_buffer (b1)->sw_if_index[VLIB_TX],
341 &last_sw_if_index, &n_packets, &n_bytes);
342 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 }
344
345 while (from + 1 <= from_end && n_left_to_tx >= 1)
346 {
347 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400348 vlib_buffer_t *b0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349
350 bi0 = from[0];
351 to_tx[0] = bi0;
352 from += 1;
353 to_tx += 1;
354 n_left_to_tx -= 1;
355
356 b0 = vlib_get_buffer (vm, bi0);
357
358 /* Be grumpy about zero length buffers for benefit of
359 driver tx function. */
360 ASSERT (b0->current_length > 0);
361
362 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_NEXT_PRESENT))
363 {
364 u32 n_buffers, n_slow_bytes;
365
366 /* Undo. */
367 from -= 1;
368 to_tx -= 1;
369 n_left_to_tx += 1;
370
371 n_buffers = slow_path (vm, bi0, b0,
372 n_left_to_tx, to_tx, &n_slow_bytes);
373
374 /* Not enough room for single packet? */
375 if (n_buffers == 0)
376 goto put;
377
378 from += 1;
379 to_tx += n_buffers;
380 n_left_to_tx -= n_buffers;
381 }
Dave Barachba868bb2016-08-08 09:51:21 -0400382 incr_output_stats (vnm, cpu_index,
383 vlib_buffer_length_in_chain (vm, b0),
384 vnet_buffer (b0)->sw_if_index[VLIB_TX],
385 &last_sw_if_index, &n_packets, &n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386 }
387
388 put:
Dave Barachba868bb2016-08-08 09:51:21 -0400389 vlib_put_next_frame (vm, node, VNET_INTERFACE_OUTPUT_NEXT_TX,
390 n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 }
392
393 /* Final update of interface stats. */
Dave Barachba868bb2016-08-08 09:51:21 -0400394 incr_output_stats (vnm, cpu_index, 0, ~0, /* ~0 will flush stats */
395 &last_sw_if_index, &n_packets, &n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396
397 return n_buffers;
398}
399
Dave Barachba868bb2016-08-08 09:51:21 -0400400VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
401CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200403always_inline uword
Dave Barachba868bb2016-08-08 09:51:21 -0400404vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
405 vlib_node_runtime_t * node,
406 vlib_frame_t * frame,
407 int with_features)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408{
Dave Barachba868bb2016-08-08 09:51:21 -0400409 vnet_main_t *vnm = vnet_get_main ();
410 vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
411 vnet_sw_interface_t *si;
412 vnet_hw_interface_t *hi;
413 u32 n_left_to_tx, *from, *from_end, *to_tx;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 u32 n_bytes, n_buffers, n_packets;
415 u32 n_bytes_b0, n_bytes_b1;
416 u32 cpu_index = vm->cpu_index;
Dave Barachba868bb2016-08-08 09:51:21 -0400417 vnet_interface_main_t *im = &vnm->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418 u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
419
420 n_buffers = frame->n_vectors;
421
422 if (node->flags & VLIB_NODE_FLAG_TRACE)
423 vnet_interface_output_trace (vm, node, frame, n_buffers);
424
425 from = vlib_frame_args (frame);
426
427 if (rt->is_deleted)
Dave Barachba868bb2016-08-08 09:51:21 -0400428 return vlib_error_drop_buffers (vm, node, from,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700429 /* buffer stride */ 1,
430 n_buffers,
431 VNET_INTERFACE_OUTPUT_NEXT_DROP,
432 node->node_index,
433 VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
434
435 si = vnet_get_sw_interface (vnm, rt->sw_if_index);
436 hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
Dave Barachba868bb2016-08-08 09:51:21 -0400437 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ||
438 !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439 {
Dave Barachba868bb2016-08-08 09:51:21 -0400440 vlib_simple_counter_main_t *cm;
441
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
Dave Barachba868bb2016-08-08 09:51:21 -0400443 VNET_INTERFACE_COUNTER_TX_ERROR);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444 vlib_increment_simple_counter (cm, cpu_index,
Dave Barachba868bb2016-08-08 09:51:21 -0400445 rt->sw_if_index, n_buffers);
446
447 return vlib_error_drop_buffers (vm, node, from,
448 /* buffer stride */ 1,
449 n_buffers,
450 VNET_INTERFACE_OUTPUT_NEXT_DROP,
451 node->node_index,
452 VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453 }
454
455 from_end = from + n_buffers;
456
457 /* Total byte count of all buffers. */
458 n_bytes = 0;
459 n_packets = 0;
460
461 while (from < from_end)
462 {
463 /* Get new next frame since previous incomplete frame may have less
Dave Barachba868bb2016-08-08 09:51:21 -0400464 than VNET_FRAME_SIZE vectors in it. */
465 vlib_get_new_next_frame (vm, node, next_index, to_tx, n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466
467 while (from + 4 <= from_end && n_left_to_tx >= 2)
468 {
469 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400470 vlib_buffer_t *b0, *b1;
471 u32 tx_swif0, tx_swif1;
472 u32 next0, next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700473
474 /* Prefetch next iteration. */
475 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
476 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
477
478 bi0 = from[0];
479 bi1 = from[1];
480 to_tx[0] = bi0;
481 to_tx[1] = bi1;
482 from += 2;
483 to_tx += 2;
484 n_left_to_tx -= 2;
485
486 b0 = vlib_get_buffer (vm, bi0);
487 b1 = vlib_get_buffer (vm, bi1);
488
489 /* Be grumpy about zero length buffers for benefit of
490 driver tx function. */
491 ASSERT (b0->current_length > 0);
492 ASSERT (b1->current_length > 0);
493
Dave Barachba868bb2016-08-08 09:51:21 -0400494 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
495 n_bytes_b1 = vlib_buffer_length_in_chain (vm, b1);
496 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
497 tx_swif1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498
499 n_bytes += n_bytes_b0 + n_bytes_b1;
500 n_packets += 2;
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200501 if (with_features)
Dave Barachba868bb2016-08-08 09:51:21 -0400502 {
503 b0->flags |= BUFFER_OUTPUT_FEAT_DONE;
504 vnet_buffer (b0)->output_features.bitmap =
505 si->output_feature_bitmap;
506 count_trailing_zeros (next0,
507 vnet_buffer (b0)->output_features.bitmap);
508 vnet_buffer (b0)->output_features.bitmap &= ~(1 << next0);
509 }
510 else
511 {
512 next0 = VNET_INTERFACE_OUTPUT_NEXT_TX;
513 vnet_buffer (b0)->output_features.bitmap = 0;
514
515 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
516 {
517 /* update vlan subif tx counts, if required */
518 vlib_increment_combined_counter (im->combined_sw_if_counters
519 +
520 VNET_INTERFACE_COUNTER_TX,
521 cpu_index, tx_swif0, 1,
522 n_bytes_b0);
523 }
524 }
525
526 if (with_features)
527 {
528 b1->flags |= BUFFER_OUTPUT_FEAT_DONE;
529 vnet_buffer (b1)->output_features.bitmap =
530 si->output_feature_bitmap;
531 count_trailing_zeros (next1,
532 vnet_buffer (b1)->output_features.bitmap);
533 vnet_buffer (b1)->output_features.bitmap &= ~(1 << next1);
534 }
535 else
536 {
537 next1 = VNET_INTERFACE_OUTPUT_NEXT_TX;
538 vnet_buffer (b1)->output_features.bitmap = 0;
539
540 /* update vlan subif tx counts, if required */
541 if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
542 {
543
544 vlib_increment_combined_counter (im->combined_sw_if_counters
545 +
546 VNET_INTERFACE_COUNTER_TX,
547 cpu_index, tx_swif1, 1,
548 n_bytes_b1);
549 }
550 }
551 if (with_features)
552 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_tx,
553 n_left_to_tx, bi0, bi1, next0,
554 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555 }
556
557 while (from + 1 <= from_end && n_left_to_tx >= 1)
558 {
559 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400560 vlib_buffer_t *b0;
561 u32 tx_swif0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700562
563 bi0 = from[0];
564 to_tx[0] = bi0;
565 from += 1;
566 to_tx += 1;
567 n_left_to_tx -= 1;
568
569 b0 = vlib_get_buffer (vm, bi0);
570
571 /* Be grumpy about zero length buffers for benefit of
572 driver tx function. */
573 ASSERT (b0->current_length > 0);
574
Dave Barachba868bb2016-08-08 09:51:21 -0400575 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
576 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700577 n_bytes += n_bytes_b0;
578 n_packets += 1;
579
Dave Barachba868bb2016-08-08 09:51:21 -0400580 if (with_features)
581 {
582 u32 next0;
583 b0->flags |= BUFFER_OUTPUT_FEAT_DONE;
584 vnet_buffer (b0)->output_features.bitmap =
585 si->output_feature_bitmap;
586 count_trailing_zeros (next0,
587 vnet_buffer (b0)->output_features.bitmap);
588 vnet_buffer (b0)->output_features.bitmap &= ~(1 << next0);
589 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_tx,
590 n_left_to_tx, bi0, next0);
591 }
592 else
593 {
594 vnet_buffer (b0)->output_features.bitmap = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595
Dave Barachba868bb2016-08-08 09:51:21 -0400596 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
597 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598
Dave Barachba868bb2016-08-08 09:51:21 -0400599 vlib_increment_combined_counter (im->combined_sw_if_counters
600 +
601 VNET_INTERFACE_COUNTER_TX,
602 cpu_index, tx_swif0, 1,
603 n_bytes_b0);
604 }
605 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700606 }
607
Dave Barachba868bb2016-08-08 09:51:21 -0400608 vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609 }
610
611 /* Update main interface stats. */
612 vlib_increment_combined_counter (im->combined_sw_if_counters
Dave Barachba868bb2016-08-08 09:51:21 -0400613 + VNET_INTERFACE_COUNTER_TX,
614 cpu_index,
615 rt->sw_if_index, n_packets, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700616 return n_buffers;
617}
618
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200619uword
620vnet_interface_output_node_no_flatten (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400621 vlib_node_runtime_t * node,
622 vlib_frame_t * frame)
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200623{
Dave Barachba868bb2016-08-08 09:51:21 -0400624 vnet_main_t *vnm = vnet_get_main ();
625 vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
626 vnet_sw_interface_t *si;
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200627 si = vnet_get_sw_interface (vnm, rt->sw_if_index);
628
Dave Barachba868bb2016-08-08 09:51:21 -0400629 if (PREDICT_FALSE (si->output_feature_bitmap))
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200630 {
631 /* if first pakcet in the frame have BUFFER_OUTPUT_FEAT_DONE flag set
Dave Barachba868bb2016-08-08 09:51:21 -0400632 then whole frame is arriving from feature node */
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200633
Dave Barachba868bb2016-08-08 09:51:21 -0400634 u32 *from = vlib_frame_args (frame);
635 vlib_buffer_t *b = vlib_get_buffer (vm, from[0]);
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200636
637 if ((b->flags & BUFFER_OUTPUT_FEAT_DONE) == 0)
Dave Barachba868bb2016-08-08 09:51:21 -0400638 return vnet_interface_output_node_no_flatten_inline (vm, node, frame,
639 1);
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200640 }
Dave Barachba868bb2016-08-08 09:51:21 -0400641 return vnet_interface_output_node_no_flatten_inline (vm, node, frame, 0);
Damjan Marion6c56a3c2016-06-10 19:26:54 +0200642}
643
Dave Barachba868bb2016-08-08 09:51:21 -0400644VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node_no_flatten);
645CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node_no_flatten);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646
647/* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
648static uword
649vnet_per_buffer_interface_output (vlib_main_t * vm,
650 vlib_node_runtime_t * node,
651 vlib_frame_t * frame)
652{
Dave Barachba868bb2016-08-08 09:51:21 -0400653 vnet_main_t *vnm = vnet_get_main ();
654 u32 n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655 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;
Dave Barachba868bb2016-08-08 09:51:21 -0400669 vlib_buffer_t *b0, *b1;
670 vnet_hw_interface_t *hi0, *hi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671
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
Dave Barachba868bb2016-08-08 09:51:21 -0400688 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]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700696
697 next0 = hi0->hw_if_index;
698 next1 = hi1->hw_if_index;
699
Dave Barachba868bb2016-08-08 09:51:21 -0400700 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
701 n_left_to_next, bi0, bi1, next0,
702 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703 }
704
705 while (n_left_from > 0 && n_left_to_next > 0)
706 {
707 u32 bi0, next0;
Dave Barachba868bb2016-08-08 09:51:21 -0400708 vlib_buffer_t *b0;
709 vnet_hw_interface_t *hi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710
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
Dave Barachba868bb2016-08-08 09:51:21 -0400720 hi0 =
721 vnet_get_sup_hw_interface (vnm,
722 vnet_buffer (b0)->sw_if_index
723 [VLIB_TX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724
725 next0 = hi0->hw_if_index;
726
Dave Barachba868bb2016-08-08 09:51:21 -0400727 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
728 n_left_to_next, bi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700729 }
730
731 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
732 }
733
734 return frame->n_vectors;
735}
736
737always_inline u32
738counter_index (vlib_main_t * vm, vlib_error_t e)
739{
Dave Barachba868bb2016-08-08 09:51:21 -0400740 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741 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
Dave Barachba868bb2016-08-08 09:51:21 -0400754static u8 *
755format_vnet_error_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756{
Dave Barachba868bb2016-08-08 09:51:21 -0400757 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700758 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
Dave Barachba868bb2016-08-08 09:51:21 -0400759 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;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762 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
771static void
772trace_errors_with_buffers (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400773 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774{
Dave Barachba868bb2016-08-08 09:51:21 -0400775 u32 n_left, *buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700776
777 buffers = vlib_frame_vector_args (frame);
778 n_left = frame->n_vectors;
Dave Barachba868bb2016-08-08 09:51:21 -0400779
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780 while (n_left >= 4)
781 {
782 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400783 vlib_buffer_t *b0, *b1;
784 vlib_error_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700785
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;
Dave Barachba868bb2016-08-08 09:51:21 -0400813 vlib_buffer_t *b0;
814 vlib_error_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
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
830static u8 *
831validate_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]);
Dave Barachba868bb2016-08-08 09:51:21 -0400835 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700836
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
849static u8 *
850validate_error_frame (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400851 vlib_node_runtime_t * node, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852{
Dave Barachba868bb2016-08-08 09:51:21 -0400853 u32 *buffers = vlib_frame_args (f);
854 vlib_buffer_t *b;
855 u8 *msg = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856 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
Dave Barachba868bb2016-08-08 09:51:21 -0400869typedef enum
870{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700871 VNET_ERROR_DISPOSITION_DROP,
872 VNET_ERROR_DISPOSITION_PUNT,
873 VNET_ERROR_N_DISPOSITION,
874} vnet_error_disposition_t;
875
876always_inline void
877do_packet (vlib_main_t * vm, vlib_error_t a)
878{
Dave Barachba868bb2016-08-08 09:51:21 -0400879 vlib_error_main_t *em = &vm->error_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880 u32 i = counter_index (vm, a);
881 em->counters[i] += 1;
882 vlib_error_elog_count (vm, i, 1);
883}
Dave Barachba868bb2016-08-08 09:51:21 -0400884
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885static_always_inline uword
886process_drop_punt (vlib_main_t * vm,
887 vlib_node_runtime_t * node,
Dave Barachba868bb2016-08-08 09:51:21 -0400888 vlib_frame_t * frame, vnet_error_disposition_t disposition)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889{
Dave Barachba868bb2016-08-08 09:51:21 -0400890 vnet_main_t *vnm = vnet_get_main ();
891 vlib_error_main_t *em = &vm->error_main;
892 u32 *buffers, *first_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700893 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;
Dave Barachba868bb2016-08-08 09:51:21 -0400897 vlib_simple_counter_main_t *cm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898 u32 cpu_index = vm->cpu_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 {
Dave Barachba868bb2016-08-08 09:51:21 -0400907 vlib_buffer_t *b = vlib_get_buffer (vm, first_buffer[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908
Dave Barachba868bb2016-08-08 09:51:21 -0400909 if (!memory_init[disposition])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 {
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);
Dave Barachba868bb2016-08-08 09:51:21 -0400925
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926 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 {
Dave Barachba868bb2016-08-08 09:51:21 -0400934 vlib_buffer_t *b0, *b1;
935 vnet_sw_interface_t *sw_if0, *sw_if1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700936 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
Dave Barachba868bb2016-08-08 09:51:21 -0400959 to current (node, code). */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960 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, cpu_index, sw_if_index0, 1);
971 vlib_increment_simple_counter (cm, cpu_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
Dave Barachba868bb2016-08-08 09:51:21 -0400977 (cm, cpu_index, sw_if0->sup_sw_if_index,
978 sw_if0->sup_sw_if_index != sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979
980 sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1);
981 vlib_increment_simple_counter
Dave Barachba868bb2016-08-08 09:51:21 -0400982 (cm, cpu_index, sw_if1->sup_sw_if_index,
983 sw_if1->sup_sw_if_index != sw_if_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700984
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 {
Dave Barachba868bb2016-08-08 09:51:21 -04001001 vlib_buffer_t *b0;
1002 vnet_sw_interface_t *sw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001003 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, cpu_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);
Dave Barachba868bb2016-08-08 09:51:21 -04001022 vlib_increment_simple_counter (cm, cpu_index, sw_if0->sup_sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 sw_if0->sup_sw_if_index != sw_if_index0);
1024
1025 if (PREDICT_FALSE (e0 != current_error))
1026 {
1027 current_counter -= 1;
1028
1029 vlib_error_elog_count (vm, current_counter_index,
1030 (current_counter
1031 - em->counters[current_counter_index]));
Dave Barachba868bb2016-08-08 09:51:21 -04001032
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033 em->counters[current_counter_index] = current_counter;
1034
1035 do_packet (vm, e0);
1036 current_error = e0;
1037 current_counter_index = counter_index (vm, e0);
1038 current_counter = em->counters[current_counter_index];
1039 }
1040 }
1041
1042 if (n_errors_current_sw_if_index > 0)
1043 {
Dave Barachba868bb2016-08-08 09:51:21 -04001044 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045
1046 vlib_increment_simple_counter (cm, cpu_index, current_sw_if_index,
1047 n_errors_current_sw_if_index);
1048
1049 si = vnet_get_sw_interface (vnm, current_sw_if_index);
1050 if (si->sup_sw_if_index != current_sw_if_index)
Dave Barachba868bb2016-08-08 09:51:21 -04001051 vlib_increment_simple_counter (cm, cpu_index, si->sup_sw_if_index,
1052 n_errors_current_sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001053 }
1054
1055 vlib_error_elog_count (vm, current_counter_index,
1056 (current_counter
1057 - em->counters[current_counter_index]));
1058
1059 /* Return cached counter. */
1060 em->counters[current_counter_index] = current_counter;
1061
1062 /* Save memory for next iteration. */
1063 memory[disposition] = current_error;
1064
Dave Barachba868bb2016-08-08 09:51:21 -04001065 if (disposition == VNET_ERROR_DISPOSITION_DROP || !vm->os_punt_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001066 {
Dave Barachba868bb2016-08-08 09:51:21 -04001067 vlib_buffer_free (vm, first_buffer, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068
1069 /* If there is no punt function, free the frame as well. */
Dave Barachba868bb2016-08-08 09:51:21 -04001070 if (disposition == VNET_ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 vlib_frame_free (vm, node, frame);
1072 }
1073 else
1074 vm->os_punt_frame (vm, node, frame);
1075
1076 return frame->n_vectors;
1077}
1078
Dave Barachba868bb2016-08-08 09:51:21 -04001079static inline void
1080pcap_drop_trace (vlib_main_t * vm,
1081 vnet_interface_main_t * im, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082{
Dave Barachba868bb2016-08-08 09:51:21 -04001083 u32 *from;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 u32 n_left = f->n_vectors;
Dave Barachba868bb2016-08-08 09:51:21 -04001085 vlib_buffer_t *b0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086 u32 bi0;
1087 i16 save_current_data;
1088 u16 save_current_length;
1089
1090 from = vlib_frame_vector_args (f);
1091
1092 while (n_left > 0)
1093 {
1094 if (PREDICT_TRUE (n_left > 1))
Dave Barachba868bb2016-08-08 09:51:21 -04001095 {
1096 p1 = vlib_get_buffer (vm, from[1]);
1097 vlib_prefetch_buffer_header (p1, LOAD);
1098 }
1099
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100 bi0 = from[0];
1101 b0 = vlib_get_buffer (vm, bi0);
1102 from++;
1103 n_left--;
Dave Barachba868bb2016-08-08 09:51:21 -04001104
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105 /* See if we're pointedly ignoring this specific error */
Dave Barachba868bb2016-08-08 09:51:21 -04001106 if (im->pcap_drop_filter_hash
1107 && hash_get (im->pcap_drop_filter_hash, b0->error))
1108 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109
1110 /* Trace all drops, or drops received on a specific interface */
1111 if (im->pcap_sw_if_index == 0 ||
Dave Barachba868bb2016-08-08 09:51:21 -04001112 im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
1113 {
1114 save_current_data = b0->current_data;
1115 save_current_length = b0->current_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116
Dave Barachba868bb2016-08-08 09:51:21 -04001117 /*
1118 * Typically, we'll need to rewind the buffer
1119 */
1120 if (b0->current_data > 0)
1121 vlib_buffer_advance (b0, (word) - b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122
Dave Barachba868bb2016-08-08 09:51:21 -04001123 pcap_add_buffer (&im->pcap_main, vm, bi0, 512);
1124
1125 b0->current_data = save_current_data;
1126 b0->current_length = save_current_length;
1127 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128 }
1129}
1130
Dave Barachba868bb2016-08-08 09:51:21 -04001131void
1132vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001133{
Dave Barachba868bb2016-08-08 09:51:21 -04001134 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001135
1136 if (im->pcap_drop_filter_hash == 0)
Dave Barachba868bb2016-08-08 09:51:21 -04001137 im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138
1139 if (is_add)
1140 hash_set (im->pcap_drop_filter_hash, error_index, 1);
1141 else
1142 hash_unset (im->pcap_drop_filter_hash, error_index);
1143}
1144
1145static uword
1146process_drop (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001147 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148{
Dave Barachba868bb2016-08-08 09:51:21 -04001149 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001150
1151 if (PREDICT_FALSE (im->drop_pcap_enable))
1152 pcap_drop_trace (vm, im, frame);
1153
1154 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
1155}
1156
1157static uword
1158process_punt (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001159 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001160{
1161 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
1162}
1163
Dave Barachba868bb2016-08-08 09:51:21 -04001164/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001165VLIB_REGISTER_NODE (drop_buffers,static) = {
1166 .function = process_drop,
1167 .name = "error-drop",
1168 .flags = VLIB_NODE_FLAG_IS_DROP,
1169 .vector_size = sizeof (u32),
1170 .format_trace = format_vnet_error_trace,
1171 .validate_frame = validate_error_frame,
1172};
Dave Barachba868bb2016-08-08 09:51:21 -04001173/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001174
Dave Barachba868bb2016-08-08 09:51:21 -04001175VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001176
Dave Barachba868bb2016-08-08 09:51:21 -04001177/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001178VLIB_REGISTER_NODE (punt_buffers,static) = {
1179 .function = process_punt,
1180 .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
1181 | VLIB_NODE_FLAG_IS_PUNT),
1182 .name = "error-punt",
1183 .vector_size = sizeof (u32),
1184 .format_trace = format_vnet_error_trace,
1185 .validate_frame = validate_error_frame,
1186};
Dave Barachba868bb2016-08-08 09:51:21 -04001187/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001188
Dave Barachba868bb2016-08-08 09:51:21 -04001189VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001190
Dave Barachba868bb2016-08-08 09:51:21 -04001191/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001192VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
1193 .function = vnet_per_buffer_interface_output,
1194 .name = "interface-output",
1195 .vector_size = sizeof (u32),
1196};
Dave Barachba868bb2016-08-08 09:51:21 -04001197/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001198
Dave Barachba868bb2016-08-08 09:51:21 -04001199VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
1200 vnet_per_buffer_interface_output);
Damjan Marion1c80e832016-05-11 23:07:18 +02001201
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202clib_error_t *
1203vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1204 u32 hw_if_index,
1205 u32 is_create)
1206{
Dave Barachba868bb2016-08-08 09:51:21 -04001207 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001208 u32 next_index;
1209
1210 next_index = vlib_node_add_next_with_slot
1211 (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1212 hi->output_node_index,
1213 /* next_index */ hw_if_index);
1214
1215 ASSERT (next_index == hw_if_index);
1216
1217 return 0;
1218}
1219
Dave Barachba868bb2016-08-08 09:51:21 -04001220VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1221 (vnet_per_buffer_interface_output_hw_interface_add_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001222
1223static clib_error_t *
1224pcap_drop_trace_command_fn (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001225 unformat_input_t * input,
1226 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227{
Dave Barachba868bb2016-08-08 09:51:21 -04001228 vnet_main_t *vnm = vnet_get_main ();
1229 vnet_interface_main_t *im = &vnm->interface_main;
1230 u8 *filename;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231 u32 max;
1232 int matched = 0;
Dave Barachba868bb2016-08-08 09:51:21 -04001233 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234
Dave Barachba868bb2016-08-08 09:51:21 -04001235 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236 {
1237 if (unformat (input, "on"))
Dave Barachba868bb2016-08-08 09:51:21 -04001238 {
1239 if (im->drop_pcap_enable == 0)
1240 {
1241 if (im->pcap_filename == 0)
1242 im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243
Dave Barachba868bb2016-08-08 09:51:21 -04001244 memset (&im->pcap_main, 0, sizeof (im->pcap_main));
1245 im->pcap_main.file_name = (char *) im->pcap_filename;
1246 im->pcap_main.n_packets_to_capture = 100;
1247 if (im->pcap_pkts_to_capture)
1248 im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture;
1249
1250 im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
1251 im->drop_pcap_enable = 1;
1252 matched = 1;
1253 vlib_cli_output (vm, "pcap drop capture on...");
1254 }
1255 else
1256 {
1257 vlib_cli_output (vm, "pcap drop capture already on...");
1258 }
1259 matched = 1;
1260 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001261 else if (unformat (input, "off"))
Dave Barachba868bb2016-08-08 09:51:21 -04001262 {
1263 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001264
Dave Barachba868bb2016-08-08 09:51:21 -04001265 if (im->drop_pcap_enable)
1266 {
1267 vlib_cli_output (vm, "captured %d pkts...",
1268 im->pcap_main.n_packets_captured);
1269 if (im->pcap_main.n_packets_captured)
1270 {
1271 im->pcap_main.n_packets_to_capture =
1272 im->pcap_main.n_packets_captured;
1273 error = pcap_write (&im->pcap_main);
1274 if (error)
1275 clib_error_report (error);
1276 else
1277 vlib_cli_output (vm, "saved to %s...", im->pcap_filename);
1278 }
1279 }
1280 else
1281 {
1282 vlib_cli_output (vm, "pcap drop capture already off...");
1283 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284
Dave Barachba868bb2016-08-08 09:51:21 -04001285 im->drop_pcap_enable = 0;
1286 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001287 else if (unformat (input, "max %d", &max))
Dave Barachba868bb2016-08-08 09:51:21 -04001288 {
1289 im->pcap_pkts_to_capture = max;
1290 matched = 1;
1291 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001292
Dave Barachba868bb2016-08-08 09:51:21 -04001293 else if (unformat (input, "intfc %U",
1294 unformat_vnet_sw_interface, vnm,
1295 &im->pcap_sw_if_index))
1296 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001297 else if (unformat (input, "intfc any"))
Dave Barachba868bb2016-08-08 09:51:21 -04001298 {
1299 im->pcap_sw_if_index = 0;
1300 matched = 1;
1301 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302 else if (unformat (input, "file %s", &filename))
Dave Barachba868bb2016-08-08 09:51:21 -04001303 {
1304 u8 *chroot_filename;
1305 /* Brain-police user path input */
1306 if (strstr ((char *) filename, "..")
1307 || index ((char *) filename, '/'))
1308 {
1309 vlib_cli_output (vm, "illegal characters in filename '%s'",
1310 filename);
1311 continue;
1312 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313
Dave Barachba868bb2016-08-08 09:51:21 -04001314 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1315 vec_free (filename);
1316
1317 if (im->pcap_filename)
1318 vec_free (im->pcap_filename);
1319 vec_add1 (filename, 0);
1320 im->pcap_filename = chroot_filename;
1321 matched = 1;
1322 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 else if (unformat (input, "status"))
Dave Barachba868bb2016-08-08 09:51:21 -04001324 {
1325 if (im->drop_pcap_enable == 0)
1326 {
1327 vlib_cli_output (vm, "pcap drop capture is off...");
1328 continue;
1329 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001330
Dave Barachba868bb2016-08-08 09:51:21 -04001331 vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...",
1332 im->pcap_main.n_packets_captured,
1333 im->pcap_main.n_packets_to_capture);
1334 matched = 1;
1335 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001336
1337 else
Dave Barachba868bb2016-08-08 09:51:21 -04001338 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001339 }
1340
1341 if (matched == 0)
Dave Barachba868bb2016-08-08 09:51:21 -04001342 return clib_error_return (0, "unknown input `%U'",
1343 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001344
1345 return 0;
1346}
1347
Dave Barachba868bb2016-08-08 09:51:21 -04001348/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349VLIB_CLI_COMMAND (pcap_trace_command, static) = {
Dave Barachba868bb2016-08-08 09:51:21 -04001350 .path = "pcap drop trace",
1351 .short_help =
1352 "pcap drop trace on off max <nn> intfc <intfc> file <name> status",
1353 .function = pcap_drop_trace_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354};
Dave Barachba868bb2016-08-08 09:51:21 -04001355/* *INDENT-ON* */
1356
1357/*
1358 * fd.io coding-style-patch-verification: ON
1359 *
1360 * Local Variables:
1361 * eval: (c-set-style "gnu")
1362 * End:
1363 */