2d220b7257bd583474954cf2fd92a034ce6efd1d
[vpp.git] / src / vnet / interface_output.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * interface_output.c: interface output node
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vnet/vnet.h>
41 #include <vnet/ip/icmp46_packet.h>
42 #include <vnet/ethernet/packet.h>
43 #include <vnet/ip/format.h>
44 #include <vnet/ip/ip4.h>
45 #include <vnet/ip/ip6.h>
46 #include <vnet/udp/udp_packet.h>
47 #include <vnet/feature/feature.h>
48 #include <vnet/classify/pcap_classify.h>
49 #include <vnet/interface_output.h>
50
51 typedef struct
52 {
53   u32 sw_if_index;
54   u32 flags;
55   u8 data[128 - 2 * sizeof (u32)];
56 }
57 interface_output_trace_t;
58
59 #ifndef CLIB_MARCH_VARIANT
60 u8 *
61 format_vnet_interface_output_trace (u8 * s, va_list * va)
62 {
63   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
64   vlib_node_t *node = va_arg (*va, vlib_node_t *);
65   interface_output_trace_t *t = va_arg (*va, interface_output_trace_t *);
66   vnet_main_t *vnm = vnet_get_main ();
67   vnet_sw_interface_t *si;
68   u32 indent;
69
70   if (t->sw_if_index != (u32) ~ 0)
71     {
72       indent = format_get_indent (s);
73
74       if (pool_is_free_index
75           (vnm->interface_main.sw_interfaces, t->sw_if_index))
76         {
77           /* the interface may have been deleted by the time the trace is printed */
78           s = format (s, "sw_if_index: %d ", t->sw_if_index);
79         }
80       else
81         {
82           si = vnet_get_sw_interface (vnm, t->sw_if_index);
83           s =
84             format (s, "%U ", format_vnet_sw_interface_name, vnm, si,
85                     t->flags);
86         }
87       s =
88         format (s, "\n%U%U", format_white_space, indent,
89                 node->format_buffer ? node->format_buffer : format_hex_bytes,
90                 t->data, sizeof (t->data));
91     }
92   return s;
93 }
94 #endif /* CLIB_MARCH_VARIANT */
95
96 static void
97 vnet_interface_output_trace (vlib_main_t * vm,
98                              vlib_node_runtime_t * node,
99                              vlib_frame_t * frame, uword n_buffers)
100 {
101   u32 n_left, *from;
102
103   n_left = n_buffers;
104   from = vlib_frame_vector_args (frame);
105
106   while (n_left >= 4)
107     {
108       u32 bi0, bi1;
109       vlib_buffer_t *b0, *b1;
110       interface_output_trace_t *t0, *t1;
111
112       /* Prefetch next iteration. */
113       vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
114       vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
115
116       bi0 = from[0];
117       bi1 = from[1];
118
119       b0 = vlib_get_buffer (vm, bi0);
120       b1 = vlib_get_buffer (vm, bi1);
121
122       if (b0->flags & VLIB_BUFFER_IS_TRACED)
123         {
124           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
125           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
126           t0->flags = b0->flags;
127           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0),
128                             sizeof (t0->data));
129         }
130       if (b1->flags & VLIB_BUFFER_IS_TRACED)
131         {
132           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
133           t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX];
134           t1->flags = b1->flags;
135           clib_memcpy_fast (t1->data, vlib_buffer_get_current (b1),
136                             sizeof (t1->data));
137         }
138       from += 2;
139       n_left -= 2;
140     }
141
142   while (n_left >= 1)
143     {
144       u32 bi0;
145       vlib_buffer_t *b0;
146       interface_output_trace_t *t0;
147
148       bi0 = from[0];
149
150       b0 = vlib_get_buffer (vm, bi0);
151
152       if (b0->flags & VLIB_BUFFER_IS_TRACED)
153         {
154           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
155           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
156           t0->flags = b0->flags;
157           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0),
158                             sizeof (t0->data));
159         }
160       from += 1;
161       n_left -= 1;
162     }
163 }
164
165 static_always_inline void
166 vnet_interface_output_handle_offload (vlib_main_t *vm, vlib_buffer_t *b)
167 {
168   if (b->flags & VNET_BUFFER_F_OFFLOAD)
169     vnet_calc_checksums_inline (vm, b, b->flags & VNET_BUFFER_F_IS_IP4,
170                                 b->flags & VNET_BUFFER_F_IS_IP6);
171 }
172
173 static_always_inline uword
174 vnet_interface_output_node_inline (vlib_main_t *vm, u32 sw_if_index,
175                                    vlib_combined_counter_main_t *ccm,
176                                    vlib_buffer_t **b, u32 config_index, u8 arc,
177                                    u32 n_left, int do_tx_offloads,
178                                    int arc_or_subif)
179 {
180   u32 n_bytes = 0;
181   u32 n_bytes0, n_bytes1, n_bytes2, n_bytes3;
182   u32 ti = vm->thread_index;
183
184   while (n_left >= 8)
185     {
186       u32 or_flags;
187
188       /* Prefetch next iteration. */
189       vlib_prefetch_buffer_header (b[4], LOAD);
190       vlib_prefetch_buffer_header (b[5], LOAD);
191       vlib_prefetch_buffer_header (b[6], LOAD);
192       vlib_prefetch_buffer_header (b[7], LOAD);
193
194       if (do_tx_offloads)
195         or_flags = b[0]->flags | b[1]->flags | b[2]->flags | b[3]->flags;
196
197       /* Be grumpy about zero length buffers for benefit of
198          driver tx function. */
199       ASSERT (b[0]->current_length > 0);
200       ASSERT (b[1]->current_length > 0);
201       ASSERT (b[2]->current_length > 0);
202       ASSERT (b[3]->current_length > 0);
203
204       n_bytes += n_bytes0 = vlib_buffer_length_in_chain (vm, b[0]);
205       n_bytes += n_bytes1 = vlib_buffer_length_in_chain (vm, b[1]);
206       n_bytes += n_bytes2 = vlib_buffer_length_in_chain (vm, b[2]);
207       n_bytes += n_bytes3 = vlib_buffer_length_in_chain (vm, b[3]);
208
209       if (arc_or_subif)
210         {
211           u32 tx_swif0, tx_swif1, tx_swif2, tx_swif3;
212           tx_swif0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
213           tx_swif1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
214           tx_swif2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
215           tx_swif3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
216
217           /* update vlan subif tx counts, if required */
218           if (PREDICT_FALSE (tx_swif0 != sw_if_index))
219             vlib_increment_combined_counter (ccm, ti, tx_swif0, 1, n_bytes0);
220
221           if (PREDICT_FALSE (tx_swif1 != sw_if_index))
222             vlib_increment_combined_counter (ccm, ti, tx_swif1, 1, n_bytes1);
223
224           if (PREDICT_FALSE (tx_swif2 != sw_if_index))
225             vlib_increment_combined_counter (ccm, ti, tx_swif2, 1, n_bytes2);
226
227           if (PREDICT_FALSE (tx_swif3 != sw_if_index))
228             vlib_increment_combined_counter (ccm, ti, tx_swif3, 1, n_bytes3);
229
230           if (PREDICT_FALSE (config_index != ~0))
231             {
232               vnet_buffer (b[0])->feature_arc_index = arc;
233               b[0]->current_config_index = config_index;
234               vnet_buffer (b[1])->feature_arc_index = arc;
235               b[1]->current_config_index = config_index;
236               vnet_buffer (b[2])->feature_arc_index = arc;
237               b[2]->current_config_index = config_index;
238               vnet_buffer (b[3])->feature_arc_index = arc;
239               b[3]->current_config_index = config_index;
240             }
241         }
242
243       if (do_tx_offloads && (or_flags & VNET_BUFFER_F_OFFLOAD))
244         {
245           vnet_interface_output_handle_offload (vm, b[0]);
246           vnet_interface_output_handle_offload (vm, b[1]);
247           vnet_interface_output_handle_offload (vm, b[2]);
248           vnet_interface_output_handle_offload (vm, b[3]);
249         }
250
251       n_left -= 4;
252       b += 4;
253     }
254
255   while (n_left)
256     {
257       /* Be grumpy about zero length buffers for benefit of
258          driver tx function. */
259       ASSERT (b[0]->current_length > 0);
260
261       n_bytes += n_bytes0 = vlib_buffer_length_in_chain (vm, b[0]);
262
263       if (arc_or_subif)
264         {
265           u32 tx_swif0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
266
267           if (PREDICT_FALSE (config_index != ~0))
268             {
269               vnet_buffer (b[0])->feature_arc_index = arc;
270               b[0]->current_config_index = config_index;
271             }
272
273           if (PREDICT_FALSE (tx_swif0 != sw_if_index))
274             vlib_increment_combined_counter (ccm, ti, tx_swif0, 1, n_bytes0);
275         }
276
277       if (do_tx_offloads)
278         vnet_interface_output_handle_offload (vm, b[0]);
279
280       n_left -= 1;
281       b += 1;
282     }
283
284   return n_bytes;
285 }
286
287 static_always_inline void vnet_interface_pcap_tx_trace
288   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame,
289    int sw_if_index_from_buffer)
290 {
291   vnet_main_t *vnm = vnet_get_main ();
292   u32 n_left_from, *from;
293   u32 sw_if_index;
294   vnet_pcap_t *pp = &vnm->pcap;
295
296   if (PREDICT_TRUE (pp->pcap_tx_enable == 0))
297     return;
298
299   if (sw_if_index_from_buffer == 0)
300     {
301       vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
302       sw_if_index = rt->sw_if_index;
303     }
304   else
305     sw_if_index = ~0;
306
307   n_left_from = frame->n_vectors;
308   from = vlib_frame_vector_args (frame);
309
310   while (n_left_from > 0)
311     {
312       u32 bi0 = from[0];
313       vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
314       from++;
315       n_left_from--;
316
317       if (sw_if_index_from_buffer)
318         sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
319
320       if (vnet_is_packet_pcaped (pp, b0, sw_if_index))
321         pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
322     }
323 }
324
325 VLIB_NODE_FN (vnet_interface_output_node)
326 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
327 {
328   vnet_main_t *vnm = vnet_get_main ();
329   vnet_interface_main_t *im = &vnm->interface_main;
330   vlib_combined_counter_main_t *ccm;
331   vnet_hw_interface_t *hi;
332   vnet_sw_interface_t *si;
333   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
334   vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
335   u32 n_bytes, n_buffers = frame->n_vectors;
336   u32 config_index = ~0;
337   u32 sw_if_index = rt->sw_if_index;
338   u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
339   u32 ti = vm->thread_index;
340   u8 arc = im->output_feature_arc_index;
341   int arc_or_subif = 0;
342   int do_tx_offloads = 0;
343   u32 *from;
344
345   if (node->flags & VLIB_NODE_FLAG_TRACE)
346     vnet_interface_output_trace (vm, node, frame, n_buffers);
347
348   from = vlib_frame_vector_args (frame);
349
350   if (rt->is_deleted)
351     return vlib_error_drop_buffers (
352       vm, node, from,
353       /* buffer stride */ 1, n_buffers, VNET_INTERFACE_OUTPUT_NEXT_DROP,
354       node->node_index, VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
355
356   vnet_interface_pcap_tx_trace (vm, node, frame,
357                                 0 /* sw_if_index_from_buffer */ );
358
359   vlib_get_buffers (vm, from, bufs, n_buffers);
360
361   si = vnet_get_sw_interface (vnm, sw_if_index);
362   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
363
364   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ||
365       !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
366     {
367       vlib_simple_counter_main_t *cm;
368
369       cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
370                              VNET_INTERFACE_COUNTER_TX_ERROR);
371       vlib_increment_simple_counter (cm, ti, sw_if_index, n_buffers);
372
373       return vlib_error_drop_buffers (
374         vm, node, from,
375         /* buffer stride */ 1, n_buffers, VNET_INTERFACE_OUTPUT_NEXT_DROP,
376         node->node_index, VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
377     }
378
379   /* interface-output feature arc handling */
380   if (PREDICT_FALSE (vnet_have_features (arc, sw_if_index)))
381     {
382       vnet_feature_config_main_t *fcm;
383       fcm = vnet_feature_get_config_main (arc);
384       config_index = vnet_get_feature_config_index (arc, sw_if_index);
385       vnet_get_config_data (&fcm->config_main, &config_index, &next_index, 0);
386       arc_or_subif = 1;
387     }
388   else if (hash_elts (hi->sub_interface_sw_if_index_by_id))
389     arc_or_subif = 1;
390
391   ccm = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX;
392
393   if ((hi->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TX_CKSUM) == 0)
394     do_tx_offloads = 1;
395
396   if (do_tx_offloads == 0 && arc_or_subif == 0)
397     n_bytes = vnet_interface_output_node_inline (
398       vm, sw_if_index, ccm, bufs, config_index, arc, n_buffers, 0, 0);
399   else if (do_tx_offloads == 0 && arc_or_subif == 1)
400     n_bytes = vnet_interface_output_node_inline (
401       vm, sw_if_index, ccm, bufs, config_index, arc, n_buffers, 0, 1);
402   else if (do_tx_offloads == 1 && arc_or_subif == 0)
403     n_bytes = vnet_interface_output_node_inline (
404       vm, sw_if_index, ccm, bufs, config_index, arc, n_buffers, 1, 0);
405   else
406     n_bytes = vnet_interface_output_node_inline (
407       vm, sw_if_index, ccm, bufs, config_index, arc, n_buffers, 1, 1);
408
409   vlib_buffer_enqueue_to_single_next (vm, node, vlib_frame_vector_args (frame),
410                                       next_index, frame->n_vectors);
411
412   /* Update main interface stats. */
413   vlib_increment_combined_counter (ccm, ti, sw_if_index, n_buffers, n_bytes);
414   return n_buffers;
415 }
416
417 VLIB_REGISTER_NODE (vnet_interface_output_node) = {
418   .name = "interface-output-template",
419   .vector_size = sizeof (u32),
420 };
421
422 /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
423 VLIB_NODE_FN (vnet_per_buffer_interface_output_node) (vlib_main_t * vm,
424                                                       vlib_node_runtime_t *
425                                                       node,
426                                                       vlib_frame_t * frame)
427 {
428   vnet_main_t *vnm = vnet_get_main ();
429   u32 n_left_to_next, *from, *to_next;
430   u32 n_left_from, next_index;
431
432   vnet_interface_pcap_tx_trace (vm, node, frame,
433                                 1 /* sw_if_index_from_buffer */ );
434
435   n_left_from = frame->n_vectors;
436
437   from = vlib_frame_vector_args (frame);
438   next_index = node->cached_next_index;
439
440   while (n_left_from > 0)
441     {
442       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
443
444       while (n_left_from >= 4 && n_left_to_next >= 2)
445         {
446           u32 bi0, bi1, next0, next1;
447           vlib_buffer_t *b0, *b1;
448           vnet_hw_interface_t *hi0, *hi1;
449
450           /* Prefetch next iteration. */
451           vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
452           vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
453
454           bi0 = from[0];
455           bi1 = from[1];
456           to_next[0] = bi0;
457           to_next[1] = bi1;
458           from += 2;
459           to_next += 2;
460           n_left_to_next -= 2;
461           n_left_from -= 2;
462
463           b0 = vlib_get_buffer (vm, bi0);
464           b1 = vlib_get_buffer (vm, bi1);
465
466           hi0 =
467             vnet_get_sup_hw_interface (vnm,
468                                        vnet_buffer (b0)->sw_if_index
469                                        [VLIB_TX]);
470           hi1 =
471             vnet_get_sup_hw_interface (vnm,
472                                        vnet_buffer (b1)->sw_if_index
473                                        [VLIB_TX]);
474
475           next0 = hi0->output_node_next_index;
476           next1 = hi1->output_node_next_index;
477
478           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
479                                            n_left_to_next, bi0, bi1, next0,
480                                            next1);
481         }
482
483       while (n_left_from > 0 && n_left_to_next > 0)
484         {
485           u32 bi0, next0;
486           vlib_buffer_t *b0;
487           vnet_hw_interface_t *hi0;
488
489           bi0 = from[0];
490           to_next[0] = bi0;
491           from += 1;
492           to_next += 1;
493           n_left_to_next -= 1;
494           n_left_from -= 1;
495
496           b0 = vlib_get_buffer (vm, bi0);
497
498           hi0 =
499             vnet_get_sup_hw_interface (vnm,
500                                        vnet_buffer (b0)->sw_if_index
501                                        [VLIB_TX]);
502
503           next0 = hi0->output_node_next_index;
504
505           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
506                                            n_left_to_next, bi0, next0);
507         }
508
509       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
510     }
511
512   return frame->n_vectors;
513 }
514
515 typedef struct vnet_error_trace_t_
516 {
517   u32 sw_if_index;
518   i8 details_valid;
519   u8 is_ip6;
520   u8 pad[2];
521   u16 mactype;
522   ip46_address_t src, dst;
523 } vnet_error_trace_t;
524
525 static u8 *
526 format_vnet_error_trace (u8 * s, va_list * va)
527 {
528   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
529   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
530   vnet_error_trace_t *t = va_arg (*va, vnet_error_trace_t *);
531
532   /* Normal, non-catchup trace */
533   if (t->details_valid == 0)
534     {
535       s = format (s, "rx:%U", format_vnet_sw_if_index_name,
536                   vnet_get_main (), t->sw_if_index);
537     }
538   else if (t->details_valid == 1)
539     {
540       /* The trace capture code didn't understant the mactype */
541       s = format (s, "mactype 0x%4x (not decoded)", t->mactype);
542     }
543   else if (t->details_valid == 2)
544     {
545       /* Dump the src/dst addresses */
546       if (t->is_ip6 == 0)
547         s = format (s, "IP4: %U -> %U",
548                     format_ip4_address, &t->src.ip4,
549                     format_ip4_address, &t->dst.ip4);
550       else
551         s = format (s, "IP6: %U -> %U",
552                     format_ip6_address, &t->src.ip6,
553                     format_ip6_address, &t->dst.ip6);
554     }
555   return s;
556 }
557
558 static void
559 interface_trace_buffers (vlib_main_t * vm,
560                          vlib_node_runtime_t * node, vlib_frame_t * frame)
561 {
562   u32 n_left, *buffers;
563
564   buffers = vlib_frame_vector_args (frame);
565   n_left = frame->n_vectors;
566
567   while (n_left >= 4)
568     {
569       u32 bi0, bi1;
570       vlib_buffer_t *b0, *b1;
571       vnet_error_trace_t *t0, *t1;
572
573       /* Prefetch next iteration. */
574       vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
575       vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
576
577       bi0 = buffers[0];
578       bi1 = buffers[1];
579
580       b0 = vlib_get_buffer (vm, bi0);
581       b1 = vlib_get_buffer (vm, bi1);
582
583       if (b0->flags & VLIB_BUFFER_IS_TRACED)
584         {
585           t0 = vlib_add_trace (vm, node, b0,
586                                STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
587           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
588           t0->details_valid = 0;
589         }
590       if (b1->flags & VLIB_BUFFER_IS_TRACED)
591         {
592           t1 = vlib_add_trace (vm, node, b1,
593                                STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
594           t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
595           t1->details_valid = 0;
596         }
597       buffers += 2;
598       n_left -= 2;
599     }
600
601   while (n_left >= 1)
602     {
603       u32 bi0;
604       vlib_buffer_t *b0;
605       vnet_error_trace_t *t0;
606
607       bi0 = buffers[0];
608
609       b0 = vlib_get_buffer (vm, bi0);
610
611       if (b0->flags & VLIB_BUFFER_IS_TRACED)
612         {
613           t0 = vlib_add_trace (vm, node, b0,
614                                STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
615           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
616           t0->details_valid = 0;
617         }
618       buffers += 1;
619       n_left -= 1;
620     }
621 }
622
623 typedef enum
624 {
625   VNET_ERROR_DISPOSITION_DROP,
626   VNET_ERROR_DISPOSITION_PUNT,
627   VNET_ERROR_N_DISPOSITION,
628 } vnet_error_disposition_t;
629
630 static void
631 drop_catchup_trace (vlib_main_t * vm,
632                     vlib_node_runtime_t * node, vlib_buffer_t * b)
633 {
634   /* Can we safely rewind the buffer? If not, fagedaboudit */
635   if (b->flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
636     {
637       vnet_error_trace_t *t;
638       ip4_header_t *ip4;
639       ip6_header_t *ip6;
640       ethernet_header_t *eh;
641       i16 delta;
642
643       t = vlib_add_trace (vm, node, b, sizeof (*t));
644       delta = vnet_buffer (b)->l2_hdr_offset - b->current_data;
645       vlib_buffer_advance (b, delta);
646
647       eh = vlib_buffer_get_current (b);
648       /* Save mactype */
649       t->mactype = clib_net_to_host_u16 (eh->type);
650       t->details_valid = 1;
651       switch (t->mactype)
652         {
653         case ETHERNET_TYPE_IP4:
654           ip4 = (void *) (eh + 1);
655           t->details_valid = 2;
656           t->is_ip6 = 0;
657           t->src.ip4.as_u32 = ip4->src_address.as_u32;
658           t->dst.ip4.as_u32 = ip4->dst_address.as_u32;
659           break;
660
661         case ETHERNET_TYPE_IP6:
662           ip6 = (void *) (eh + 1);
663           t->details_valid = 2;
664           t->is_ip6 = 1;
665           clib_memcpy_fast (t->src.as_u8, ip6->src_address.as_u8,
666                             sizeof (ip6_address_t));
667           clib_memcpy_fast (t->dst.as_u8, ip6->dst_address.as_u8,
668                             sizeof (ip6_address_t));
669           break;
670
671         default:
672           /* Dunno, do nothing, leave details_valid alone */
673           break;
674         }
675       /* Restore current data (probably unnecessary) */
676       vlib_buffer_advance (b, -delta);
677     }
678 }
679
680 static_always_inline uword
681 interface_drop_punt (vlib_main_t * vm,
682                      vlib_node_runtime_t * node,
683                      vlib_frame_t * frame,
684                      vnet_error_disposition_t disposition)
685 {
686   u32 *from, n_left, thread_index, *sw_if_index;
687   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
688   u32 sw_if_indices[VLIB_FRAME_SIZE];
689   vlib_simple_counter_main_t *cm;
690   u16 nexts[VLIB_FRAME_SIZE];
691   u32 n_trace;
692   vnet_main_t *vnm;
693
694   vnm = vnet_get_main ();
695   thread_index = vm->thread_index;
696   from = vlib_frame_vector_args (frame);
697   n_left = frame->n_vectors;
698   b = bufs;
699   sw_if_index = sw_if_indices;
700
701   vlib_get_buffers (vm, from, bufs, n_left);
702
703   /* "trace add error-drop NNN?" */
704   if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
705     {
706       /* If pkts aren't otherwise traced... */
707       if ((node->flags & VLIB_NODE_FLAG_TRACE) == 0)
708         {
709           /* Trace them from here */
710           node->flags |= VLIB_NODE_FLAG_TRACE;
711           while (n_trace && n_left)
712             {
713               if (PREDICT_TRUE
714                   (vlib_trace_buffer (vm, node, 0 /* next_index */ , b[0],
715                                       0 /* follow chain */ )))
716                 {
717                   /*
718                    * Here we have a wireshark dissector problem.
719                    * Packets may be well-formed, or not. We
720                    * must not blow chunks in any case.
721                    *
722                    * Try to produce trace records which will help
723                    * folks understand what's going on.
724                    */
725                   drop_catchup_trace (vm, node, b[0]);
726                   n_trace--;
727                 }
728               n_left--;
729               b++;
730             }
731         }
732
733       vlib_set_trace_count (vm, node, n_trace);
734       b = bufs;
735       n_left = frame->n_vectors;
736     }
737
738   if (node->flags & VLIB_NODE_FLAG_TRACE)
739     interface_trace_buffers (vm, node, frame);
740
741   /* All going to drop regardless, this is just a counting exercise */
742   clib_memset (nexts, 0, sizeof (nexts));
743
744   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
745                          (disposition == VNET_ERROR_DISPOSITION_PUNT
746                           ? VNET_INTERFACE_COUNTER_PUNT
747                           : VNET_INTERFACE_COUNTER_DROP));
748
749   /* collect the array of interfaces first ... */
750   while (n_left >= 4)
751     {
752       if (n_left >= 12)
753         {
754           /* Prefetch 8 ahead - there's not much going on in each iteration */
755           vlib_prefetch_buffer_header (b[4], LOAD);
756           vlib_prefetch_buffer_header (b[5], LOAD);
757           vlib_prefetch_buffer_header (b[6], LOAD);
758           vlib_prefetch_buffer_header (b[7], LOAD);
759         }
760       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
761       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
762       sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
763       sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
764
765       sw_if_index += 4;
766       n_left -= 4;
767       b += 4;
768     }
769   while (n_left)
770     {
771       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
772
773       sw_if_index += 1;
774       n_left -= 1;
775       b += 1;
776     }
777
778   /* ... then count against them in blocks */
779   n_left = frame->n_vectors;
780
781   while (n_left)
782     {
783       vnet_sw_interface_t *sw_if0;
784       u16 off, count;
785
786       off = frame->n_vectors - n_left;
787
788       sw_if_index = sw_if_indices + off;
789
790       count = clib_count_equal_u32 (sw_if_index, n_left);
791       n_left -= count;
792
793       vlib_increment_simple_counter (cm, thread_index, sw_if_index[0], count);
794
795       /* Increment super-interface drop/punt counters for
796          sub-interfaces. */
797       sw_if0 = vnet_get_sw_interface (vnm, sw_if_index[0]);
798       if (sw_if0->sup_sw_if_index != sw_if_index[0])
799         vlib_increment_simple_counter
800           (cm, thread_index, sw_if0->sup_sw_if_index, count);
801     }
802
803   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
804
805   return frame->n_vectors;
806 }
807
808 static inline void
809 pcap_drop_trace (vlib_main_t * vm,
810                  vnet_interface_main_t * im,
811                  vnet_pcap_t * pp, vlib_frame_t * f)
812 {
813   u32 *from;
814   u32 n_left = f->n_vectors;
815   vlib_buffer_t *b0, *p1;
816   u32 bi0;
817   i16 save_current_data;
818   u16 save_current_length;
819   vlib_error_main_t *em = &vm->error_main;
820
821   from = vlib_frame_vector_args (f);
822
823   while (n_left > 0)
824     {
825       if (PREDICT_TRUE (n_left > 1))
826         {
827           p1 = vlib_get_buffer (vm, from[1]);
828           vlib_prefetch_buffer_header (p1, LOAD);
829         }
830
831       bi0 = from[0];
832       b0 = vlib_get_buffer (vm, bi0);
833       from++;
834       n_left--;
835
836       /* See if we're pointedly ignoring this specific error */
837       if (im->pcap_drop_filter_hash
838           && hash_get (im->pcap_drop_filter_hash, b0->error))
839         continue;
840
841       if (!vnet_is_packet_pcaped (pp, b0, ~0))
842         continue; /* not matching, skip */
843
844       /* Trace all drops, or drops received on a specific interface */
845       save_current_data = b0->current_data;
846       save_current_length = b0->current_length;
847
848       /*
849        * Typically, we'll need to rewind the buffer
850        * if l2_hdr_offset is valid, make sure to rewind to the start of
851        * the L2 header. This may not be the buffer start in case we pop-ed
852        * vlan tags.
853        * Otherwise, rewind to buffer start and hope for the best.
854        */
855       if (b0->flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
856         {
857           if (b0->current_data > vnet_buffer (b0)->l2_hdr_offset)
858             vlib_buffer_advance (b0, vnet_buffer (b0)->l2_hdr_offset -
859                                        b0->current_data);
860         }
861       else if (b0->current_data > 0)
862         {
863           vlib_buffer_advance (b0, (word) -b0->current_data);
864         }
865
866       {
867         vlib_buffer_t *last = b0;
868         u32 error_node_index;
869         int drop_string_len;
870         vlib_node_t *n;
871         /* Length of the error string */
872         int error_string_len =
873           clib_strnlen (em->counters_heap[b0->error].name, 128);
874
875         /* Dig up the drop node */
876         error_node_index = vm->node_main.node_by_error[b0->error];
877         n = vlib_get_node (vm, error_node_index);
878
879         /* Length of full drop string, w/ "nodename: " prepended */
880         drop_string_len = error_string_len + vec_len (n->name) + 2;
881
882         /* Find the last buffer in the chain */
883         while (last->flags & VLIB_BUFFER_NEXT_PRESENT)
884           last = vlib_get_buffer (vm, last->next_buffer);
885
886         /*
887          * Append <nodename>: <error-string> to the capture,
888          * only if we can do that without allocating a new buffer.
889          */
890         if (PREDICT_TRUE ((last->current_data + last->current_length) <
891                           (VLIB_BUFFER_DEFAULT_DATA_SIZE - drop_string_len)))
892           {
893             clib_memcpy_fast (last->data + last->current_data +
894                                 last->current_length,
895                               n->name, vec_len (n->name));
896             clib_memcpy_fast (last->data + last->current_data +
897                                 last->current_length + vec_len (n->name),
898                               ": ", 2);
899             clib_memcpy_fast (last->data + last->current_data +
900                                 last->current_length + vec_len (n->name) + 2,
901                               em->counters_heap[b0->error].name,
902                               error_string_len);
903             last->current_length += drop_string_len;
904             b0->flags &= ~(VLIB_BUFFER_TOTAL_LENGTH_VALID);
905             pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
906             last->current_length -= drop_string_len;
907             b0->current_data = save_current_data;
908             b0->current_length = save_current_length;
909             continue;
910           }
911       }
912
913       /*
914        * Didn't have space in the last buffer, here's the dropped
915        * packet as-is
916        */
917       pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
918
919       b0->current_data = save_current_data;
920       b0->current_length = save_current_length;
921     }
922 }
923
924 #ifndef CLIB_MARCH_VARIANT
925 void
926 vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
927 {
928   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
929
930   if (im->pcap_drop_filter_hash == 0)
931     im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
932
933   if (is_add)
934     hash_set (im->pcap_drop_filter_hash, error_index, 1);
935   else
936     hash_unset (im->pcap_drop_filter_hash, error_index);
937 }
938 #endif /* CLIB_MARCH_VARIANT */
939
940 VLIB_NODE_FN (interface_drop) (vlib_main_t * vm,
941                                vlib_node_runtime_t * node,
942                                vlib_frame_t * frame)
943 {
944   vnet_main_t *vnm = vnet_get_main ();
945   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
946   vnet_pcap_t *pp = &vnm->pcap;
947
948   if (PREDICT_FALSE (pp->pcap_drop_enable))
949     pcap_drop_trace (vm, im, pp, frame);
950
951   return interface_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
952 }
953
954 VLIB_NODE_FN (interface_punt) (vlib_main_t * vm,
955                                vlib_node_runtime_t * node,
956                                vlib_frame_t * frame)
957 {
958   return interface_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
959 }
960
961 /* *INDENT-OFF* */
962 VLIB_REGISTER_NODE (interface_drop) = {
963   .name = "error-drop",
964   .vector_size = sizeof (u32),
965   .format_trace = format_vnet_error_trace,
966   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
967   .n_next_nodes = 1,
968   .next_nodes = {
969     [0] = "drop",
970   },
971 };
972 /* *INDENT-ON* */
973
974 /* *INDENT-OFF* */
975 VLIB_REGISTER_NODE (interface_punt) = {
976   .name = "error-punt",
977   .vector_size = sizeof (u32),
978   .format_trace = format_vnet_error_trace,
979   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
980   .n_next_nodes = 1,
981   .next_nodes = {
982     [0] = "punt",
983   },
984 };
985 /* *INDENT-ON* */
986
987 VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node) = {
988   .name = "interface-output",
989   .vector_size = sizeof (u32),
990 };
991
992 VLIB_NODE_FN (vnet_interface_output_arc_end_node)
993 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
994 {
995   vnet_main_t *vnm = vnet_get_main ();
996   vnet_interface_main_t *im = &vnm->interface_main;
997   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
998   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
999   u32 *from, n_left;
1000   u16 *lt = im->if_out_arc_end_next_index_by_sw_if_index;
1001
1002   from = vlib_frame_vector_args (frame);
1003   n_left = frame->n_vectors;
1004   vlib_get_buffers (vm, from, bufs, n_left);
1005
1006   while (n_left >= 8)
1007     {
1008       vlib_prefetch_buffer_header (b[4], LOAD);
1009       vlib_prefetch_buffer_header (b[5], LOAD);
1010       vlib_prefetch_buffer_header (b[6], LOAD);
1011       vlib_prefetch_buffer_header (b[7], LOAD);
1012       next[0] = vec_elt (lt, vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
1013       next[1] = vec_elt (lt, vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
1014       next[2] = vec_elt (lt, vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
1015       next[3] = vec_elt (lt, vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
1016
1017       b += 4;
1018       next += 4;
1019       n_left -= 4;
1020     }
1021
1022   while (n_left)
1023     {
1024       next[0] = vec_elt (lt, vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
1025       b++;
1026       next++;
1027       n_left--;
1028     }
1029
1030   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1031   return frame->n_vectors;
1032 }
1033
1034 VLIB_REGISTER_NODE (vnet_interface_output_arc_end_node) = {
1035   .name = "interface-output-arc-end",
1036   .vector_size = sizeof (u32),
1037   .n_next_nodes = 1,
1038   .next_nodes = {
1039     [0] = "error-drop",
1040   },
1041 };
1042
1043 VNET_FEATURE_ARC_INIT (interface_output, static) = {
1044   .arc_name = "interface-output",
1045   .start_nodes = VNET_FEATURES (0),
1046   .last_in_arc = "interface-output-arc-end",
1047   .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1048 };
1049
1050 VNET_FEATURE_INIT (span_tx, static) = {
1051   .arc_name = "interface-output",
1052   .node_name = "span-output",
1053   .runs_before = VNET_FEATURES ("interface-output-arc-end"),
1054 };
1055
1056 VNET_FEATURE_INIT (ipsec_if_tx, static) = {
1057   .arc_name = "interface-output",
1058   .node_name = "ipsec-if-output",
1059   .runs_before = VNET_FEATURES ("interface-output-arc-end"),
1060 };
1061
1062 VNET_FEATURE_INIT (interface_output_arc_end, static) = {
1063   .arc_name = "interface-output",
1064   .node_name = "interface-output-arc-end",
1065   .runs_before = 0,
1066 };
1067
1068 #ifndef CLIB_MARCH_VARIANT
1069 clib_error_t *
1070 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1071                                                        u32 hw_if_index,
1072                                                        u32 is_create)
1073 {
1074   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1075   u32 next_index;
1076
1077   if (hi->output_node_index == 0)
1078     return 0;
1079
1080   next_index = vlib_node_add_next
1081     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1082      hi->output_node_index);
1083   hi->output_node_next_index = next_index;
1084
1085   return 0;
1086 }
1087
1088 VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1089   (vnet_per_buffer_interface_output_hw_interface_add_del);
1090
1091 void
1092 vnet_set_interface_output_node (vnet_main_t * vnm,
1093                                 u32 hw_if_index, u32 node_index)
1094 {
1095   ASSERT (node_index);
1096   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1097   u32 next_index = vlib_node_add_next
1098     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index, node_index);
1099   hi->output_node_next_index = next_index;
1100   hi->output_node_index = node_index;
1101 }
1102 #endif /* CLIB_MARCH_VARIANT */
1103
1104 /*
1105  * fd.io coding-style-patch-verification: ON
1106  *
1107  * Local Variables:
1108  * eval: (c-set-style "gnu")
1109  * End:
1110  */