LCOV - code coverage report
Current view: top level - vnet/span - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 123 127 96.9 %
Date: 2023-07-05 22:20:52 Functions: 33 46 71.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 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             : #include <vlib/vlib.h>
      17             : #include <vnet/vnet.h>
      18             : #include <vppinfra/error.h>
      19             : 
      20             : #include <vnet/span/span.h>
      21             : #include <vnet/l2/l2_input.h>
      22             : #include <vnet/l2/l2_output.h>
      23             : #include <vnet/l2/feat_bitmap.h>
      24             : 
      25             : #include <vppinfra/error.h>
      26             : #include <vppinfra/elog.h>
      27             : 
      28             : /* packet trace format function */
      29             : static u8 *
      30        3084 : format_span_trace (u8 * s, va_list * args)
      31             : {
      32        3084 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      33        3084 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      34        3084 :   span_trace_t *t = va_arg (*args, span_trace_t *);
      35             : 
      36        3084 :   vnet_main_t *vnm = vnet_get_main ();
      37        3084 :   s = format (s, "SPAN: mirrored %U -> %U",
      38             :               format_vnet_sw_if_index_name, vnm, t->src_sw_if_index,
      39             :               format_vnet_sw_if_index_name, vnm, t->mirror_sw_if_index);
      40             : 
      41        3084 :   return s;
      42             : }
      43             : 
      44             : #define foreach_span_error                      \
      45             : _(HITS, "SPAN incoming packets processed")
      46             : 
      47             : typedef enum
      48             : {
      49             : #define _(sym,str) SPAN_ERROR_##sym,
      50             :   foreach_span_error
      51             : #undef _
      52             :     SPAN_N_ERROR,
      53             : } span_error_t;
      54             : 
      55             : static char *span_error_strings[] = {
      56             : #define _(sym,string) string,
      57             :   foreach_span_error
      58             : #undef _
      59             : };
      60             : 
      61             : static_always_inline void
      62        3084 : span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
      63             :              vlib_buffer_t * b0, vlib_frame_t ** mirror_frames,
      64             :              vlib_rx_or_tx_t rxtx, span_feat_t sf)
      65             : {
      66             :   vlib_buffer_t *c0;
      67        3084 :   span_main_t *sm = &span_main;
      68        3084 :   vnet_main_t *vnm = vnet_get_main ();
      69        3084 :   u32 *to_mirror_next = 0;
      70             :   u32 i;
      71             :   span_interface_t *si0;
      72             :   span_mirror_t *sm0;
      73             : 
      74        3084 :   if (sw_if_index0 >= vec_len (sm->interfaces))
      75           0 :     return;
      76             : 
      77        3084 :   si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
      78        3084 :   sm0 = &si0->mirror_rxtx[sf][rxtx];
      79             : 
      80        3084 :   if (sm0->num_mirror_ports == 0)
      81           0 :     return;
      82             : 
      83             :   /* Don't do it again */
      84        3084 :   if (PREDICT_FALSE (b0->flags & VNET_BUFFER_F_SPAN_CLONE))
      85           0 :     return;
      86             : 
      87             :   /* *INDENT-OFF* */
      88        6168 :   clib_bitmap_foreach (i, sm0->mirror_ports)
      89             :     {
      90        3084 :       if (mirror_frames[i] == 0)
      91             :         {
      92          24 :           if (sf == SPAN_FEAT_L2)
      93          22 :             mirror_frames[i] = vlib_get_frame_to_node (vm, l2output_node.index);
      94             :           else
      95           2 :             mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
      96             :         }
      97        3084 :       to_mirror_next = vlib_frame_vector_args (mirror_frames[i]);
      98        3084 :       to_mirror_next += mirror_frames[i]->n_vectors;
      99             :       /* This can fail */
     100        3084 :       c0 = vlib_buffer_copy (vm, b0);
     101        3084 :       if (PREDICT_TRUE(c0 != 0))
     102             :         {
     103        3084 :           vnet_buffer (c0)->sw_if_index[VLIB_TX] = i;
     104        3084 :           c0->flags |= VNET_BUFFER_F_SPAN_CLONE;
     105        3084 :           if (sf == SPAN_FEAT_L2)
     106        2827 :             vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT;
     107        3084 :           to_mirror_next[0] = vlib_get_buffer_index (vm, c0);
     108        3084 :           mirror_frames[i]->n_vectors++;
     109        3084 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     110             :             {
     111        3084 :               span_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
     112        3084 :               t->src_sw_if_index = sw_if_index0;
     113        3084 :               t->mirror_sw_if_index = i;
     114             : #if 0
     115             :               /* Enable this path to allow packet trace of SPAN packets.
     116             :                  Note that all SPAN packets will show up on the trace output
     117             :                  with the first SPAN packet (since they are in the same frame)
     118             :                  thus making trace output of the original packet confusing */
     119             :               mirror_frames[i]->flags |= VLIB_FRAME_TRACE;
     120             :               c0->flags |= VLIB_BUFFER_IS_TRACED;
     121             : #endif
     122             :             }
     123             :         }
     124             :     }
     125             :   /* *INDENT-ON* */
     126             : }
     127             : 
     128             : static_always_inline uword
     129          24 : span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
     130             :                      vlib_frame_t * frame, vlib_rx_or_tx_t rxtx,
     131             :                      span_feat_t sf)
     132             : {
     133          24 :   span_main_t *sm = &span_main;
     134          24 :   vnet_main_t *vnm = vnet_get_main ();
     135             :   u32 n_left_from, *from, *to_next;
     136             :   u32 next_index;
     137             :   u32 sw_if_index;
     138             :   static __thread vlib_frame_t **mirror_frames = 0;
     139             : 
     140          24 :   from = vlib_frame_vector_args (frame);
     141          24 :   n_left_from = frame->n_vectors;
     142          24 :   next_index = node->cached_next_index;
     143             : 
     144          24 :   vec_validate_aligned (mirror_frames, sm->max_sw_if_index,
     145             :                         CLIB_CACHE_LINE_BYTES);
     146             : 
     147          48 :   while (n_left_from > 0)
     148             :     {
     149             :       u32 n_left_to_next;
     150             : 
     151          24 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     152             : 
     153        1548 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     154             :         {
     155             :           u32 bi0;
     156             :           u32 bi1;
     157             :           vlib_buffer_t *b0;
     158             :           vlib_buffer_t *b1;
     159             :           u32 sw_if_index0;
     160        1524 :           u32 next0 = 0;
     161             :           u32 sw_if_index1;
     162        1524 :           u32 next1 = 0;
     163             : 
     164             :           /* speculatively enqueue b0, b1 to the current next frame */
     165        1524 :           to_next[0] = bi0 = from[0];
     166        1524 :           to_next[1] = bi1 = from[1];
     167        1524 :           to_next += 2;
     168        1524 :           n_left_to_next -= 2;
     169        1524 :           from += 2;
     170        1524 :           n_left_from -= 2;
     171             : 
     172        1524 :           b0 = vlib_get_buffer (vm, bi0);
     173        1524 :           b1 = vlib_get_buffer (vm, bi1);
     174        1524 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
     175        1524 :           sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx];
     176             : 
     177        1524 :           span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
     178        1524 :           span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf);
     179             : 
     180        1524 :           switch (sf)
     181             :             {
     182        1397 :             case SPAN_FEAT_L2:
     183        1397 :               if (rxtx == VLIB_RX)
     184             :                 {
     185        1016 :                   next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
     186             :                                                 L2INPUT_FEAT_SPAN);
     187        1016 :                   next1 = vnet_l2_feature_next (b1, sm->l2_input_next,
     188             :                                                 L2INPUT_FEAT_SPAN);
     189             :                 }
     190             :               else
     191             :                 {
     192         381 :                   next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
     193             :                                                 L2OUTPUT_FEAT_SPAN);
     194         381 :                   next1 = vnet_l2_feature_next (b1, sm->l2_output_next,
     195             :                                                 L2OUTPUT_FEAT_SPAN);
     196             :                 }
     197        1397 :               break;
     198         127 :             case SPAN_FEAT_DEVICE:
     199             :             default:
     200         127 :               vnet_feature_next (&next0, b0);
     201         127 :               vnet_feature_next (&next1, b1);
     202         127 :               break;
     203             :             }
     204             : 
     205             :           /* verify speculative enqueue, maybe switch current next frame */
     206        1524 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
     207             :                                            to_next, n_left_to_next,
     208             :                                            bi0, bi1, next0, next1);
     209             :         }
     210          60 :       while (n_left_from > 0 && n_left_to_next > 0)
     211             :         {
     212             :           u32 bi0;
     213             :           vlib_buffer_t *b0;
     214             :           u32 sw_if_index0;
     215          36 :           u32 next0 = 0;
     216             : 
     217             :           /* speculatively enqueue b0 to the current next frame */
     218          36 :           to_next[0] = bi0 = from[0];
     219          36 :           to_next += 1;
     220          36 :           n_left_to_next -= 1;
     221          36 :           from += 1;
     222          36 :           n_left_from -= 1;
     223             : 
     224          36 :           b0 = vlib_get_buffer (vm, bi0);
     225          36 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
     226             : 
     227          36 :           span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
     228             : 
     229          36 :           switch (sf)
     230             :             {
     231          33 :             case SPAN_FEAT_L2:
     232          33 :               if (rxtx == VLIB_RX)
     233          24 :                 next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
     234             :                                               L2INPUT_FEAT_SPAN);
     235             :               else
     236           9 :                 next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
     237             :                                               L2OUTPUT_FEAT_SPAN);
     238          33 :               break;
     239           3 :             case SPAN_FEAT_DEVICE:
     240             :             default:
     241           3 :               vnet_feature_next (&next0, b0);
     242           3 :               break;
     243             :             }
     244             : 
     245             :           /* verify speculative enqueue, maybe switch current next frame */
     246          36 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     247             :                                            n_left_to_next, bi0, next0);
     248             :         }
     249             : 
     250          24 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     251             :     }
     252             : 
     253             : 
     254         166 :   for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++)
     255             :     {
     256         142 :       vlib_frame_t *f = mirror_frames[sw_if_index];
     257         142 :       if (f == 0)
     258         118 :         continue;
     259             : 
     260          24 :       if (sf == SPAN_FEAT_L2)
     261          22 :         vlib_put_frame_to_node (vm, l2output_node.index, f);
     262             :       else
     263           2 :         vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
     264          24 :       mirror_frames[sw_if_index] = 0;
     265             :     }
     266             : 
     267          24 :   return frame->n_vectors;
     268             : }
     269             : 
     270        2238 : VLIB_NODE_FN (span_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     271             :                                 vlib_frame_t * frame)
     272             : {
     273           2 :   return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE);
     274             : }
     275             : 
     276        2236 : VLIB_NODE_FN (span_output_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     277             :                                  vlib_frame_t * frame)
     278             : {
     279           0 :   return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE);
     280             : }
     281             : 
     282        2252 : VLIB_NODE_FN (span_l2_input_node) (vlib_main_t * vm,
     283             :                                    vlib_node_runtime_t * node,
     284             :                                    vlib_frame_t * frame)
     285             : {
     286          16 :   return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2);
     287             : }
     288             : 
     289        2242 : VLIB_NODE_FN (span_l2_output_node) (vlib_main_t * vm,
     290             :                                     vlib_node_runtime_t * node,
     291             :                                     vlib_frame_t * frame)
     292             : {
     293           6 :   return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2);
     294             : }
     295             : 
     296             : #define span_node_defs                           \
     297             :   .vector_size = sizeof (u32),                   \
     298             :   .format_trace = format_span_trace,             \
     299             :   .type = VLIB_NODE_TYPE_INTERNAL,               \
     300             :   .n_errors = ARRAY_LEN(span_error_strings),     \
     301             :   .error_strings = span_error_strings,           \
     302             :   .n_next_nodes = 0,                             \
     303             :   .next_nodes = {                                \
     304             :     [0] = "error-drop"                           \
     305             :   }
     306             : 
     307             : /* *INDENT-OFF* */
     308      178120 : VLIB_REGISTER_NODE (span_input_node) = {
     309             :   span_node_defs,
     310             :   .name = "span-input",
     311             : };
     312             : 
     313      178120 : VLIB_REGISTER_NODE (span_output_node) = {
     314             :   span_node_defs,
     315             :   .name = "span-output",
     316             : };
     317             : 
     318      178120 : VLIB_REGISTER_NODE (span_l2_input_node) = {
     319             :   span_node_defs,
     320             :   .name = "span-l2-input",
     321             : };
     322             : 
     323      178120 : VLIB_REGISTER_NODE (span_l2_output_node) = {
     324             :   span_node_defs,
     325             :   .name = "span-l2-output",
     326             : };
     327             : 
     328             : #ifndef CLIB_MARCH_VARIANT
     329         559 : clib_error_t *span_init (vlib_main_t * vm)
     330             : {
     331         559 :   span_main_t *sm = &span_main;
     332             : 
     333         559 :   sm->vlib_main = vm;
     334         559 :   sm->vnet_main = vnet_get_main ();
     335             : 
     336             :   /* Initialize the feature next-node indexes */
     337         559 :   feat_bitmap_init_next_nodes (vm,
     338             :                                span_l2_input_node.index,
     339             :                                L2INPUT_N_FEAT,
     340             :                                l2input_get_feat_names (),
     341         559 :                                sm->l2_input_next);
     342             : 
     343         559 :   feat_bitmap_init_next_nodes (vm,
     344             :                                span_l2_output_node.index,
     345             :                                L2OUTPUT_N_FEAT,
     346             :                                l2output_get_feat_names (),
     347         559 :                                sm->l2_output_next);
     348         559 :   return 0;
     349             : }
     350             : 
     351       72239 : VLIB_INIT_FUNCTION (span_init);
     352             : /* *INDENT-ON* */
     353             : #endif /* CLIB_MARCH_VARIANT */
     354             : 
     355             : #undef span_node_defs
     356             : /*
     357             :  * fd.io coding-style-patch-verification: ON
     358             :  *
     359             :  * Local Variables:
     360             :  * eval: (c-set-style "gnu")
     361             :  * End:
     362             :  */

Generated by: LCOV version 1.14