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