session: cleanup use of api_client_index
[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
47 typedef struct
48 {
49   u32 sw_if_index;
50   u8 data[128 - sizeof (u32)];
51 }
52 interface_output_trace_t;
53
54 u8 *
55 format_vnet_interface_output_trace (u8 * s, va_list * va)
56 {
57   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
58   vlib_node_t *node = va_arg (*va, vlib_node_t *);
59   interface_output_trace_t *t = va_arg (*va, interface_output_trace_t *);
60   vnet_main_t *vnm = vnet_get_main ();
61   vnet_sw_interface_t *si;
62   u32 indent;
63
64   if (t->sw_if_index != (u32) ~ 0)
65     {
66       indent = format_get_indent (s);
67
68       if (pool_is_free_index
69           (vnm->interface_main.sw_interfaces, t->sw_if_index))
70         {
71           /* the interface may have been deleted by the time the trace is printed */
72           s = format (s, "sw_if_index: %d\n%U%U",
73                       t->sw_if_index,
74                       format_white_space, indent,
75                       node->format_buffer ? node->
76                       format_buffer : format_hex_bytes, t->data,
77                       sizeof (t->data));
78         }
79       else
80         {
81           si = vnet_get_sw_interface (vnm, t->sw_if_index);
82
83           s = format (s, "%U\n%U%U",
84                       format_vnet_sw_interface_name, vnm, si,
85                       format_white_space, indent,
86                       node->format_buffer ? node->
87                       format_buffer : format_hex_bytes, t->data,
88                       sizeof (t->data));
89         }
90     }
91   return s;
92 }
93
94 static void
95 vnet_interface_output_trace (vlib_main_t * vm,
96                              vlib_node_runtime_t * node,
97                              vlib_frame_t * frame, uword n_buffers)
98 {
99   u32 n_left, *from;
100
101   n_left = n_buffers;
102   from = vlib_frame_vector_args (frame);
103
104   while (n_left >= 4)
105     {
106       u32 bi0, bi1;
107       vlib_buffer_t *b0, *b1;
108       interface_output_trace_t *t0, *t1;
109
110       /* Prefetch next iteration. */
111       vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
112       vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
113
114       bi0 = from[0];
115       bi1 = from[1];
116
117       b0 = vlib_get_buffer (vm, bi0);
118       b1 = vlib_get_buffer (vm, bi1);
119
120       if (b0->flags & VLIB_BUFFER_IS_TRACED)
121         {
122           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
123           t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
124           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0),
125                             sizeof (t0->data));
126         }
127       if (b1->flags & VLIB_BUFFER_IS_TRACED)
128         {
129           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
130           t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX];
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           clib_memcpy_fast (t0->data, vlib_buffer_get_current (b0),
153                             sizeof (t0->data));
154         }
155       from += 1;
156       n_left -= 1;
157     }
158 }
159
160 static_always_inline void
161 calc_checksums (vlib_main_t * vm, vlib_buffer_t * b)
162 {
163   ip4_header_t *ip4;
164   ip6_header_t *ip6;
165   tcp_header_t *th;
166   udp_header_t *uh;
167
168   int is_ip4 = (b->flags & VNET_BUFFER_F_IS_IP4) != 0;
169   int is_ip6 = (b->flags & VNET_BUFFER_F_IS_IP6) != 0;
170
171   ASSERT (!(is_ip4 && is_ip6));
172
173   ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
174   ip6 = (ip6_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
175   th = (tcp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset);
176   uh = (udp_header_t *) (b->data + vnet_buffer (b)->l4_hdr_offset);
177
178   if (is_ip4)
179     {
180       ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
181       if (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
182         ip4->checksum = ip4_header_checksum (ip4);
183       if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
184         th->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
185       if (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)
186         uh->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
187     }
188   if (is_ip6)
189     {
190       int bogus;
191       if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
192         th->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus);
193       if (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)
194         uh->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus);
195     }
196
197   b->flags &= ~VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
198   b->flags &= ~VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
199   b->flags &= ~VNET_BUFFER_F_OFFLOAD_IP_CKSUM;
200 }
201
202 static_always_inline uword
203 vnet_interface_output_node_inline (vlib_main_t * vm,
204                                    vlib_node_runtime_t * node,
205                                    vlib_frame_t * frame, vnet_main_t * vnm,
206                                    vnet_hw_interface_t * hi,
207                                    int do_tx_offloads)
208 {
209   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
210   vnet_sw_interface_t *si;
211   u32 n_left_to_tx, *from, *from_end, *to_tx;
212   u32 n_bytes, n_buffers, n_packets;
213   u32 n_bytes_b0, n_bytes_b1, n_bytes_b2, n_bytes_b3;
214   u32 thread_index = vm->thread_index;
215   vnet_interface_main_t *im = &vnm->interface_main;
216   u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
217   u32 current_config_index = ~0;
218   u8 arc = im->output_feature_arc_index;
219
220   n_buffers = frame->n_vectors;
221
222   if (node->flags & VLIB_NODE_FLAG_TRACE)
223     vnet_interface_output_trace (vm, node, frame, n_buffers);
224
225   from = vlib_frame_vector_args (frame);
226
227   if (rt->is_deleted)
228     return vlib_error_drop_buffers (vm, node, from,
229                                     /* buffer stride */ 1,
230                                     n_buffers,
231                                     VNET_INTERFACE_OUTPUT_NEXT_DROP,
232                                     node->node_index,
233                                     VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
234
235   si = vnet_get_sw_interface (vnm, rt->sw_if_index);
236   hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
237   if (!(si->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP |
238                      VNET_SW_INTERFACE_FLAG_BOND_SLAVE)) ||
239       !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
240     {
241       vlib_simple_counter_main_t *cm;
242
243       cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
244                              VNET_INTERFACE_COUNTER_TX_ERROR);
245       vlib_increment_simple_counter (cm, thread_index,
246                                      rt->sw_if_index, n_buffers);
247
248       return vlib_error_drop_buffers (vm, node, from,
249                                       /* buffer stride */ 1,
250                                       n_buffers,
251                                       VNET_INTERFACE_OUTPUT_NEXT_DROP,
252                                       node->node_index,
253                                       VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
254     }
255
256   from_end = from + n_buffers;
257
258   /* Total byte count of all buffers. */
259   n_bytes = 0;
260   n_packets = 0;
261
262   /* interface-output feature arc handling */
263   if (PREDICT_FALSE (vnet_have_features (arc, rt->sw_if_index)))
264     {
265       vnet_feature_config_main_t *fcm;
266       fcm = vnet_feature_get_config_main (arc);
267       current_config_index = vnet_get_feature_config_index (arc,
268                                                             rt->sw_if_index);
269       vnet_get_config_data (&fcm->config_main, &current_config_index,
270                             &next_index, 0);
271     }
272
273   while (from < from_end)
274     {
275       /* Get new next frame since previous incomplete frame may have less
276          than VNET_FRAME_SIZE vectors in it. */
277       vlib_get_new_next_frame (vm, node, next_index, to_tx, n_left_to_tx);
278
279       while (from + 8 <= from_end && n_left_to_tx >= 4)
280         {
281           u32 bi0, bi1, bi2, bi3;
282           vlib_buffer_t *b0, *b1, *b2, *b3;
283           u32 tx_swif0, tx_swif1, tx_swif2, tx_swif3;
284           u32 or_flags;
285
286           /* Prefetch next iteration. */
287           vlib_prefetch_buffer_with_index (vm, from[4], LOAD);
288           vlib_prefetch_buffer_with_index (vm, from[5], LOAD);
289           vlib_prefetch_buffer_with_index (vm, from[6], LOAD);
290           vlib_prefetch_buffer_with_index (vm, from[7], LOAD);
291
292           bi0 = from[0];
293           bi1 = from[1];
294           bi2 = from[2];
295           bi3 = from[3];
296           to_tx[0] = bi0;
297           to_tx[1] = bi1;
298           to_tx[2] = bi2;
299           to_tx[3] = bi3;
300           from += 4;
301           to_tx += 4;
302           n_left_to_tx -= 4;
303
304           b0 = vlib_get_buffer (vm, bi0);
305           b1 = vlib_get_buffer (vm, bi1);
306           b2 = vlib_get_buffer (vm, bi2);
307           b3 = vlib_get_buffer (vm, bi3);
308
309           /* Be grumpy about zero length buffers for benefit of
310              driver tx function. */
311           ASSERT (b0->current_length > 0);
312           ASSERT (b1->current_length > 0);
313           ASSERT (b2->current_length > 0);
314           ASSERT (b3->current_length > 0);
315
316           n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
317           n_bytes_b1 = vlib_buffer_length_in_chain (vm, b1);
318           n_bytes_b2 = vlib_buffer_length_in_chain (vm, b2);
319           n_bytes_b3 = vlib_buffer_length_in_chain (vm, b3);
320           tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
321           tx_swif1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
322           tx_swif2 = vnet_buffer (b2)->sw_if_index[VLIB_TX];
323           tx_swif3 = vnet_buffer (b3)->sw_if_index[VLIB_TX];
324
325           n_bytes += n_bytes_b0 + n_bytes_b1;
326           n_bytes += n_bytes_b2 + n_bytes_b3;
327           n_packets += 4;
328
329           if (PREDICT_FALSE (current_config_index != ~0))
330             {
331               vnet_buffer (b0)->feature_arc_index = arc;
332               vnet_buffer (b1)->feature_arc_index = arc;
333               vnet_buffer (b2)->feature_arc_index = arc;
334               vnet_buffer (b3)->feature_arc_index = arc;
335               b0->current_config_index = current_config_index;
336               b1->current_config_index = current_config_index;
337               b2->current_config_index = current_config_index;
338               b3->current_config_index = current_config_index;
339             }
340
341           /* update vlan subif tx counts, if required */
342           if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
343             {
344               vlib_increment_combined_counter (im->combined_sw_if_counters +
345                                                VNET_INTERFACE_COUNTER_TX,
346                                                thread_index, tx_swif0, 1,
347                                                n_bytes_b0);
348             }
349
350           if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
351             {
352
353               vlib_increment_combined_counter (im->combined_sw_if_counters +
354                                                VNET_INTERFACE_COUNTER_TX,
355                                                thread_index, tx_swif1, 1,
356                                                n_bytes_b1);
357             }
358
359           if (PREDICT_FALSE (tx_swif2 != rt->sw_if_index))
360             {
361
362               vlib_increment_combined_counter (im->combined_sw_if_counters +
363                                                VNET_INTERFACE_COUNTER_TX,
364                                                thread_index, tx_swif2, 1,
365                                                n_bytes_b2);
366             }
367           if (PREDICT_FALSE (tx_swif3 != rt->sw_if_index))
368             {
369
370               vlib_increment_combined_counter (im->combined_sw_if_counters +
371                                                VNET_INTERFACE_COUNTER_TX,
372                                                thread_index, tx_swif3, 1,
373                                                n_bytes_b3);
374             }
375
376           or_flags = b0->flags | b1->flags | b2->flags | b3->flags;
377
378           if (do_tx_offloads)
379             {
380               if (or_flags &
381                   (VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
382                    VNET_BUFFER_F_OFFLOAD_UDP_CKSUM |
383                    VNET_BUFFER_F_OFFLOAD_IP_CKSUM))
384                 {
385                   calc_checksums (vm, b0);
386                   calc_checksums (vm, b1);
387                   calc_checksums (vm, b2);
388                   calc_checksums (vm, b3);
389                 }
390             }
391         }
392
393       while (from + 1 <= from_end && n_left_to_tx >= 1)
394         {
395           u32 bi0;
396           vlib_buffer_t *b0;
397           u32 tx_swif0;
398
399           bi0 = from[0];
400           to_tx[0] = bi0;
401           from += 1;
402           to_tx += 1;
403           n_left_to_tx -= 1;
404
405           b0 = vlib_get_buffer (vm, bi0);
406
407           /* Be grumpy about zero length buffers for benefit of
408              driver tx function. */
409           ASSERT (b0->current_length > 0);
410
411           n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
412           tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
413           n_bytes += n_bytes_b0;
414           n_packets += 1;
415
416           if (PREDICT_FALSE (current_config_index != ~0))
417             {
418               vnet_buffer (b0)->feature_arc_index = arc;
419               b0->current_config_index = current_config_index;
420             }
421
422           if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
423             {
424
425               vlib_increment_combined_counter (im->combined_sw_if_counters +
426                                                VNET_INTERFACE_COUNTER_TX,
427                                                thread_index, tx_swif0, 1,
428                                                n_bytes_b0);
429             }
430
431           if (do_tx_offloads)
432             calc_checksums (vm, b0);
433         }
434
435       vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
436     }
437
438   /* Update main interface stats. */
439   vlib_increment_combined_counter (im->combined_sw_if_counters
440                                    + VNET_INTERFACE_COUNTER_TX,
441                                    thread_index,
442                                    rt->sw_if_index, n_packets, n_bytes);
443   return n_buffers;
444 }
445
446 static uword
447 vnet_interface_output_node (vlib_main_t * vm, vlib_node_runtime_t * node,
448                             vlib_frame_t * frame)
449 {
450   vnet_main_t *vnm = vnet_get_main ();
451   vnet_hw_interface_t *hi;
452   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
453   hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
454
455   if (hi->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD)
456     return vnet_interface_output_node_inline (vm, node, frame, vnm, hi,
457                                               /* do_tx_offloads */ 0);
458   else
459     return vnet_interface_output_node_inline (vm, node, frame, vnm, hi,
460                                               /* do_tx_offloads */ 1);
461 }
462
463 VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
464 CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
465
466 /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
467 static uword
468 vnet_per_buffer_interface_output (vlib_main_t * vm,
469                                   vlib_node_runtime_t * node,
470                                   vlib_frame_t * frame)
471 {
472   vnet_main_t *vnm = vnet_get_main ();
473   u32 n_left_to_next, *from, *to_next;
474   u32 n_left_from, next_index;
475
476   n_left_from = frame->n_vectors;
477
478   from = vlib_frame_vector_args (frame);
479   next_index = node->cached_next_index;
480
481   while (n_left_from > 0)
482     {
483       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
484
485       while (n_left_from >= 4 && n_left_to_next >= 2)
486         {
487           u32 bi0, bi1, next0, next1;
488           vlib_buffer_t *b0, *b1;
489           vnet_hw_interface_t *hi0, *hi1;
490
491           /* Prefetch next iteration. */
492           vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
493           vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
494
495           bi0 = from[0];
496           bi1 = from[1];
497           to_next[0] = bi0;
498           to_next[1] = bi1;
499           from += 2;
500           to_next += 2;
501           n_left_to_next -= 2;
502           n_left_from -= 2;
503
504           b0 = vlib_get_buffer (vm, bi0);
505           b1 = vlib_get_buffer (vm, bi1);
506
507           hi0 =
508             vnet_get_sup_hw_interface (vnm,
509                                        vnet_buffer (b0)->sw_if_index
510                                        [VLIB_TX]);
511           hi1 =
512             vnet_get_sup_hw_interface (vnm,
513                                        vnet_buffer (b1)->sw_if_index
514                                        [VLIB_TX]);
515
516           next0 = hi0->output_node_next_index;
517           next1 = hi1->output_node_next_index;
518
519           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
520                                            n_left_to_next, bi0, bi1, next0,
521                                            next1);
522         }
523
524       while (n_left_from > 0 && n_left_to_next > 0)
525         {
526           u32 bi0, next0;
527           vlib_buffer_t *b0;
528           vnet_hw_interface_t *hi0;
529
530           bi0 = from[0];
531           to_next[0] = bi0;
532           from += 1;
533           to_next += 1;
534           n_left_to_next -= 1;
535           n_left_from -= 1;
536
537           b0 = vlib_get_buffer (vm, bi0);
538
539           hi0 =
540             vnet_get_sup_hw_interface (vnm,
541                                        vnet_buffer (b0)->sw_if_index
542                                        [VLIB_TX]);
543
544           next0 = hi0->output_node_next_index;
545
546           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
547                                            n_left_to_next, bi0, next0);
548         }
549
550       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
551     }
552
553   return frame->n_vectors;
554 }
555
556 always_inline u32
557 counter_index (vlib_main_t * vm, vlib_error_t e)
558 {
559   vlib_node_t *n;
560   u32 ci, ni;
561
562   ni = vlib_error_get_node (e);
563   n = vlib_get_node (vm, ni);
564
565   ci = vlib_error_get_code (e);
566   ASSERT (ci < n->n_errors);
567
568   ci += n->error_heap_index;
569
570   return ci;
571 }
572
573 static u8 *
574 format_vnet_error_trace (u8 * s, va_list * va)
575 {
576   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
577   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
578   vlib_error_t *e = va_arg (*va, vlib_error_t *);
579   vlib_node_t *error_node;
580   vlib_error_main_t *em = &vm->error_main;
581   u32 i;
582
583   error_node = vlib_get_node (vm, vlib_error_get_node (e[0]));
584   i = counter_index (vm, e[0]);
585   s = format (s, "%v: %s", error_node->name, em->error_strings_heap[i]);
586
587   return s;
588 }
589
590 static void
591 trace_errors_with_buffers (vlib_main_t * vm,
592                            vlib_node_runtime_t * node, vlib_frame_t * frame)
593 {
594   u32 n_left, *buffers;
595
596   buffers = vlib_frame_vector_args (frame);
597   n_left = frame->n_vectors;
598
599   while (n_left >= 4)
600     {
601       u32 bi0, bi1;
602       vlib_buffer_t *b0, *b1;
603       vlib_error_t *t0, *t1;
604
605       /* Prefetch next iteration. */
606       vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
607       vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
608
609       bi0 = buffers[0];
610       bi1 = buffers[1];
611
612       b0 = vlib_get_buffer (vm, bi0);
613       b1 = vlib_get_buffer (vm, bi1);
614
615       if (b0->flags & VLIB_BUFFER_IS_TRACED)
616         {
617           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
618           t0[0] = b0->error;
619         }
620       if (b1->flags & VLIB_BUFFER_IS_TRACED)
621         {
622           t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
623           t1[0] = b1->error;
624         }
625       buffers += 2;
626       n_left -= 2;
627     }
628
629   while (n_left >= 1)
630     {
631       u32 bi0;
632       vlib_buffer_t *b0;
633       vlib_error_t *t0;
634
635       bi0 = buffers[0];
636
637       b0 = vlib_get_buffer (vm, bi0);
638
639       if (b0->flags & VLIB_BUFFER_IS_TRACED)
640         {
641           t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
642           t0[0] = b0->error;
643         }
644       buffers += 1;
645       n_left -= 1;
646     }
647 }
648
649 static u8 *
650 validate_error (vlib_main_t * vm, vlib_error_t * e, u32 index)
651 {
652   uword node_index = vlib_error_get_node (e[0]);
653   uword code = vlib_error_get_code (e[0]);
654   vlib_node_t *n;
655
656   if (node_index >= vec_len (vm->node_main.nodes))
657     return format (0, "[%d], node index out of range 0x%x, error 0x%x",
658                    index, node_index, e[0]);
659
660   n = vlib_get_node (vm, node_index);
661   if (code >= n->n_errors)
662     return format (0, "[%d], code %d out of range for node %v",
663                    index, code, n->name);
664
665   return 0;
666 }
667
668 static u8 *
669 validate_error_frame (vlib_main_t * vm,
670                       vlib_node_runtime_t * node, vlib_frame_t * f)
671 {
672   u32 *buffers = vlib_frame_vector_args (f);
673   vlib_buffer_t *b;
674   u8 *msg = 0;
675   uword i;
676
677   for (i = 0; i < f->n_vectors; i++)
678     {
679       b = vlib_get_buffer (vm, buffers[i]);
680       msg = validate_error (vm, &b->error, i);
681       if (msg)
682         return msg;
683     }
684
685   return msg;
686 }
687
688 typedef enum
689 {
690   VNET_ERROR_DISPOSITION_DROP,
691   VNET_ERROR_DISPOSITION_PUNT,
692   VNET_ERROR_N_DISPOSITION,
693 } vnet_error_disposition_t;
694
695 always_inline void
696 do_packet (vlib_main_t * vm, vlib_error_t a)
697 {
698   vlib_error_main_t *em = &vm->error_main;
699   u32 i = counter_index (vm, a);
700   em->counters[i] += 1;
701   vlib_error_elog_count (vm, i, 1);
702 }
703
704 static_always_inline uword
705 process_drop_punt (vlib_main_t * vm,
706                    vlib_node_runtime_t * node,
707                    vlib_frame_t * frame, vnet_error_disposition_t disposition)
708 {
709   vnet_main_t *vnm = vnet_get_main ();
710   vlib_error_main_t *em = &vm->error_main;
711   u32 *buffers, *first_buffer;
712   vlib_error_t current_error;
713   u32 current_counter_index, n_errors_left;
714   u32 current_sw_if_index, n_errors_current_sw_if_index;
715   u64 current_counter;
716   vlib_simple_counter_main_t *cm;
717   u32 thread_index = vm->thread_index;
718
719   static vlib_error_t memory[VNET_ERROR_N_DISPOSITION];
720   static char memory_init[VNET_ERROR_N_DISPOSITION];
721
722   buffers = vlib_frame_vector_args (frame);
723   first_buffer = buffers;
724
725   {
726     vlib_buffer_t *b = vlib_get_buffer (vm, first_buffer[0]);
727
728     if (!memory_init[disposition])
729       {
730         memory_init[disposition] = 1;
731         memory[disposition] = b->error;
732       }
733
734     current_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
735     n_errors_current_sw_if_index = 0;
736   }
737
738   current_error = memory[disposition];
739   current_counter_index = counter_index (vm, memory[disposition]);
740   current_counter = em->counters[current_counter_index];
741
742   if (node->flags & VLIB_NODE_FLAG_TRACE)
743     trace_errors_with_buffers (vm, node, frame);
744
745   n_errors_left = frame->n_vectors;
746   cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
747                          (disposition == VNET_ERROR_DISPOSITION_PUNT
748                           ? VNET_INTERFACE_COUNTER_PUNT
749                           : VNET_INTERFACE_COUNTER_DROP));
750
751   while (n_errors_left >= 2)
752     {
753       vlib_buffer_t *b0, *b1;
754       vnet_sw_interface_t *sw_if0, *sw_if1;
755       vlib_error_t e0, e1;
756       u32 bi0, bi1;
757       u32 sw_if_index0, sw_if_index1;
758
759       bi0 = buffers[0];
760       bi1 = buffers[1];
761
762       buffers += 2;
763       n_errors_left -= 2;
764
765       b0 = vlib_get_buffer (vm, bi0);
766       b1 = vlib_get_buffer (vm, bi1);
767
768       e0 = b0->error;
769       e1 = b1->error;
770
771       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
772       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
773
774       /* Speculate that sw_if_index == sw_if_index[01]. */
775       n_errors_current_sw_if_index += 2;
776
777       /* Speculatively assume all 2 (node, code) pairs are equal
778          to current (node, code). */
779       current_counter += 2;
780
781       if (PREDICT_FALSE (e0 != current_error
782                          || e1 != current_error
783                          || sw_if_index0 != current_sw_if_index
784                          || sw_if_index1 != current_sw_if_index))
785         {
786           current_counter -= 2;
787           n_errors_current_sw_if_index -= 2;
788
789           vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
790           vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
791
792           /* Increment super-interface drop/punt counters for
793              sub-interfaces. */
794           sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
795           vlib_increment_simple_counter
796             (cm, thread_index, sw_if0->sup_sw_if_index,
797              sw_if0->sup_sw_if_index != sw_if_index0);
798
799           sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1);
800           vlib_increment_simple_counter
801             (cm, thread_index, sw_if1->sup_sw_if_index,
802              sw_if1->sup_sw_if_index != sw_if_index1);
803
804           em->counters[current_counter_index] = current_counter;
805           do_packet (vm, e0);
806           do_packet (vm, e1);
807
808           /* For 2 repeated errors, change current error. */
809           if (e0 == e1 && e1 != current_error)
810             {
811               current_error = e0;
812               current_counter_index = counter_index (vm, e0);
813             }
814           current_counter = em->counters[current_counter_index];
815         }
816     }
817
818   while (n_errors_left >= 1)
819     {
820       vlib_buffer_t *b0;
821       vnet_sw_interface_t *sw_if0;
822       vlib_error_t e0;
823       u32 bi0, sw_if_index0;
824
825       bi0 = buffers[0];
826
827       buffers += 1;
828       n_errors_left -= 1;
829       current_counter += 1;
830
831       b0 = vlib_get_buffer (vm, bi0);
832       e0 = b0->error;
833
834       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
835
836       /* Increment drop/punt counters. */
837       vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
838
839       /* Increment super-interface drop/punt counters for sub-interfaces. */
840       sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
841       vlib_increment_simple_counter (cm, thread_index,
842                                      sw_if0->sup_sw_if_index,
843                                      sw_if0->sup_sw_if_index != sw_if_index0);
844
845       if (PREDICT_FALSE (e0 != current_error))
846         {
847           current_counter -= 1;
848
849           vlib_error_elog_count (vm, current_counter_index,
850                                  (current_counter
851                                   - em->counters[current_counter_index]));
852
853           em->counters[current_counter_index] = current_counter;
854
855           do_packet (vm, e0);
856           current_error = e0;
857           current_counter_index = counter_index (vm, e0);
858           current_counter = em->counters[current_counter_index];
859         }
860     }
861
862   if (n_errors_current_sw_if_index > 0)
863     {
864       vnet_sw_interface_t *si;
865
866       vlib_increment_simple_counter (cm, thread_index, current_sw_if_index,
867                                      n_errors_current_sw_if_index);
868
869       si = vnet_get_sw_interface (vnm, current_sw_if_index);
870       if (si->sup_sw_if_index != current_sw_if_index)
871         vlib_increment_simple_counter (cm, thread_index, si->sup_sw_if_index,
872                                        n_errors_current_sw_if_index);
873     }
874
875   vlib_error_elog_count (vm, current_counter_index,
876                          (current_counter
877                           - em->counters[current_counter_index]));
878
879   /* Return cached counter. */
880   em->counters[current_counter_index] = current_counter;
881
882   /* Save memory for next iteration. */
883   memory[disposition] = current_error;
884
885   if (disposition == VNET_ERROR_DISPOSITION_DROP || !vm->os_punt_frame)
886     {
887       vlib_buffer_free (vm, first_buffer, frame->n_vectors);
888
889       /* If there is no punt function, free the frame as well. */
890       if (disposition == VNET_ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
891         vlib_frame_free (vm, node, frame);
892     }
893   else
894     vm->os_punt_frame (vm, node, frame);
895
896   return frame->n_vectors;
897 }
898
899 static inline void
900 pcap_drop_trace (vlib_main_t * vm,
901                  vnet_interface_main_t * im, vlib_frame_t * f)
902 {
903   u32 *from;
904   u32 n_left = f->n_vectors;
905   vlib_buffer_t *b0, *p1;
906   u32 bi0;
907   i16 save_current_data;
908   u16 save_current_length;
909
910   from = vlib_frame_vector_args (f);
911
912   while (n_left > 0)
913     {
914       if (PREDICT_TRUE (n_left > 1))
915         {
916           p1 = vlib_get_buffer (vm, from[1]);
917           vlib_prefetch_buffer_header (p1, LOAD);
918         }
919
920       bi0 = from[0];
921       b0 = vlib_get_buffer (vm, bi0);
922       from++;
923       n_left--;
924
925       /* See if we're pointedly ignoring this specific error */
926       if (im->pcap_drop_filter_hash
927           && hash_get (im->pcap_drop_filter_hash, b0->error))
928         continue;
929
930       /* Trace all drops, or drops received on a specific interface */
931       if (im->pcap_sw_if_index == 0 ||
932           im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
933         {
934           save_current_data = b0->current_data;
935           save_current_length = b0->current_length;
936
937           /*
938            * Typically, we'll need to rewind the buffer
939            */
940           if (b0->current_data > 0)
941             vlib_buffer_advance (b0, (word) - b0->current_data);
942
943           pcap_add_buffer (&im->pcap_main, vm, bi0, 512);
944
945           b0->current_data = save_current_data;
946           b0->current_length = save_current_length;
947         }
948     }
949 }
950
951 void
952 vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
953 {
954   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
955
956   if (im->pcap_drop_filter_hash == 0)
957     im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
958
959   if (is_add)
960     hash_set (im->pcap_drop_filter_hash, error_index, 1);
961   else
962     hash_unset (im->pcap_drop_filter_hash, error_index);
963 }
964
965 static uword
966 process_drop (vlib_main_t * vm,
967               vlib_node_runtime_t * node, vlib_frame_t * frame)
968 {
969   vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
970
971   if (PREDICT_FALSE (im->drop_pcap_enable))
972     pcap_drop_trace (vm, im, frame);
973
974   return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
975 }
976
977 static uword
978 process_punt (vlib_main_t * vm,
979               vlib_node_runtime_t * node, vlib_frame_t * frame)
980 {
981   return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
982 }
983
984 /* *INDENT-OFF* */
985 VLIB_REGISTER_NODE (drop_buffers,static) = {
986   .function = process_drop,
987   .name = "error-drop",
988   .flags = VLIB_NODE_FLAG_IS_DROP,
989   .vector_size = sizeof (u32),
990   .format_trace = format_vnet_error_trace,
991   .validate_frame = validate_error_frame,
992 };
993 /* *INDENT-ON* */
994
995 VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop);
996
997 /* *INDENT-OFF* */
998 VLIB_REGISTER_NODE (punt_buffers,static) = {
999   .function = process_punt,
1000   .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
1001             | VLIB_NODE_FLAG_IS_PUNT),
1002   .name = "error-punt",
1003   .vector_size = sizeof (u32),
1004   .format_trace = format_vnet_error_trace,
1005   .validate_frame = validate_error_frame,
1006 };
1007 /* *INDENT-ON* */
1008
1009 VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt);
1010
1011 /* *INDENT-OFF* */
1012 VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
1013   .function = vnet_per_buffer_interface_output,
1014   .name = "interface-output",
1015   .vector_size = sizeof (u32),
1016 };
1017 /* *INDENT-ON* */
1018
1019 VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
1020                               vnet_per_buffer_interface_output);
1021
1022 static uword
1023 interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
1024                       vlib_frame_t * from_frame)
1025 {
1026   vnet_main_t *vnm = vnet_get_main ();
1027   u32 last_sw_if_index = ~0;
1028   vlib_frame_t *to_frame = 0;
1029   vnet_hw_interface_t *hw = 0;
1030   u32 *from, *to_next = 0;
1031   u32 n_left_from;
1032
1033   from = vlib_frame_vector_args (from_frame);
1034   n_left_from = from_frame->n_vectors;
1035   while (n_left_from > 0)
1036     {
1037       u32 bi0;
1038       vlib_buffer_t *b0;
1039       u32 sw_if_index0;
1040
1041       bi0 = from[0];
1042       from++;
1043       n_left_from--;
1044       b0 = vlib_get_buffer (vm, bi0);
1045       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
1046
1047       if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
1048         {
1049           if (to_frame)
1050             {
1051               hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
1052               vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1053             }
1054           last_sw_if_index = sw_if_index0;
1055           hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1056           to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
1057           to_next = vlib_frame_vector_args (to_frame);
1058         }
1059
1060       to_next[0] = bi0;
1061       to_next++;
1062       to_frame->n_vectors++;
1063     }
1064   vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
1065   return from_frame->n_vectors;
1066 }
1067
1068 /* *INDENT-OFF* */
1069 VLIB_REGISTER_NODE (interface_tx, static) = {
1070   .function = interface_tx_node_fn,
1071   .name = "interface-tx",
1072   .vector_size = sizeof (u32),
1073   .n_next_nodes = 1,
1074   .next_nodes = {
1075     [0] = "error-drop",
1076   },
1077 };
1078
1079 VNET_FEATURE_ARC_INIT (interface_output, static) =
1080 {
1081   .arc_name  = "interface-output",
1082   .start_nodes = VNET_FEATURES (0),
1083   .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1084 };
1085
1086 VNET_FEATURE_INIT (span_tx, static) = {
1087   .arc_name = "interface-output",
1088   .node_name = "span-output",
1089   .runs_before = VNET_FEATURES ("interface-tx"),
1090 };
1091
1092 VNET_FEATURE_INIT (ipsec_if_tx, static) = {
1093   .arc_name = "interface-output",
1094   .node_name = "ipsec-if-output",
1095   .runs_before = VNET_FEATURES ("interface-tx"),
1096 };
1097
1098 VNET_FEATURE_INIT (interface_tx, static) = {
1099   .arc_name = "interface-output",
1100   .node_name = "interface-tx",
1101   .runs_before = 0,
1102 };
1103 /* *INDENT-ON* */
1104
1105 clib_error_t *
1106 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1107                                                        u32 hw_if_index,
1108                                                        u32 is_create)
1109 {
1110   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1111   u32 next_index;
1112
1113   if (hi->output_node_index == 0)
1114     return 0;
1115
1116   next_index = vlib_node_add_next
1117     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1118      hi->output_node_index);
1119   hi->output_node_next_index = next_index;
1120
1121   return 0;
1122 }
1123
1124 VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1125   (vnet_per_buffer_interface_output_hw_interface_add_del);
1126
1127 void
1128 vnet_set_interface_output_node (vnet_main_t * vnm,
1129                                 u32 hw_if_index, u32 node_index)
1130 {
1131   ASSERT (node_index);
1132   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1133   u32 next_index = vlib_node_add_next
1134     (vnm->vlib_main, vnet_per_buffer_interface_output_node.index, node_index);
1135   hi->output_node_next_index = next_index;
1136   hi->output_node_index = node_index;
1137 }
1138
1139 static clib_error_t *
1140 pcap_drop_trace_command_fn (vlib_main_t * vm,
1141                             unformat_input_t * input,
1142                             vlib_cli_command_t * cmd)
1143 {
1144   vnet_main_t *vnm = vnet_get_main ();
1145   vnet_interface_main_t *im = &vnm->interface_main;
1146   u8 *filename;
1147   u32 max;
1148   int matched = 0;
1149   clib_error_t *error = 0;
1150
1151   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1152     {
1153       if (unformat (input, "on"))
1154         {
1155           if (im->drop_pcap_enable == 0)
1156             {
1157               if (im->pcap_filename == 0)
1158                 im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0);
1159
1160               clib_memset (&im->pcap_main, 0, sizeof (im->pcap_main));
1161               im->pcap_main.file_name = (char *) im->pcap_filename;
1162               im->pcap_main.n_packets_to_capture = 100;
1163               if (im->pcap_pkts_to_capture)
1164                 im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture;
1165
1166               im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
1167               im->drop_pcap_enable = 1;
1168               matched = 1;
1169               vlib_cli_output (vm, "pcap drop capture on...");
1170             }
1171           else
1172             {
1173               vlib_cli_output (vm, "pcap drop capture already on...");
1174             }
1175           matched = 1;
1176         }
1177       else if (unformat (input, "off"))
1178         {
1179           matched = 1;
1180
1181           if (im->drop_pcap_enable)
1182             {
1183               vlib_cli_output (vm, "captured %d pkts...",
1184                                im->pcap_main.n_packets_captured);
1185               if (im->pcap_main.n_packets_captured)
1186                 {
1187                   im->pcap_main.n_packets_to_capture =
1188                     im->pcap_main.n_packets_captured;
1189                   error = pcap_write (&im->pcap_main);
1190                   if (error)
1191                     clib_error_report (error);
1192                   else
1193                     vlib_cli_output (vm, "saved to %s...", im->pcap_filename);
1194                 }
1195             }
1196           else
1197             {
1198               vlib_cli_output (vm, "pcap drop capture already off...");
1199             }
1200
1201           im->drop_pcap_enable = 0;
1202         }
1203       else if (unformat (input, "max %d", &max))
1204         {
1205           im->pcap_pkts_to_capture = max;
1206           matched = 1;
1207         }
1208
1209       else if (unformat (input, "intfc %U",
1210                          unformat_vnet_sw_interface, vnm,
1211                          &im->pcap_sw_if_index))
1212         matched = 1;
1213       else if (unformat (input, "intfc any"))
1214         {
1215           im->pcap_sw_if_index = 0;
1216           matched = 1;
1217         }
1218       else if (unformat (input, "file %s", &filename))
1219         {
1220           u8 *chroot_filename;
1221           /* Brain-police user path input */
1222           if (strstr ((char *) filename, "..")
1223               || index ((char *) filename, '/'))
1224             {
1225               vlib_cli_output (vm, "illegal characters in filename '%s'",
1226                                filename);
1227               continue;
1228             }
1229
1230           chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1231           vec_free (filename);
1232
1233           if (im->pcap_filename)
1234             vec_free (im->pcap_filename);
1235           im->pcap_filename = chroot_filename;
1236           im->pcap_main.file_name = (char *) im->pcap_filename;
1237           matched = 1;
1238         }
1239       else if (unformat (input, "status"))
1240         {
1241           if (im->drop_pcap_enable == 0)
1242             {
1243               vlib_cli_output (vm, "pcap drop capture is off...");
1244               continue;
1245             }
1246
1247           vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...",
1248                            im->pcap_main.n_packets_captured,
1249                            im->pcap_main.n_packets_to_capture);
1250           matched = 1;
1251         }
1252
1253       else
1254         break;
1255     }
1256
1257   if (matched == 0)
1258     return clib_error_return (0, "unknown input `%U'",
1259                               format_unformat_error, input);
1260
1261   return 0;
1262 }
1263
1264 /* *INDENT-OFF* */
1265 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
1266   .path = "pcap drop trace",
1267   .short_help =
1268   "pcap drop trace on off max <nn> intfc <intfc> file <name> status",
1269   .function = pcap_drop_trace_command_fn,
1270 };
1271 /* *INDENT-ON* */
1272
1273 /*
1274  * fd.io coding-style-patch-verification: ON
1275  *
1276  * Local Variables:
1277  * eval: (c-set-style "gnu")
1278  * End:
1279  */