blob: 475b0b935af02c78bbfddd8185256bc57ebce67a [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;
430 u32 n_bytes_b0, n_bytes_b1;
431 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
495 while (from + 4 <= from_end && n_left_to_tx >= 2)
496 {
497 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400498 vlib_buffer_t *b0, *b1;
499 u32 tx_swif0, tx_swif1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500
501 /* Prefetch next iteration. */
502 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
503 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
504
505 bi0 = from[0];
506 bi1 = from[1];
507 to_tx[0] = bi0;
508 to_tx[1] = bi1;
509 from += 2;
510 to_tx += 2;
511 n_left_to_tx -= 2;
512
513 b0 = vlib_get_buffer (vm, bi0);
514 b1 = vlib_get_buffer (vm, bi1);
515
516 /* Be grumpy about zero length buffers for benefit of
517 driver tx function. */
518 ASSERT (b0->current_length > 0);
519 ASSERT (b1->current_length > 0);
520
Dave Barachba868bb2016-08-08 09:51:21 -0400521 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
522 n_bytes_b1 = vlib_buffer_length_in_chain (vm, b1);
523 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
524 tx_swif1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525
526 n_bytes += n_bytes_b0 + n_bytes_b1;
527 n_packets += 2;
Dave Barachba868bb2016-08-08 09:51:21 -0400528
Damjan Marion152e21d2016-11-29 14:55:43 +0100529 if (PREDICT_FALSE (current_config_index != ~0))
530 {
531 b0->feature_arc_index = arc;
532 b1->feature_arc_index = arc;
533 b0->current_config_index = current_config_index;
534 b1->current_config_index = current_config_index;
535 }
536
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100537 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
Dave Barachba868bb2016-08-08 09:51:21 -0400538 {
Dave Barachba868bb2016-08-08 09:51:21 -0400539 /* update vlan subif tx counts, if required */
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100540 vlib_increment_combined_counter (im->combined_sw_if_counters +
541 VNET_INTERFACE_COUNTER_TX,
542 cpu_index, tx_swif0, 1,
543 n_bytes_b0);
Dave Barachba868bb2016-08-08 09:51:21 -0400544 }
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100545
546 /* update vlan subif tx counts, if required */
547 if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
548 {
549
550 vlib_increment_combined_counter (im->combined_sw_if_counters +
551 VNET_INTERFACE_COUNTER_TX,
552 cpu_index, tx_swif1, 1,
553 n_bytes_b1);
554 }
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
Damjan Marion152e21d2016-11-29 14:55:43 +0100580 if (PREDICT_FALSE (current_config_index != ~0))
581 {
582 b0->feature_arc_index = arc;
583 b0->current_config_index = current_config_index;
584 }
585
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100586 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
Dave Barachba868bb2016-08-08 09:51:21 -0400587 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588
Damjan Marion9c6ae5f2016-11-15 23:20:01 +0100589 vlib_increment_combined_counter (im->combined_sw_if_counters +
590 VNET_INTERFACE_COUNTER_TX,
591 cpu_index, tx_swif0, 1,
592 n_bytes_b0);
Dave Barachba868bb2016-08-08 09:51:21 -0400593 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700594 }
595
Dave Barachba868bb2016-08-08 09:51:21 -0400596 vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597 }
598
599 /* Update main interface stats. */
600 vlib_increment_combined_counter (im->combined_sw_if_counters
Dave Barachba868bb2016-08-08 09:51:21 -0400601 + VNET_INTERFACE_COUNTER_TX,
602 cpu_index,
603 rt->sw_if_index, n_packets, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604 return n_buffers;
605}
606
Damjan Marion8b2247d2016-12-02 08:09:45 +0100607VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
608CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609
610/* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
611static uword
612vnet_per_buffer_interface_output (vlib_main_t * vm,
613 vlib_node_runtime_t * node,
614 vlib_frame_t * frame)
615{
Dave Barachba868bb2016-08-08 09:51:21 -0400616 vnet_main_t *vnm = vnet_get_main ();
617 u32 n_left_to_next, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618 u32 n_left_from, next_index;
619
620 n_left_from = frame->n_vectors;
621
622 from = vlib_frame_args (frame);
623 next_index = node->cached_next_index;
624
625 while (n_left_from > 0)
626 {
627 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
628
629 while (n_left_from >= 4 && n_left_to_next >= 2)
630 {
631 u32 bi0, bi1, next0, next1;
Dave Barachba868bb2016-08-08 09:51:21 -0400632 vlib_buffer_t *b0, *b1;
633 vnet_hw_interface_t *hi0, *hi1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
635 /* Prefetch next iteration. */
636 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
637 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
638
639 bi0 = from[0];
640 bi1 = from[1];
641 to_next[0] = bi0;
642 to_next[1] = bi1;
643 from += 2;
644 to_next += 2;
645 n_left_to_next -= 2;
646 n_left_from -= 2;
647
648 b0 = vlib_get_buffer (vm, bi0);
649 b1 = vlib_get_buffer (vm, bi1);
650
Dave Barachba868bb2016-08-08 09:51:21 -0400651 hi0 =
652 vnet_get_sup_hw_interface (vnm,
653 vnet_buffer (b0)->sw_if_index
654 [VLIB_TX]);
655 hi1 =
656 vnet_get_sup_hw_interface (vnm,
657 vnet_buffer (b1)->sw_if_index
658 [VLIB_TX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659
660 next0 = hi0->hw_if_index;
661 next1 = hi1->hw_if_index;
662
Dave Barachba868bb2016-08-08 09:51:21 -0400663 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
664 n_left_to_next, bi0, bi1, next0,
665 next1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700666 }
667
668 while (n_left_from > 0 && n_left_to_next > 0)
669 {
670 u32 bi0, next0;
Dave Barachba868bb2016-08-08 09:51:21 -0400671 vlib_buffer_t *b0;
672 vnet_hw_interface_t *hi0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673
674 bi0 = from[0];
675 to_next[0] = bi0;
676 from += 1;
677 to_next += 1;
678 n_left_to_next -= 1;
679 n_left_from -= 1;
680
681 b0 = vlib_get_buffer (vm, bi0);
682
Dave Barachba868bb2016-08-08 09:51:21 -0400683 hi0 =
684 vnet_get_sup_hw_interface (vnm,
685 vnet_buffer (b0)->sw_if_index
686 [VLIB_TX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700687
688 next0 = hi0->hw_if_index;
689
Dave Barachba868bb2016-08-08 09:51:21 -0400690 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
691 n_left_to_next, bi0, next0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 }
693
694 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
695 }
696
697 return frame->n_vectors;
698}
699
700always_inline u32
701counter_index (vlib_main_t * vm, vlib_error_t e)
702{
Dave Barachba868bb2016-08-08 09:51:21 -0400703 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704 u32 ci, ni;
705
706 ni = vlib_error_get_node (e);
707 n = vlib_get_node (vm, ni);
708
709 ci = vlib_error_get_code (e);
710 ASSERT (ci < n->n_errors);
711
712 ci += n->error_heap_index;
713
714 return ci;
715}
716
Dave Barachba868bb2016-08-08 09:51:21 -0400717static u8 *
718format_vnet_error_trace (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719{
Dave Barachba868bb2016-08-08 09:51:21 -0400720 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
Dave Barachba868bb2016-08-08 09:51:21 -0400722 vlib_error_t *e = va_arg (*va, vlib_error_t *);
723 vlib_node_t *error_node;
724 vlib_error_main_t *em = &vm->error_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725 u32 i;
726
727 error_node = vlib_get_node (vm, vlib_error_get_node (e[0]));
728 i = counter_index (vm, e[0]);
729 s = format (s, "%v: %s", error_node->name, em->error_strings_heap[i]);
730
731 return s;
732}
733
734static void
735trace_errors_with_buffers (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400736 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737{
Dave Barachba868bb2016-08-08 09:51:21 -0400738 u32 n_left, *buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739
740 buffers = vlib_frame_vector_args (frame);
741 n_left = frame->n_vectors;
Dave Barachba868bb2016-08-08 09:51:21 -0400742
Ed Warnickecb9cada2015-12-08 15:45:58 -0700743 while (n_left >= 4)
744 {
745 u32 bi0, bi1;
Dave Barachba868bb2016-08-08 09:51:21 -0400746 vlib_buffer_t *b0, *b1;
747 vlib_error_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748
749 /* Prefetch next iteration. */
750 vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
751 vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
752
753 bi0 = buffers[0];
754 bi1 = buffers[1];
755
756 b0 = vlib_get_buffer (vm, bi0);
757 b1 = vlib_get_buffer (vm, bi1);
758
759 if (b0->flags & VLIB_BUFFER_IS_TRACED)
760 {
761 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
762 t0[0] = b0->error;
763 }
764 if (b1->flags & VLIB_BUFFER_IS_TRACED)
765 {
766 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
767 t1[0] = b1->error;
768 }
769 buffers += 2;
770 n_left -= 2;
771 }
772
773 while (n_left >= 1)
774 {
775 u32 bi0;
Dave Barachba868bb2016-08-08 09:51:21 -0400776 vlib_buffer_t *b0;
777 vlib_error_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778
779 bi0 = buffers[0];
780
781 b0 = vlib_get_buffer (vm, bi0);
782
783 if (b0->flags & VLIB_BUFFER_IS_TRACED)
784 {
785 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
786 t0[0] = b0->error;
787 }
788 buffers += 1;
789 n_left -= 1;
790 }
791}
792
793static u8 *
794validate_error (vlib_main_t * vm, vlib_error_t * e, u32 index)
795{
796 uword node_index = vlib_error_get_node (e[0]);
797 uword code = vlib_error_get_code (e[0]);
Dave Barachba868bb2016-08-08 09:51:21 -0400798 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799
800 if (node_index >= vec_len (vm->node_main.nodes))
801 return format (0, "[%d], node index out of range 0x%x, error 0x%x",
802 index, node_index, e[0]);
803
804 n = vlib_get_node (vm, node_index);
805 if (code >= n->n_errors)
806 return format (0, "[%d], code %d out of range for node %v",
807 index, code, n->name);
808
809 return 0;
810}
811
812static u8 *
813validate_error_frame (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -0400814 vlib_node_runtime_t * node, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815{
Dave Barachba868bb2016-08-08 09:51:21 -0400816 u32 *buffers = vlib_frame_args (f);
817 vlib_buffer_t *b;
818 u8 *msg = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700819 uword i;
820
821 for (i = 0; i < f->n_vectors; i++)
822 {
823 b = vlib_get_buffer (vm, buffers[i]);
824 msg = validate_error (vm, &b->error, i);
825 if (msg)
826 return msg;
827 }
828
829 return msg;
830}
831
Dave Barachba868bb2016-08-08 09:51:21 -0400832typedef enum
833{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834 VNET_ERROR_DISPOSITION_DROP,
835 VNET_ERROR_DISPOSITION_PUNT,
836 VNET_ERROR_N_DISPOSITION,
837} vnet_error_disposition_t;
838
839always_inline void
840do_packet (vlib_main_t * vm, vlib_error_t a)
841{
Dave Barachba868bb2016-08-08 09:51:21 -0400842 vlib_error_main_t *em = &vm->error_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700843 u32 i = counter_index (vm, a);
844 em->counters[i] += 1;
845 vlib_error_elog_count (vm, i, 1);
846}
Dave Barachba868bb2016-08-08 09:51:21 -0400847
Ed Warnickecb9cada2015-12-08 15:45:58 -0700848static_always_inline uword
849process_drop_punt (vlib_main_t * vm,
850 vlib_node_runtime_t * node,
Dave Barachba868bb2016-08-08 09:51:21 -0400851 vlib_frame_t * frame, vnet_error_disposition_t disposition)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852{
Dave Barachba868bb2016-08-08 09:51:21 -0400853 vnet_main_t *vnm = vnet_get_main ();
854 vlib_error_main_t *em = &vm->error_main;
855 u32 *buffers, *first_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856 vlib_error_t current_error;
857 u32 current_counter_index, n_errors_left;
858 u32 current_sw_if_index, n_errors_current_sw_if_index;
859 u64 current_counter;
Dave Barachba868bb2016-08-08 09:51:21 -0400860 vlib_simple_counter_main_t *cm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700861 u32 cpu_index = vm->cpu_index;
862
863 static vlib_error_t memory[VNET_ERROR_N_DISPOSITION];
864 static char memory_init[VNET_ERROR_N_DISPOSITION];
865
866 buffers = vlib_frame_args (frame);
867 first_buffer = buffers;
868
869 {
Dave Barachba868bb2016-08-08 09:51:21 -0400870 vlib_buffer_t *b = vlib_get_buffer (vm, first_buffer[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700871
Dave Barachba868bb2016-08-08 09:51:21 -0400872 if (!memory_init[disposition])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873 {
874 memory_init[disposition] = 1;
875 memory[disposition] = b->error;
876 }
877
878 current_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
879 n_errors_current_sw_if_index = 0;
880 }
881
882 current_error = memory[disposition];
883 current_counter_index = counter_index (vm, memory[disposition]);
884 current_counter = em->counters[current_counter_index];
885
886 if (node->flags & VLIB_NODE_FLAG_TRACE)
887 trace_errors_with_buffers (vm, node, frame);
Dave Barachba868bb2016-08-08 09:51:21 -0400888
Ed Warnickecb9cada2015-12-08 15:45:58 -0700889 n_errors_left = frame->n_vectors;
890 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
891 (disposition == VNET_ERROR_DISPOSITION_PUNT
892 ? VNET_INTERFACE_COUNTER_PUNT
893 : VNET_INTERFACE_COUNTER_DROP));
894
895 while (n_errors_left >= 2)
896 {
Dave Barachba868bb2016-08-08 09:51:21 -0400897 vlib_buffer_t *b0, *b1;
898 vnet_sw_interface_t *sw_if0, *sw_if1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700899 vlib_error_t e0, e1;
900 u32 bi0, bi1;
901 u32 sw_if_index0, sw_if_index1;
902
903 bi0 = buffers[0];
904 bi1 = buffers[1];
905
906 buffers += 2;
907 n_errors_left -= 2;
908
909 b0 = vlib_get_buffer (vm, bi0);
910 b1 = vlib_get_buffer (vm, bi1);
911
912 e0 = b0->error;
913 e1 = b1->error;
914
915 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
916 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
917
918 /* Speculate that sw_if_index == sw_if_index[01]. */
919 n_errors_current_sw_if_index += 2;
920
921 /* Speculatively assume all 2 (node, code) pairs are equal
Dave Barachba868bb2016-08-08 09:51:21 -0400922 to current (node, code). */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700923 current_counter += 2;
924
925 if (PREDICT_FALSE (e0 != current_error
926 || e1 != current_error
927 || sw_if_index0 != current_sw_if_index
928 || sw_if_index1 != current_sw_if_index))
929 {
930 current_counter -= 2;
931 n_errors_current_sw_if_index -= 2;
932
933 vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
934 vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1);
935
936 /* Increment super-interface drop/punt counters for
937 sub-interfaces. */
938 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
939 vlib_increment_simple_counter
Dave Barachba868bb2016-08-08 09:51:21 -0400940 (cm, cpu_index, sw_if0->sup_sw_if_index,
941 sw_if0->sup_sw_if_index != sw_if_index0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942
943 sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1);
944 vlib_increment_simple_counter
Dave Barachba868bb2016-08-08 09:51:21 -0400945 (cm, cpu_index, sw_if1->sup_sw_if_index,
946 sw_if1->sup_sw_if_index != sw_if_index1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700947
948 em->counters[current_counter_index] = current_counter;
949 do_packet (vm, e0);
950 do_packet (vm, e1);
951
952 /* For 2 repeated errors, change current error. */
953 if (e0 == e1 && e1 != current_error)
954 {
955 current_error = e0;
956 current_counter_index = counter_index (vm, e0);
957 }
958 current_counter = em->counters[current_counter_index];
959 }
960 }
961
962 while (n_errors_left >= 1)
963 {
Dave Barachba868bb2016-08-08 09:51:21 -0400964 vlib_buffer_t *b0;
965 vnet_sw_interface_t *sw_if0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966 vlib_error_t e0;
967 u32 bi0, sw_if_index0;
968
969 bi0 = buffers[0];
970
971 buffers += 1;
972 n_errors_left -= 1;
973 current_counter += 1;
974
975 b0 = vlib_get_buffer (vm, bi0);
976 e0 = b0->error;
977
978 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
979
980 /* Increment drop/punt counters. */
981 vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
982
983 /* Increment super-interface drop/punt counters for sub-interfaces. */
984 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
Dave Barachba868bb2016-08-08 09:51:21 -0400985 vlib_increment_simple_counter (cm, cpu_index, sw_if0->sup_sw_if_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700986 sw_if0->sup_sw_if_index != sw_if_index0);
987
988 if (PREDICT_FALSE (e0 != current_error))
989 {
990 current_counter -= 1;
991
992 vlib_error_elog_count (vm, current_counter_index,
993 (current_counter
994 - em->counters[current_counter_index]));
Dave Barachba868bb2016-08-08 09:51:21 -0400995
Ed Warnickecb9cada2015-12-08 15:45:58 -0700996 em->counters[current_counter_index] = current_counter;
997
998 do_packet (vm, e0);
999 current_error = e0;
1000 current_counter_index = counter_index (vm, e0);
1001 current_counter = em->counters[current_counter_index];
1002 }
1003 }
1004
1005 if (n_errors_current_sw_if_index > 0)
1006 {
Dave Barachba868bb2016-08-08 09:51:21 -04001007 vnet_sw_interface_t *si;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008
1009 vlib_increment_simple_counter (cm, cpu_index, current_sw_if_index,
1010 n_errors_current_sw_if_index);
1011
1012 si = vnet_get_sw_interface (vnm, current_sw_if_index);
1013 if (si->sup_sw_if_index != current_sw_if_index)
Dave Barachba868bb2016-08-08 09:51:21 -04001014 vlib_increment_simple_counter (cm, cpu_index, si->sup_sw_if_index,
1015 n_errors_current_sw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016 }
1017
1018 vlib_error_elog_count (vm, current_counter_index,
1019 (current_counter
1020 - em->counters[current_counter_index]));
1021
1022 /* Return cached counter. */
1023 em->counters[current_counter_index] = current_counter;
1024
1025 /* Save memory for next iteration. */
1026 memory[disposition] = current_error;
1027
Dave Barachba868bb2016-08-08 09:51:21 -04001028 if (disposition == VNET_ERROR_DISPOSITION_DROP || !vm->os_punt_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029 {
Dave Barachba868bb2016-08-08 09:51:21 -04001030 vlib_buffer_free (vm, first_buffer, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031
1032 /* If there is no punt function, free the frame as well. */
Dave Barachba868bb2016-08-08 09:51:21 -04001033 if (disposition == VNET_ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001034 vlib_frame_free (vm, node, frame);
1035 }
1036 else
1037 vm->os_punt_frame (vm, node, frame);
1038
1039 return frame->n_vectors;
1040}
1041
Dave Barachba868bb2016-08-08 09:51:21 -04001042static inline void
1043pcap_drop_trace (vlib_main_t * vm,
1044 vnet_interface_main_t * im, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045{
Dave Barachba868bb2016-08-08 09:51:21 -04001046 u32 *from;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 u32 n_left = f->n_vectors;
Dave Barachba868bb2016-08-08 09:51:21 -04001048 vlib_buffer_t *b0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001049 u32 bi0;
1050 i16 save_current_data;
1051 u16 save_current_length;
1052
1053 from = vlib_frame_vector_args (f);
1054
1055 while (n_left > 0)
1056 {
1057 if (PREDICT_TRUE (n_left > 1))
Dave Barachba868bb2016-08-08 09:51:21 -04001058 {
1059 p1 = vlib_get_buffer (vm, from[1]);
1060 vlib_prefetch_buffer_header (p1, LOAD);
1061 }
1062
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063 bi0 = from[0];
1064 b0 = vlib_get_buffer (vm, bi0);
1065 from++;
1066 n_left--;
Dave Barachba868bb2016-08-08 09:51:21 -04001067
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 /* See if we're pointedly ignoring this specific error */
Dave Barachba868bb2016-08-08 09:51:21 -04001069 if (im->pcap_drop_filter_hash
1070 && hash_get (im->pcap_drop_filter_hash, b0->error))
1071 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072
1073 /* Trace all drops, or drops received on a specific interface */
1074 if (im->pcap_sw_if_index == 0 ||
Dave Barachba868bb2016-08-08 09:51:21 -04001075 im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
1076 {
1077 save_current_data = b0->current_data;
1078 save_current_length = b0->current_length;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001079
Dave Barachba868bb2016-08-08 09:51:21 -04001080 /*
1081 * Typically, we'll need to rewind the buffer
1082 */
1083 if (b0->current_data > 0)
1084 vlib_buffer_advance (b0, (word) - b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001085
Dave Barachba868bb2016-08-08 09:51:21 -04001086 pcap_add_buffer (&im->pcap_main, vm, bi0, 512);
1087
1088 b0->current_data = save_current_data;
1089 b0->current_length = save_current_length;
1090 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001091 }
1092}
1093
Dave Barachba868bb2016-08-08 09:51:21 -04001094void
1095vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096{
Dave Barachba868bb2016-08-08 09:51:21 -04001097 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098
1099 if (im->pcap_drop_filter_hash == 0)
Dave Barachba868bb2016-08-08 09:51:21 -04001100 im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001101
1102 if (is_add)
1103 hash_set (im->pcap_drop_filter_hash, error_index, 1);
1104 else
1105 hash_unset (im->pcap_drop_filter_hash, error_index);
1106}
1107
1108static uword
1109process_drop (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001110 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111{
Dave Barachba868bb2016-08-08 09:51:21 -04001112 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113
1114 if (PREDICT_FALSE (im->drop_pcap_enable))
1115 pcap_drop_trace (vm, im, frame);
1116
1117 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
1118}
1119
1120static uword
1121process_punt (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001122 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123{
1124 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
1125}
1126
Dave Barachba868bb2016-08-08 09:51:21 -04001127/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128VLIB_REGISTER_NODE (drop_buffers,static) = {
1129 .function = process_drop,
1130 .name = "error-drop",
1131 .flags = VLIB_NODE_FLAG_IS_DROP,
1132 .vector_size = sizeof (u32),
1133 .format_trace = format_vnet_error_trace,
1134 .validate_frame = validate_error_frame,
1135};
Dave Barachba868bb2016-08-08 09:51:21 -04001136/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137
Dave Barachba868bb2016-08-08 09:51:21 -04001138VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop);
Damjan Marion1c80e832016-05-11 23:07:18 +02001139
Dave Barachba868bb2016-08-08 09:51:21 -04001140/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141VLIB_REGISTER_NODE (punt_buffers,static) = {
1142 .function = process_punt,
1143 .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
1144 | VLIB_NODE_FLAG_IS_PUNT),
1145 .name = "error-punt",
1146 .vector_size = sizeof (u32),
1147 .format_trace = format_vnet_error_trace,
1148 .validate_frame = validate_error_frame,
1149};
Dave Barachba868bb2016-08-08 09:51:21 -04001150/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151
Dave Barachba868bb2016-08-08 09:51:21 -04001152VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt);
Damjan Marion1c80e832016-05-11 23:07:18 +02001153
Dave Barachba868bb2016-08-08 09:51:21 -04001154/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
1156 .function = vnet_per_buffer_interface_output,
1157 .name = "interface-output",
1158 .vector_size = sizeof (u32),
1159};
Dave Barachba868bb2016-08-08 09:51:21 -04001160/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161
Dave Barachba868bb2016-08-08 09:51:21 -04001162VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
1163 vnet_per_buffer_interface_output);
Damjan Marion1c80e832016-05-11 23:07:18 +02001164
Damjan Marion152e21d2016-11-29 14:55:43 +01001165static uword
1166interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1167 vlib_frame_t * from_frame)
1168{
1169 vnet_main_t *vnm = vnet_get_main ();
1170 u32 last_sw_if_index = ~0;
1171 vlib_frame_t *to_frame = 0;
1172 vnet_hw_interface_t *hw = 0;
1173 u32 *from, *to_next = 0;
1174 u32 n_left_from;
1175
1176 from = vlib_frame_vector_args (from_frame);
1177 n_left_from = from_frame->n_vectors;
1178 while (n_left_from > 0)
1179 {
1180 u32 bi0;
1181 vlib_buffer_t *b0;
1182 u32 sw_if_index0;
1183
1184 bi0 = from[0];
1185 from++;
1186 n_left_from--;
1187 b0 = vlib_get_buffer (vm, bi0);
1188 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1189
1190 if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
1191 {
1192 if (to_frame)
1193 {
1194 hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
1195 vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1196 }
1197 last_sw_if_index = sw_if_index0;
1198 hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1199 to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
1200 to_next = vlib_frame_vector_args (to_frame);
1201 }
1202
1203 to_next[0] = bi0;
1204 to_next++;
1205 to_frame->n_vectors++;
1206 }
1207 vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1208 return from_frame->n_vectors;
1209}
1210
1211/* *INDENT-OFF* */
1212VLIB_REGISTER_NODE (interface_tx, static) = {
1213 .function = interface_tx_node_fn,
1214 .name = "interface-tx",
1215 .vector_size = sizeof (u32),
1216 .n_next_nodes = 1,
1217 .next_nodes = {
1218 [0] = "error-drop",
1219 },
1220};
1221
1222VNET_FEATURE_ARC_INIT (interface_output, static) =
1223{
1224 .arc_name = "interface-output",
1225 .start_nodes = VNET_FEATURES (0),
Pavel Kotucek3a2a1c42016-12-06 10:10:10 +01001226 .end_node = "interface-tx",
Damjan Marion152e21d2016-11-29 14:55:43 +01001227 .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1228};
1229
Pavel Kotucek3a2a1c42016-12-06 10:10:10 +01001230VNET_FEATURE_INIT (span_tx, static) = {
1231 .arc_name = "interface-output",
1232 .node_name = "span-output",
1233 .runs_before = VNET_FEATURES ("interface-tx"),
1234};
1235
Damjan Marion152e21d2016-11-29 14:55:43 +01001236VNET_FEATURE_INIT (interface_tx, static) = {
1237 .arc_name = "interface-output",
1238 .node_name = "interface-tx",
1239 .runs_before = 0,
1240};
1241/* *INDENT-ON* */
1242
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243clib_error_t *
1244vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1245 u32 hw_if_index,
1246 u32 is_create)
1247{
Dave Barachba868bb2016-08-08 09:51:21 -04001248 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001249 u32 next_index;
1250
1251 next_index = vlib_node_add_next_with_slot
1252 (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1253 hi->output_node_index,
1254 /* next_index */ hw_if_index);
1255
1256 ASSERT (next_index == hw_if_index);
1257
1258 return 0;
1259}
1260
Dave Barachba868bb2016-08-08 09:51:21 -04001261VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1262 (vnet_per_buffer_interface_output_hw_interface_add_del);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001263
1264static clib_error_t *
1265pcap_drop_trace_command_fn (vlib_main_t * vm,
Dave Barachba868bb2016-08-08 09:51:21 -04001266 unformat_input_t * input,
1267 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001268{
Dave Barachba868bb2016-08-08 09:51:21 -04001269 vnet_main_t *vnm = vnet_get_main ();
1270 vnet_interface_main_t *im = &vnm->interface_main;
1271 u8 *filename;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001272 u32 max;
1273 int matched = 0;
Dave Barachba868bb2016-08-08 09:51:21 -04001274 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001275
Dave Barachba868bb2016-08-08 09:51:21 -04001276 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277 {
1278 if (unformat (input, "on"))
Dave Barachba868bb2016-08-08 09:51:21 -04001279 {
1280 if (im->drop_pcap_enable == 0)
1281 {
1282 if (im->pcap_filename == 0)
1283 im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284
Dave Barachba868bb2016-08-08 09:51:21 -04001285 memset (&im->pcap_main, 0, sizeof (im->pcap_main));
1286 im->pcap_main.file_name = (char *) im->pcap_filename;
1287 im->pcap_main.n_packets_to_capture = 100;
1288 if (im->pcap_pkts_to_capture)
1289 im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture;
1290
1291 im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
1292 im->drop_pcap_enable = 1;
1293 matched = 1;
1294 vlib_cli_output (vm, "pcap drop capture on...");
1295 }
1296 else
1297 {
1298 vlib_cli_output (vm, "pcap drop capture already on...");
1299 }
1300 matched = 1;
1301 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302 else if (unformat (input, "off"))
Dave Barachba868bb2016-08-08 09:51:21 -04001303 {
1304 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001305
Dave Barachba868bb2016-08-08 09:51:21 -04001306 if (im->drop_pcap_enable)
1307 {
1308 vlib_cli_output (vm, "captured %d pkts...",
1309 im->pcap_main.n_packets_captured);
1310 if (im->pcap_main.n_packets_captured)
1311 {
1312 im->pcap_main.n_packets_to_capture =
1313 im->pcap_main.n_packets_captured;
1314 error = pcap_write (&im->pcap_main);
1315 if (error)
1316 clib_error_report (error);
1317 else
1318 vlib_cli_output (vm, "saved to %s...", im->pcap_filename);
1319 }
1320 }
1321 else
1322 {
1323 vlib_cli_output (vm, "pcap drop capture already off...");
1324 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001325
Dave Barachba868bb2016-08-08 09:51:21 -04001326 im->drop_pcap_enable = 0;
1327 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001328 else if (unformat (input, "max %d", &max))
Dave Barachba868bb2016-08-08 09:51:21 -04001329 {
1330 im->pcap_pkts_to_capture = max;
1331 matched = 1;
1332 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001333
Dave Barachba868bb2016-08-08 09:51:21 -04001334 else if (unformat (input, "intfc %U",
1335 unformat_vnet_sw_interface, vnm,
1336 &im->pcap_sw_if_index))
1337 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338 else if (unformat (input, "intfc any"))
Dave Barachba868bb2016-08-08 09:51:21 -04001339 {
1340 im->pcap_sw_if_index = 0;
1341 matched = 1;
1342 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001343 else if (unformat (input, "file %s", &filename))
Dave Barachba868bb2016-08-08 09:51:21 -04001344 {
1345 u8 *chroot_filename;
1346 /* Brain-police user path input */
1347 if (strstr ((char *) filename, "..")
1348 || index ((char *) filename, '/'))
1349 {
1350 vlib_cli_output (vm, "illegal characters in filename '%s'",
1351 filename);
1352 continue;
1353 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001354
Dave Barachba868bb2016-08-08 09:51:21 -04001355 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1356 vec_free (filename);
1357
1358 if (im->pcap_filename)
1359 vec_free (im->pcap_filename);
1360 vec_add1 (filename, 0);
1361 im->pcap_filename = chroot_filename;
1362 matched = 1;
1363 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364 else if (unformat (input, "status"))
Dave Barachba868bb2016-08-08 09:51:21 -04001365 {
1366 if (im->drop_pcap_enable == 0)
1367 {
1368 vlib_cli_output (vm, "pcap drop capture is off...");
1369 continue;
1370 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001371
Dave Barachba868bb2016-08-08 09:51:21 -04001372 vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...",
1373 im->pcap_main.n_packets_captured,
1374 im->pcap_main.n_packets_to_capture);
1375 matched = 1;
1376 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001377
1378 else
Dave Barachba868bb2016-08-08 09:51:21 -04001379 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001380 }
1381
1382 if (matched == 0)
Dave Barachba868bb2016-08-08 09:51:21 -04001383 return clib_error_return (0, "unknown input `%U'",
1384 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385
1386 return 0;
1387}
1388
Dave Barachba868bb2016-08-08 09:51:21 -04001389/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001390VLIB_CLI_COMMAND (pcap_trace_command, static) = {
Dave Barachba868bb2016-08-08 09:51:21 -04001391 .path = "pcap drop trace",
1392 .short_help =
1393 "pcap drop trace on off max <nn> intfc <intfc> file <name> status",
1394 .function = pcap_drop_trace_command_fn,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001395};
Dave Barachba868bb2016-08-08 09:51:21 -04001396/* *INDENT-ON* */
1397
1398/*
1399 * fd.io coding-style-patch-verification: ON
1400 *
1401 * Local Variables:
1402 * eval: (c-set-style "gnu")
1403 * End:
1404 */