span: add tx functionality and support for multiple mirror ports
[vpp.git] / vnet / vnet / interface_output.c
index 173bb75..475b0b9 100644 (file)
@@ -38,6 +38,7 @@
  */
 
 #include <vnet/vnet.h>
+#include <vnet/feature/feature.h>
 
 typedef struct
 {
@@ -58,15 +59,30 @@ format_vnet_interface_output_trace (u8 * s, va_list * va)
 
   if (t->sw_if_index != (u32) ~ 0)
     {
-      si = vnet_get_sw_interface (vnm, t->sw_if_index);
       indent = format_get_indent (s);
 
-      s = format (s, "%U\n%U%U",
-                 format_vnet_sw_interface_name, vnm, si,
-                 format_white_space, indent,
-                 node->format_buffer ? node->
-                 format_buffer : format_hex_bytes, t->data,
-                 sizeof (t->data));
+      if (pool_is_free_index
+         (vnm->interface_main.sw_interfaces, t->sw_if_index))
+       {
+         /* the interface may have been deleted by the time the trace is printed */
+         s = format (s, "sw_if_index: %d\n%U%U",
+                     t->sw_if_index,
+                     format_white_space, indent,
+                     node->format_buffer ? node->
+                     format_buffer : format_hex_bytes, t->data,
+                     sizeof (t->data));
+       }
+      else
+       {
+         si = vnet_get_sw_interface (vnm, t->sw_if_index);
+
+         s = format (s, "%U\n%U%U",
+                     format_vnet_sw_interface_name, vnm, si,
+                     format_white_space, indent,
+                     node->format_buffer ? node->
+                     format_buffer : format_hex_bytes, t->data,
+                     sizeof (t->data));
+       }
     }
   return s;
 }
@@ -213,8 +229,9 @@ incr_output_stats (vnet_main_t * vnm,
 
 /* Interface output functions. */
 uword
-vnet_interface_output_node (vlib_main_t * vm,
-                           vlib_node_runtime_t * node, vlib_frame_t * frame)
+vnet_interface_output_node_flatten (vlib_main_t * vm,
+                                   vlib_node_runtime_t * node,
+                                   vlib_frame_t * frame)
 {
   vnet_main_t *vnm = vnet_get_main ();
   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
@@ -397,14 +414,12 @@ vnet_interface_output_node (vlib_main_t * vm,
   return n_buffers;
 }
 
-VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
-CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
+VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node_flatten);
+CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node_flatten);
 
