c46868e02540935c03071016219de6e3813279f2
[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/trace_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 uword
166 vnet_interface_output_node_inline (vlib_main_t * vm,
167                                    vlib_node_runtime_t * node,
168                                    vlib_frame_t * frame,
169                                    vnet_main_t * vnm,
170                                    vnet_hw_interface_t * hi,
171                                    int do_tx_offloads)
172 {
173   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
174   vnet_sw_interface_t *si;
175   u32 n_left_to_tx, *from, *from_end, *to_tx;
176   u32 n_bytes, n_buffers, n_packets;
177   u32 n_bytes_b0, n_bytes_b1, n_bytes_b2, n_bytes_b3;
178   u32 thread_index = vm->thread_index;
179   vnet_interface_main_t *im = &vnm->interface_main;
180   u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
181   u32 current_config_index = ~0;
182   u8 arc = im->output_feature_arc_index;
183   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
184
185   n_buffers = frame->n_vectors;
186
187   if (node->flags & VLIB_NODE_FLAG_TRACE)
188     vnet_interface_output_trace (vm, node, frame, n_buffers);
189
190   from = vlib_frame_vector_args (frame);
191   vlib_get_buffers (vm, from, b, n_buffers);
192
193   if (rt->is_deleted)
194     return vlib_error_drop_buffers (vm, node, from,
195                                     /* buffer stride */ 1,
196                                     n_buffers,
197                                     VNET_INTERFACE_OUTPUT_NEXT_DROP,
198                                     node->node_index,
199                                     VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
200
201   si = vnet_get_sw_interface (vnm, rt->sw_if_index);
202   hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
203   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ||
204       !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
205     {
206       vlib_simple_counter_main_t *cm;
207
208       cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
209                              VNET_INTERFACE_COUNTER_TX_ERROR);
210       vlib_increment_simple_counter (cm, thread_index,
211                                      rt->sw_if_index, n_buffers);
212
213       return vlib_error_drop_buffers (vm, node, from,
214                                       /* buffer stride */ 1,
215                                       n_buffers,
216                                       VNET_INTERFACE_OUTPUT_NEXT_DROP,
217                                       node->node_index,
218                                       VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
219     }
220
221   from_end = from + n_buffers;
222
223   /* Total byte count of all buffers. */
224   n_bytes = 0;
225   n_packets = 0;
226
227   /* interface-output feature arc handling */
228   if (PREDICT_FALSE (vnet_have_features (arc, rt->sw_if_index)))
229     {
230       vnet_feature_config_main_t *fcm;
231       fcm = vnet_feature_get_config_main (arc);
232       current_config_index = vnet_get_feature_config_index (arc,
233                                                             rt->sw_if_index);
234       vnet_get_config_data (&fcm->config_main, &current_config_index,
235                             &next_index, 0);
236     }
237
238   while (from < from_end)
239     {
240       /* Get new next frame since previous incomplete frame may have less
241          than VNET_FRAME_SIZE vectors in it. */
242       vlib_get_new_next_frame (vm, node, next_index, to_tx, n_left_to_tx);
243
244       while (from + 8 <= from_end && n_left_to_tx >= 4)
245         {
246           u32 bi0, bi1, bi2, bi3;
247           u32 tx_swif0, tx_swif1, tx_swif2, tx_swif3;
248           u32 or_flags;
249
250           /* Prefetch next iteration. */
251           vlib_prefetch_buffer_header (b[4], LOAD);
252           vlib_prefetch_buffer_header (b[5], LOAD);
253           vlib_prefetch_buffer_header (b[6], LOAD);
254           vlib_prefetch_buffer_header (b[7], LOAD);
255
256           bi0 = from[0];
257           bi1 = from[1];
258           bi2 = from[2];
259           bi3 = from[3];
260           to_tx[0] = bi0;
261           to_tx[1] = bi1;
262           to_tx[2] = bi2;
263           to_tx[3] = bi3;
264
265           or_flags = b[0]->flags | b[1]->flags | b[2]->flags | b[3]->flags;
266
267           from += 4;
268           to_tx += 4;
269           n_left_to_tx -= 4;
270
271           /* Be grumpy about zero length buffers for benefit of
272              driver tx function. */
273           ASSERT (b[0]->current_length > 0);
274           ASSERT (b[1]->current_length > 0);
275           ASSERT (b[2]->current_length > 0);
276           ASSERT (b[3]->current_length > 0);
277
278           n_bytes_b0 = vlib_buffer_length_in_chain (vm, b[0]);
279           n_bytes_b1 = vlib_buffer_length_in_chain (vm, b[1]);
280           n_bytes_b2 = vlib_buffer_length_in_chain (vm, b[2]);
281           n_bytes_b3 = vlib_buffer_length_in_chain (vm, b[3]);
282           tx_swif0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
283           tx_swif1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
284           tx_swif2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
285           tx_swif3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
286
287           n_bytes += n_bytes_b0 + n_bytes_b1;
288           n_bytes += n_bytes_b2 + n_bytes_b3;
289           n_packets += 4;
290
291           if (PREDICT_FALSE (current_config_index != ~0))
292             {
293               vnet_buffer (b[0])->feature_arc_index = arc;
294               vnet_buffer (b[1])->feature_arc_index = arc;
295               vnet_buffer (b[2])->feature_arc_index = arc;
296               vnet_buffer (b[3])->feature_arc_index = arc;
297               b[0]->current_config_index = current_config_index;
298               b[1]->current_config_index = current_config_index;
299               b[2]->current_config_index = current_config_index;
300               b[3]->current_config_index = current_config_index;
301             }
302
303           /* update vlan subif tx counts, if required */
304           if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
305             {
306               vlib_increment_combined_counter (im->combined_sw_if_counters +
307                                                VNET_INTERFACE_COUNTER_TX,
308                                                thread_index, tx_swif0, 1,
309                                                n_bytes_b0);
310             }
311
312           if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
313             {
314
315               vlib_increment_combined_counter (im->combined_sw_if_counters +
316                                                VNET_INTERFACE_COUNTER_TX,
317                                                thread_index, tx_swif1, 1,
318                                                n_bytes_b1);
319             }
320
321           if (PREDICT_FALSE (tx_swif2 != rt->sw_if_index))
322             {
323
324               vlib_increment_combined_counter (im->combined_sw_if_counters +
325                                                VNET_INTERFACE_COUNTER_TX,
326                                                thread_index, tx_swif2, 1,
327                                                n_bytes_b2);
328             }
329           if (PREDICT_FALSE (tx_swif3 != rt->sw_if_index))
330             {
331
332               vlib_increment_combined_counter (im->combined_sw_if_counters +
333                                                VNET_INTERFACE_COUNTER_TX,
334                                                thread_index, tx_swif3, 1,
335                                                n_bytes_b3);
336             }
337
338           if (do_tx_offloads)
339             {
340               if (or_flags & VNET_BUFFER_F_OFFLOAD)
341                 {
342                   if (b[0]->flags & VNET_BUFFER_F_OFFLOAD)
343                     vnet_calc_checksums_inline
344                       (vm, b[0],
345                        b[0]->flags & VNET_BUFFER_F_IS_IP4,
346                        b[0]->flags & VNET_BUFFER_F_IS_IP6);
347                   if (b[1]->flags & VNET_BUFFER_F_OFFLOAD)
348                     vnet_calc_checksums_inline
349                       (vm, b[1],
350                        b[1]->flags & VNET_BUFFER_F_IS_IP4,
351                        b[1]->flags & VNET_BUFFER_F_IS_IP6);
352                   if (b[2]->flags & VNET_BUFFER_F_OFFLOAD)
353                     vnet_calc_checksums_inline
354                       (vm, b[2],
355                        b[2]->flags & VNET_BUFFER_F_IS_IP4,
356                        b[2]->flags & VNET_BUFFER_F_IS_IP6);
357                   if (b[3]->flags & VNET_BUFFER_F_OFFLOAD)
358                     vnet_calc_checksums_inline
359                       (vm, b[3],
360                        b[3]->flags & VNET_BUFFER_F_IS_IP4,
361                        b[3]->flags & VNET_BUFFER_F_IS_IP6);
362                 }
363             }
364           b += 4;
365
366         }
367
368       while (from + 1 <= from_end && n_left_to_tx >= 1)
369         {
370           u32 bi0;
371           u32 tx_swif0;
372
373           bi0 = from[0];
374           to_tx[0] = bi0;
375           from += 1;
376           to_tx += 1;
377           n_left_to_tx -= 1;
378
379           /* Be grumpy about zero length buffers for benefit of
380              driver tx function. */
381           ASSERT (b[0]->current_length > 0);
382
383           n_bytes_b0 = vlib_buffer_length_in_chain (vm, b[0]);
384           tx_swif0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
385           n_bytes += n_bytes_b0;
386           n_packets += 1;
387
388           if (PREDICT_FALSE (current_config_index != ~0))
389             {
390               vnet_buffer (b[0])->feature_arc_index = arc;
391               b[0]->current_config_index = current_config_index;
392             }
393
394           if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
395             {
396
397               vlib_increment_combined_counter (im->combined_sw_if_counters +
398                                                VNET_INTERFACE_COUNTER_TX,
399                                                thread_index, tx_swif0, 1,
400                                                n_bytes_b0);
401             }
402
403           if (do_tx_offloads)
404             {
405               if (b[0]->flags & VNET_BUFFER_F_OFFLOAD)
406                 vnet_calc_checksums_inline
407                   (vm, b[0],
408                    b[0]->flags & VNET_BUFFER_F_IS_IP4,
409                    b[0]->flags & VNET_BUFFER_F_IS_IP6);
410             }
411           b += 1;
412         }
413
414       vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
415     }
416
417   /* Update main interface stats. */
418   vlib_increment_combined_counter (im->combined_sw_if_counters
419                                    + VNET_INTERFACE_COUNTER_TX,
420                                    thread_index,
421                                    rt->sw_if_index, n_packets, n_bytes);
422   return n_buffers;
423 }
424
425 static_always_inline void vnet_interface_pcap_tx_trace
426   (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame,
427    int sw_if_index_from_buffer)
428 {
429   vnet_main_t *vnm = vnet_get_main ();
430   u32 n_left_from, *from;
431   u32 sw_if_index;
432   vnet_pcap_t *pp = &vnm->pcap;
433
434   if (PREDICT_TRUE (pp->pcap_tx_enable == 0))
435     return;
436
437   if (sw_if_index_from_buffer == 0)
438     {
439       vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
440       sw_if_index = rt->sw_if_index;
441     }
442   else
443     sw_if_index = ~0;
444
445   n_left_from = frame->n_vectors;
446   from = vlib_frame_vector_args (frame);
447
448   while (n_left_from > 0)
449     {
450       int classify_filter_result;
451       u32 bi0 = from[0];
452       vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
453       from++;
454       n_left_from--;
455
456       if (pp->filter_classify_table_index != ~0)
457         {
458           classify_filter_result =
459             vnet_is_packet_traced_inline
460             (b0, pp->filter_classify_table_index, 0 /* full classify */ );
461           if (classify_filter_result)
462             pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
463           continue;
464         }
465
466       if (sw_if_index_from_buffer)
467         sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
468
469       if (pp->pcap_sw_if_index == 0 || pp->pcap_sw_if_index == sw_if_index)
470         {
471           vnet_main_t *vnm = vnet_get_main ();
472           vnet_hw_interface_t *hi =
473             vnet_get_sup_hw_interface (vnm, sw_if_index);
474           /* Capture pkt if not filtered, or if filter hits */
475           if (hi->trace_classify_table_index == ~0 ||
476               vnet_is_packet_traced_inline
477               (b0, hi->trace_classify_table_index, 0 /* full classify */ ))
478             pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
479         }
480     }
481 }
482
483 VLIB_NODE_FN (vnet_interface_output_node)
484 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
485 {
486   vnet_main_t *vnm = vnet_get_main ();
487   vnet_hw_interface_t *hi;
488   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
489   hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
490
491   vnet_interface_pcap_tx_trace (vm, node, frame,
492                                 0 /* sw_if_index_from_buffer */ );
493
494   if (hi->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TX_CKSUM)
495     return vnet_interface_output_node_inline (vm, node, frame, vnm, hi,
496                                               /* do_tx_offloads */ 0);
497   else
498     return vnet_interface_output_node_inline (vm, node, frame, vnm, hi,
499                                               /* do_tx_offloads */ 1);
500 }
501
502 VLIB_REGISTER_NODE (vnet_interface_output_node) = {
503   .name = "interface-output-template",
504   .vector_size = sizeof (u32),
505 };
506
507 /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
508 VLIB_NODE_FN (vnet_per_buffer_interface_output_node) (vlib_main_t * vm,
509                                                       vlib_node_runtime_t *
510                                                       node,
511                                                       vlib_frame_t * frame)
512 {
513   vnet_main_t *vnm = vnet_get_main ();
514   u32 n_left_to_next, *from, *to_next;
515   u32 n_left_from, next_index;
516
517   vnet_interface_pcap_tx_trace (vm, node, frame,
518                                 1 /* sw_if_index_from_buffer */ );
519
520   n_left_from = frame->n_vectors;
521
522   from = vlib_frame_vector_args (frame);
523   next_index = node->cached_next_index;
524
525   while (n_left_from > 0)
526     {
527       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
528
529       while (n_left_from >= 4 && n_left_to_next >= 2)
530         {
531           u32 bi0, bi1, next0, next1;
532           vlib_buffer_t *b0, *b1;
533           vnet_hw_interface_t *hi0, *hi1;
534
535           /* Prefetch next iteration. */
536           vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
537           vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
538
539           bi0 = from[0];
540           bi1 = from[1];
541           to_next[0] = bi0;
542           to_next[1] = bi1;
543           from += 2;
544           to_next += 2;
545           n_left_to_next -= 2;
546           n_left_from -= 2;
547
548           b0 = vlib_get_buffer (vm, bi0);
549           b1 = vlib_get_buffer (vm, bi1);
550
551           hi0 =
552             vnet_get_sup_hw_interface (vnm,
553                                        vnet_buffer (b0)->sw_if_index
554                                        [VLIB_TX]);
555           hi1 =
556             vnet_get_sup_hw_interface (vnm,
557                                        vnet_buffer (b1)->sw_if_index
558                                        [VLIB_TX]);
559
560           next0 = hi0->output_node_next_index;
561           next1 = hi1->output_node_next_index;
562
563           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
564                                            n_left_to_next, bi0, bi1, next0,
565                                            next1);
566         }
567
568       while (n_left_from > 0 && n_left_to_next > 0)
569         {
570           u32 bi0, next0;
571           vlib_buffer_t *b0;
572           vnet_hw_interface_t *hi0;
573
574           bi0 = from[0];
575           to_next[0] = bi0;
576           from += 1;
577           to_next += 1;
578           n_left_to_next -= 1;
579           n_left_from -= 1;
580
581           b0 = vlib_get_buffer (vm, bi0);
582
583           hi0 =
584             vnet_get_sup_hw_interface (vnm,
585                                        vnet_buffer (b0)->sw_if_index
586                                        [VLIB_TX]);
587
588           next0 = hi0->output_node_next_index;
589
590           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
591                                            n_left_to_next, bi0, next0);
592         }
593
594       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
595     }
596
597   return frame->n_vectors;
598 }
599
600 typedef struct vnet_error_trace_t_
601 {
602   u32 sw_if_index;
603   i8 details_valid;
604   u8 is_ip6;
605   u8 pad[2];
606   u16 mactype;
607   ip46_address_t src, dst;
608 } vnet_error_trace_t;
609
610 static u8 *
611 format_vnet_error_trace (u8 * s, va_list * va)
612 {
613   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
614   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
615   vnet_error_trace_t *t = va_arg (*va, vnet_error_trace_t *);
616
617   /* Normal, non-catchup trace */
618   if (t->details_valid == 0)
619     {
620       s = format (s, "rx:%U", format_vnet_sw_if_index_name,
621                   vnet_get_main (), t->sw_if_index);
622     }
623   else if (t->details_valid == 1)
624     {
625       /* The trace capture code didn't understant the mactype */
626       s = format (s, "mactype 0x%4x (not decoded)", t->mactype);
627     }
628   else if (t->details_valid == 2)
629     {
630       /* Dump the src/dst addresses */
631       if (t->is_ip6 == 0)
632         s = format (s, "IP4: %U -> %U",
633                     format_ip4_address, &t->src.ip4,
634                     format_ip4_address, &t->dst.ip4);
635       else
636         s = format (s, "IP6: %U -> %U",
637                     format_ip6_address, &t->src.ip6,
638                     format_ip6_address, &t->dst.ip6);
639     }
640   return s;
641 }
642
643 static void
644 interface_trace_buffers (vlib_main_t * vm,
645                          vlib_node_runtime_t * node, vlib_frame_t * frame)
646 {
647   u32 n_left, *buffers;
648
649   buffers = vlib_frame_vector_args (frame);
650   n_left = frame->n_vectors;
651
652   while (n_left >= 4)
653     {
654       u32 bi0, bi1;
655       vlib_buffer_t *b0, *b1;
656       vnet_error_trace_t *t0, *t1;
657
658       /* Prefetch next iteration. */
659       vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
660       vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
661
662       bi0 = buffers[0];
663       bi1 = buffers[1];
664
665       b0 = vlib_get_buffer (vm, bi0);
666       b1 = vlib_get_buffer (vm, bi1);
667
668       if (b0->flags & VLIB_BUFFER_IS_TRACED)
669         {
670           t0 = vlib_add_trace (vm, node, b0,
671                                STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
672           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
673           t0->details_valid = 0;
674         }
675       if (b1->flags & VLIB_BUFFER_IS_TRACED)
676         {
677           t1 = vlib_add_trace (vm, node, b1,
678                                STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
679           t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];
680           t1->details_valid = 0;
681         }
682       buffers += 2;
683       n_left -= 2;
684     }
685
686   while (n_left >= 1)
687     {
688       u32 bi0;
689       vlib_buffer_t *b0;
690       vnet_error_trace_t *t0;
691
692       bi0 = buffers[0];
693
694       b0 = vlib_get_buffer (vm, bi0);
695
696       if (b0->flags & VLIB_BUFFER_IS_TRACED)
697         {
698           t0 = vlib_add_trace (vm, node, b0,
699                                STRUCT_OFFSET_OF (vnet_error_trace_t, pad));
700           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
701           t0->details_valid = 0;
702         }
703       buffers += 1;
704       n_left -= 1;
705     }
706 }
707
708 typedef enum
709 {
710   VNET_ERROR_DISPOSITION_DROP,
711   VNET_ERROR_DISPOSITION_PUNT,
712   VNET_ERROR_N_DISPOSITION,
713 } vnet_error_disposition_t;
714
715 static void
716 drop_catchup_trace (vlib_main_t * vm,
717                     vlib_node_runtime_t * node, vlib_buffer_t * b)
718 {
719   /* Can we safely rewind the buffer? If not, fagedaboudit */
720   if (b->flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
721     {
722       vnet_error_trace_t *t;
723       ip4_header_t *ip4;
724       ip6_header_t *ip6;
725       ethernet_header_t *eh;
726       i16 delta;
727
728       t = vlib_add_trace (vm, node, b, sizeof (*t));
729       delta = vnet_buffer (b)->l2_hdr_offset - b->current_data;
730       vlib_buffer_advance (b, delta);
731
732       eh = vlib_buffer_get_current (b);
733       /* Save mactype */
734       t->mactype = clib_net_to_host_u16 (eh->type);
735       t->details_valid = 1;
736       switch (t->mactype)
737         {
738         case ETHERNET_TYPE_IP4:
739           ip4 = (void *) (eh + 1);
740           t->details_valid = 2;
741           t->is_ip6 = 0;
742           t->src.ip4.as_u32 = ip4->src_address.as_u32;
743           t->dst.ip4.as_u32 = ip4->dst_address.as_u32;
744           break;
745
746         case ETHERNET_TYPE_IP6:
747           ip6 = (void *) (eh + 1);
748           t->details_valid = 2;
749           t->is_ip6 = 1;
750           clib_memcpy_fast (t->src.as_u8, ip6->src_address.as_u8,
751                             sizeof (ip6_address_t));
752           clib_memcpy_fast (t->dst.as_u8, ip6->dst_address.as_u8,
753                             sizeof (ip6_address_t));
754           break;
755
756         default:
757           /* Dunno, do nothing, leave details_valid alone */
758           break;
759         }
760       /* Restore current data (probably unnecessary) */
761       vlib_buffer_advance (b, -delta);
762     }
763 }
764
765 static_always_inline uword
766 interface_drop_punt (vlib_main_t * vm,
767                      vlib_node_runtime_t * node,
768                      vlib_frame_t * frame,
769                      vnet_error_disposition_t disposition)
770 {
771   u32 *from, n_left, thread_index, *sw_if_index;
772   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
773   u32 sw_if_indices[VLIB_FRAME_SIZE];
774   vlib_simple_counter_main_t *cm;
775   u16 nexts[VLIB_FRAME_SIZE];
776   u32 n_trace;
777   vnet_main_t *vnm;
778
779   vnm = vnet_get_main ();
780   thread_index = vm->thread_index;
781   from = vlib_frame_vector_args (frame);
782   n_left = frame->n_vectors;
783   b = bufs;
784   sw_if_index = sw_if_indices;
785
786   vlib_get_buffers (vm, from, bufs, n_left);
787
788   /* "trace add error-drop NNN?" */
789   if (PREDICT_FALSE ((n_trace = vlib_get_trace_count (vm, node))))
790     {
791       /* If pkts aren't otherwise traced... */
792       if ((node->flags & VLIB_NODE_FLAG_TRACE) == 0)
793         {
794           /* Trace them from here */
795           node->flags |= VLIB_NODE_FLAG_TRACE;
796           while (n_trace && n_left)
797             {
798               if (PREDICT_TRUE
799                   (vlib_trace_buffer (vm, node, 0 /* next_index */ , b[0],
800                                       0 /* follow chain */ )))
801                 {
802                   /*
803                    * Here we have a wireshark dissector problem.
804                    * Packets may be well-formed, or not. We
805                    * must not blow chunks in any case.
806                    *
807                    * Try to produce trace records which will help
808                    * folks understand what's going on.
809                    */
810                   drop_catchup_trace (vm, node, b[0]);
811                   n_trace--;
812                 }
813               n_left--;
814               b++;
815             }
816         }
817
818       vlib_set_trace_count (vm, node, n_trace);
819       b = bufs;
820       n_left = frame->n_vectors;
821     }
822
823   if (node->flags & VLIB_NODE_FLAG_TRACE)
824     interface_trace_buffers (vm, node, frame);
825
826   /* All going to drop regardless, this is just a counting exercise */
827   clib_memset (nexts, 0, sizeof (nexts));
828
829   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
830                          (disposition == VNET_ERROR_DISPOSITION_PUNT
831                           ? VNET_INTERFACE_COUNTER_PUNT
832                           : VNET_INTERFACE_COUNTER_DROP));
833
834   /* collect the array of interfaces first ... */
835   while (n_left >= 4)
836     {
837       if (n_left >= 12)
838         {
839           /* Prefetch 8 ahead - there's not much going on in each iteration */
840           vlib_prefetch_buffer_header (b[4], LOAD);
841           vlib_prefetch_buffer_header (b[5], LOAD);
842           vlib_prefetch_buffer_header (b[6], LOAD);
843           vlib_prefetch_buffer_header (b[7], LOAD);
844         }
845       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
846       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
847       sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
848       sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
849
850       sw_if_index += 4;
851       n_left -= 4;
852       b += 4;
853     }
854   while (n_left)
855     {
856       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
857
858       sw_if_index += 1;
859       n_left -= 1;
860       b += 1;
861     }
862
863   /* ... then count against them in blocks */
864   n_left = frame->n_vectors;
865
866   while (n_left)
867     {
868       vnet_sw_interface_t *sw_if0;
869       u16 off, count;
870
871       off = frame->n_vectors - n_left;
872
873       sw_if_index = sw_if_indices + off;
874
875       count = clib_count_equal_u32 (sw_if_index, n_left);
876       n_left -= count;
877
878       vlib_increment_simple_counter (cm, thread_index, sw_if_index[0], count);
879
880       /* Increment super-interface drop/punt counters for
881          sub-interfaces. */
882       sw_if0 = vnet_get_sw_interface (vnm, sw_if_index[0]);
883       if (sw_if0->sup_sw_if_index != sw_if_index[0])
884         vlib_increment_simple_counter
885           (cm, thread_index, sw_if0->sup_sw_if_index, count);
886     }
887
888   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
889
890   return frame->n_vectors;
891 }
892
893 static inline void
894 pcap_drop_trace (vlib_main_t * vm,
895                  vnet_interface_main_t * im,
896                  vnet_pcap_t * pp, vlib_frame_t * f)
897 {
898   u32 *from;
899   u32 n_left = f->n_vectors;
900   vlib_buffer_t *b0, *p1;
901   u32 bi0;
902   i16 save_current_data;
903   u16 save_current_length;
904   vlib_error_main_t *em = &vm->error_main;
905   int do_trace = 0;
906
907
908   from = vlib_frame_vector_args (f);
909
910   while (n_left > 0)
911     {
912       if (PREDICT_TRUE (n_left > 1))
913         {
914           p1 = vlib_get_buffer (vm, from[1]);
915           vlib_prefetch_buffer_header (p1, LOAD);
916         }
917
918       bi0 = from[0];
919       b0 = vlib_get_buffer (vm, bi0);
920       from++;
921       n_left--;
922
923       /* See if we're pointedly ignoring this specific error */
924       if (im->pcap_drop_filter_hash
925           && hash_get (im->pcap_drop_filter_hash, b0->error))
926         continue;
927
928       do_trace = (pp->pcap_sw_if_index == 0) ||
929         pp->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX];
930
931       if (PREDICT_FALSE
932           (do_trace == 0 && pp->filter_classify_table_index != ~0))
933         {
934           do_trace = vnet_is_packet_traced_inline
935             (b0, pp->filter_classify_table_index, 0 /* full classify */ );
936         }
937
938       /* Trace all drops, or drops received on a specific interface */
939       if (do_trace)
940         {
941           save_current_data = b0->current_data;
942           save_current_length = b0->current_length;
943
944           /*
945            * Typically, we'll need to rewind the buffer
946            * if l2_hdr_offset is valid, make sure to rewind to the start of
947            * the L2 header. This may not be the buffer start in case we pop-ed
948            * vlan tags.
949            * Otherwise, rewind to buffer start and hope for the best.
950            */
951           if (b0->flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
952             {
953               if (b0->current_data > vnet_buffer (b0)->l2_hdr_offset)
954                 vlib_buffer_advance (b0,
955                                      vnet_buffer (b0)->l2_hdr_offset -
956                                      b0->current_data);
957             }
958           else if (b0->current_data > 0)
959             vlib_buffer_advance (b0, (word) - b0->current_data);
960
961           {
962             vlib_buffer_t *last = b0;
963             u32 error_node_index;
964             int drop_string_len;
965             vlib_node_t *n;
966             /* Length of the error string */
967             int error_string_len =
968               clib_strnlen (em->counters_heap[b0->error].name, 128);
969
970             /* Dig up the drop node */
971             error_node_index = vm->node_main.node_by_error[b0->error];
972             n = vlib_get_node (vm, error_node_index);
973
974             /* Length of full drop string, w/ "nodename: " prepended */
975             drop_string_len = error_string_len + vec_len (n->name) + 2;
976
977             /* Find the last buffer in the chain */
978             while (last->flags & VLIB_BUFFER_NEXT_PRESENT)
979               last = vlib_get_buffer (vm, last->next_buffer);
980
981             /*
982              * Append <nodename>: <error-string> to the capture,
983              * only if we can do that without allocating a new buffer.
984              */
985             if (PREDICT_TRUE ((last->current_data + last->current_length)
986                               < (VLIB_BUFFER_DEFAULT_DATA_SIZE
987                                  - drop_string_len)))
988               {
989                 clib_memcpy_fast (last->data + last->current_data +
990                                   last->current_length, n->name,
991                                   vec_len (n->name));
992                 clib_memcpy_fast (last->data + last->current_data +
993                                   last->current_length + vec_len (n->name),
994                                   ": ", 2);
995                 clib_memcpy_fast (last->data + last->current_data +
996                                   last->current_length + vec_len (n->name) +
997                                   2, em->counters_heap[b0->error].name,
998                                   error_string_len);
999                 last->current_length += drop_string_len;
1000                 b0->flags &= ~(VLIB_BUFFER_TOTAL_LENGTH_VALID);
1001                 pcap_add_buffer (&pp->pcap_main, vm, bi0,
1002                                  pp->max_bytes_per_pkt);
1003                 last->current_length -= drop_string_len;
1004                 b0->current_data = save_current_data;
1005                 b0->current_length = save_current_length;
1006                 continue;
1007               }
1008           }
1009
1010           /*
1011            * Didn't have space in the last buffer, here's the dropped
1012            * packet as-is
1013            */
1014           pcap_add_buffer (&pp->pcap_main, vm, bi0, pp->max_bytes_per_pkt);
1015
1016           b0->current_data = save_current_data;
1017           b0->current_length = save_current_length;
1018         }
1019     }
1020 }
1021
1022 #ifndef CLIB_MARCH_VARIANT
1023 void
1024 vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
1025 {
1026   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
1027
1028   if (im->pcap_drop_filter_hash == 0)
1029     im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
1030
1031   if (is_add)
1032     hash_set (im->pcap_drop_filter_hash, error_index, 1);
1033   else
1034     hash_unset (im->pcap_drop_filter_hash, error_index);
1035 }
1036 #endif /* CLIB_MARCH_VARIANT */
1037
1038 VLIB_NODE_FN (interface_drop) (vlib_main_t * vm,
1039                                vlib_node_runtime_t * node,
1040                                vlib_frame_t * frame)
1041 {
1042   vnet_main_t *vnm = vnet_get_main ();
1043   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
1044   vnet_pcap_t *pp = &vnm->pcap;
1045
1046   if (PREDICT_FALSE (pp->pcap_drop_enable))
1047     pcap_drop_trace (vm, im, pp, frame);
1048
1049   return interface_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
1050 }
1051
1052 VLIB_NODE_FN (interface_punt) (vlib_main_t * vm,
1053                                vlib_node_runtime_t * node,
1054                                vlib_frame_t * frame)
1055 {
1056   return interface_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
1057 }
1058
1059 /* *INDENT-OFF* */
1060 VLIB_REGISTER_NODE (interface_drop) = {
1061   .name = "error-drop",
1062   .vector_size = sizeof (u32),
1063   .format_trace = format_vnet_error_trace,
1064   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
1065   .n_next_nodes = 1,
1066   .next_nodes = {
1067     [0] = "drop",
1068   },
1069 };
1070 /* *INDENT-ON* */
1071
1072 /* *INDENT-OFF* */
1073 VLIB_REGISTER_NODE (interface_punt) = {
1074   .name = "error-punt",
1075   .vector_size = sizeof (u32),
1076   .format_trace = format_vnet_error_trace,
1077   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
1078   .n_next_nodes = 1,
1079   .next_nodes = {
1080     [0] = "punt",
1081   },
1082 };
1083 /* *INDENT-ON* */
1084
1085 /* *INDENT-OFF* */
1086 VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node) = {
1087   .name = "interface-output",
1088   .vector_size = sizeof (u32),
1089 };
1090 /* *INDENT-ON* */
1091
1092 static uword
1093 interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1094                       vlib_frame_t * from_frame)
1095 {
1096   vnet_main_t *vnm = vnet_get_main ();
1097   u32 last_sw_if_index = ~0;
1098   vlib_frame_t *to_frame = 0;
1099   vnet_hw_interface_t *hw = 0;
1100   u32 *from, *to_next = 0;
1101   u32 n_left_from;
1102
1103   from = vlib_frame_vector_args (from_frame);
1104   n_left_from = from_frame->n_vectors;
1105   while (n_left_from > 0)
1106     {
1107       u32 bi0;
1108       vlib_buffer_t *b0;
1109       u32 sw_if_index0;
1110
1111       bi0 = from[0];
1112       from++;
1113       n_left_from--;
1114       b0 = vlib_get_buffer (vm, bi0);
1115       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1116
1117       if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
1118         {
1119           if (to_frame)
1120             {
1121               hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
1122               vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1123             }
1124           last_sw_if_index = sw_if_index0;
1125           hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1126           to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
1127           to_next = vlib_frame_vector_args (to_frame);
1128         }
1129
1130       to_next[0] = bi0;
1131       to_next++;
1132       to_frame->n_vectors++;
1133     }
1134   vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1135   return from_frame->n_vectors;
1136 }
1137
1138 /* *INDENT-OFF* */
1139 VLIB_REGISTER_NODE (interface_tx) = {
1140   .function = interface_tx_node_fn,
1141   .name = "interface-tx",
1142   .vector_size = sizeof (u32),
1143   .n_next_nodes = 1,
1144   .next_nodes = {
1145     [0] = "error-drop",
1146   },
1147 };
1148
1149 VNET_FEATURE_ARC_INIT (interface_output, static) =
1150 {
1151   .arc_name  = "interface-output",
1152   .start_nodes = VNET_FEATURES (0),
1153   .last_in_arc = "interface-tx",
1154   .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1155 };
1156
1157 VNET_FEATURE_INIT (span_tx, static) = {
1158   .arc_name = "interface-output",
1159   .node_name = "span-output",
1160   .runs_before = VNET_FEATURES ("interface-tx"),
1161 };
1162
1163 VNET_FEATURE_INIT (ipsec_if_tx, static) = {
1164   .arc_name = "interface-output",
1165   .node_name = "ipsec-if-output",
1166   .runs_before = VNET_FEATURES ("interface-tx"),
1167 };
1168
1169 VNET_FEATURE_INIT (interface_tx, static) = {
1170   .arc_name = "interface-output",
1171   .node_name = "interface-tx",
1172   .runs_before = 0,
1173 };
1174 /* *INDENT-ON* */
1175
1176 #ifndef CLIB_MARCH_VARIANT
1177 clib_error_t *
1178 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1179                                                        u32 hw_if_index,
1180                                                        u32 is_create)
1181 {
1182   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1183   u32 next_index;
1184
1185   if (hi->output_node_index == 0)
1186     return 0;
1187
1188   next_index = vlib_node_add_next
1189     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1190      hi->output_node_index);
1191   hi->output_node_next_index = next_index;
1192
1193   return 0;
1194 }
1195
1196 VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1197   (vnet_per_buffer_interface_output_hw_interface_add_del);
1198
1199 void
1200 vnet_set_interface_output_node (vnet_main_t * vnm,
1201                                 u32 hw_if_index, u32 node_index)
1202 {
1203   ASSERT (node_index);
1204   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1205   u32 next_index = vlib_node_add_next
1206     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index, node_index);
1207   hi->output_node_next_index = next_index;
1208   hi->output_node_index = node_index;
1209 }
1210 #endif /* CLIB_MARCH_VARIANT */
1211
1212 /*
1213  * fd.io coding-style-patch-verification: ON
1214  *
1215  * Local Variables:
1216  * eval: (c-set-style "gnu")
1217  * End:
1218  */