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