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