-always_inline uword
-vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
-                                             vlib_node_runtime_t * node,
-                                             vlib_frame_t * frame,
-                                             int with_features)
+uword
+vnet_interface_output_node (vlib_main_t * vm,
+                           vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
   vnet_main_t *vnm = vnet_get_main ();
   vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
@@ -416,6 +431,8 @@ vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
   u32 cpu_index = vm->cpu_index;
   vnet_interface_main_t *im = &vnm->interface_main;
   u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
+  u32 current_config_index = ~0;
+  u8 arc = im->output_feature_arc_index;
 
   n_buffers = frame->n_vectors;
 
@@ -458,6 +475,17 @@ vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
   n_bytes = 0;
   n_packets = 0;
 
+  /* interface-output feature arc handling */
+  if (PREDICT_FALSE (vnet_have_features (arc, rt->sw_if_index)))
+    {
+      vnet_feature_config_main_t *fcm;
+      fcm = vnet_feature_get_config_main (arc);
+      current_config_index = vnet_get_feature_config_index (arc,
+                                                           rt->sw_if_index);
+      vnet_get_config_data (&fcm->config_main, &current_config_index,
+                           &next_index, 0);
+    }
+
   while (from < from_end)
     {
       /* Get new next frame since previous incomplete frame may have less
@@ -469,7 +497,6 @@ vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
          u32 bi0, bi1;
          vlib_buffer_t *b0, *b1;
          u32 tx_swif0, tx_swif1;
-         u32 next0, next1;
 
          /* Prefetch next iteration. */
          vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
@@ -498,60 +525,33 @@ vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
 
          n_bytes += n_bytes_b0 + n_bytes_b1;
          n_packets += 2;
-         if (with_features)
-           {
-             b0->flags |= BUFFER_OUTPUT_FEAT_DONE;
-             vnet_buffer (b0)->output_features.bitmap =
-               si->output_feature_bitmap;
-             count_trailing_zeros (next0,
-                                   vnet_buffer (b0)->output_features.bitmap);
-             vnet_buffer (b0)->output_features.bitmap &= ~(1 << next0);
-           }
-         else
-           {
-             next0 = VNET_INTERFACE_OUTPUT_NEXT_TX;
-             vnet_buffer (b0)->output_features.bitmap = 0;
 
-             if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
-               {
-                 /* update vlan subif tx counts, if required */
-                 vlib_increment_combined_counter (im->combined_sw_if_counters
-                                                  +
-                                                  VNET_INTERFACE_COUNTER_TX,
-                                                  cpu_index, tx_swif0, 1,
-                                                  n_bytes_b0);
-               }
+         if (PREDICT_FALSE (current_config_index != ~0))
+           {
+             b0->feature_arc_index = arc;
+             b1->feature_arc_index = arc;
+             b0->current_config_index = current_config_index;
+             b1->current_config_index = current_config_index;
            }
 
-         if (with_features)
+         if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
            {
-             b1->flags |= BUFFER_OUTPUT_FEAT_DONE;
-             vnet_buffer (b1)->output_features.bitmap =
-               si->output_feature_bitmap;
-             count_trailing_zeros (next1,
-                                   vnet_buffer (b1)->output_features.bitmap);
-             vnet_buffer (b1)->output_features.bitmap &= ~(1 << next1);
+             /* update vlan subif tx counts, if required */
+             vlib_increment_combined_counter (im->combined_sw_if_counters +
+                                              VNET_INTERFACE_COUNTER_TX,
+                                              cpu_index, tx_swif0, 1,
+                                              n_bytes_b0);
            }
-         else
-           {
-             next1 = VNET_INTERFACE_OUTPUT_NEXT_TX;
-             vnet_buffer (b1)->output_features.bitmap = 0;
 
-             /* update vlan subif tx counts, if required */
-             if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
-               {
+         /* update vlan subif tx counts, if required */
+         if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
+           {
 
-                 vlib_increment_combined_counter (im->combined_sw_if_counters
-                                                  +
-                                                  VNET_INTERFACE_COUNTER_TX,
-                                                  cpu_index, tx_swif1, 1,
-                                                  n_bytes_b1);
-               }
+             vlib_increment_combined_counter (im->combined_sw_if_counters +
+                                              VNET_INTERFACE_COUNTER_TX,
+                                              cpu_index, tx_swif1, 1,
+                                              n_bytes_b1);
            }
-         if (with_features)
-           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_tx,
-                                            n_left_to_tx, bi0, bi1, next0,
-                                            next1);
        }
 
       while (from + 1 <= from_end && n_left_to_tx >= 1)
@@ -577,31 +577,19 @@ vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
          n_bytes += n_bytes_b0;
          n_packets += 1;
 
-         if (with_features)
+         if (PREDICT_FALSE (current_config_index != ~0))
            {
-             u32 next0;
-             b0->flags |= BUFFER_OUTPUT_FEAT_DONE;
-             vnet_buffer (b0)->output_features.bitmap =
-               si->output_feature_bitmap;
-             count_trailing_zeros (next0,
-                                   vnet_buffer (b0)->output_features.bitmap);
-             vnet_buffer (b0)->output_features.bitmap &= ~(1 << next0);
-             vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_tx,
-                                              n_left_to_tx, bi0, next0);
+             b0->feature_arc_index = arc;
+             b0->current_config_index = current_config_index;
            }
-         else
-           {
-             vnet_buffer (b0)->output_features.bitmap = 0;
 
-             if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
-               {
+         if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
+           {
 
-                 vlib_increment_combined_counter (im->combined_sw_if_counters
-                                                  +
-                                                  VNET_INTERFACE_COUNTER_TX,
-                                                  cpu_index, tx_swif0, 1,
-                                                  n_bytes_b0);
-               }
+             vlib_increment_combined_counter (im->combined_sw_if_counters +
+                                              VNET_INTERFACE_COUNTER_TX,
+                                              cpu_index, tx_swif0, 1,
+                                              n_bytes_b0);
            }
        }
 
@@ -616,33 +604,8 @@ vnet_interface_output_node_no_flatten_inline (vlib_main_t * vm,
   return n_buffers;
 }
 
-uword
-vnet_interface_output_node_no_flatten (vlib_main_t * vm,
-                                      vlib_node_runtime_t * node,
-                                      vlib_frame_t * frame)
-{
-  vnet_main_t *vnm = vnet_get_main ();
-  vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
-  vnet_sw_interface_t *si;
-  si = vnet_get_sw_interface (vnm, rt->sw_if_index);
-
-  if (PREDICT_FALSE (si->output_feature_bitmap))
-    {
-      /* if first pakcet in the frame have BUFFER_OUTPUT_FEAT_DONE flag set
-         then whole frame is arriving from feature node */
-
-      u32 *from = vlib_frame_args (frame);
-      vlib_buffer_t *b = vlib_get_buffer (vm, from[0]);
-
-      if ((b->flags & BUFFER_OUTPUT_FEAT_DONE) == 0)
-       return vnet_interface_output_node_no_flatten_inline (vm, node, frame,
-                                                            1);
-    }
-  return vnet_interface_output_node_no_flatten_inline (vm, node, frame, 0);
-}
-
-VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node_no_flatten);
-CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node_no_flatten);
+VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
+CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
 
 /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
 static uword
