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