@@ -1199,6 +1162,84 @@ VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
 VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
                              vnet_per_buffer_interface_output);
 
+static uword
+interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                     vlib_frame_t * from_frame)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 last_sw_if_index = ~0;
+  vlib_frame_t *to_frame = 0;
+  vnet_hw_interface_t *hw = 0;
+  u32 *from, *to_next = 0;
+  u32 n_left_from;
+
+  from = vlib_frame_vector_args (from_frame);
+  n_left_from = from_frame->n_vectors;
+  while (n_left_from > 0)
+    {
+      u32 bi0;
+      vlib_buffer_t *b0;
+      u32 sw_if_index0;
+
+      bi0 = from[0];
+      from++;
+      n_left_from--;
+      b0 = vlib_get_buffer (vm, bi0);
+      sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+
+      if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
+       {
+         if (to_frame)
+           {
+             hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
+             vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
+           }
+         last_sw_if_index = sw_if_index0;
+         hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
+         to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
+         to_next = vlib_frame_vector_args (to_frame);
+       }
+
+      to_next[0] = bi0;
+      to_next++;
+      to_frame->n_vectors++;
+    }
+  vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
+  return from_frame->n_vectors;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (interface_tx, static) = {
+  .function = interface_tx_node_fn,
+  .name = "interface-tx",
+  .vector_size = sizeof (u32),
+  .n_next_nodes = 1,
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VNET_FEATURE_ARC_INIT (interface_output, static) =
+{
+  .arc_name  = "interface-output",
+  .start_nodes = VNET_FEATURES (0),
+  .end_node = "interface-tx",
+  .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
+};
+
+VNET_FEATURE_INIT (span_tx, static) = {
+  .arc_name = "interface-output",
+  .node_name = "span-output",
+  .runs_before = VNET_FEATURES ("interface-tx"),
+};
+
+VNET_FEATURE_INIT (interface_tx, static) = {
+  .arc_name = "interface-output",
+  .node_name = "interface-tx",
+  .runs_before = 0,
+};
+/* *INDENT-ON* */
+
 clib_error_t *
 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
                                                       u32 hw_if_index,