L2-FIB: replace bit-fields with flags
[vpp.git] / src / vnet / l2 / l2_fwd.c
index 710a9d9..8c03683 100644 (file)
@@ -49,6 +49,9 @@ typedef struct
   /* next node index for the L3 input node of each ethertype */
   next_by_ethertype_t l3_next;
 
+  /* Next nodes for each feature */
+  u32 feat_next_node_index[32];
+
   /* convenience variables */
   vlib_main_t *vlib_main;
   vnet_main_t *vnet_main;
@@ -89,7 +92,8 @@ _(HIT,           "L2 forward hits")                   \
 _(BVI_BAD_MAC,   "BVI L3 MAC mismatch")                \
 _(BVI_ETHERTYPE, "BVI packet with unhandled ethertype")        \
 _(FILTER_DROP,   "Filter Mac Drop")                    \
-_(REFLECT_DROP,  "Reflection Drop")
+_(REFLECT_DROP,  "Reflection Drop")                    \
+_(STALE_DROP,    "Stale entry Drop")
 
 typedef enum
 {
@@ -108,7 +112,6 @@ static char *l2fwd_error_strings[] = {
 typedef enum
 {
   L2FWD_NEXT_L2_OUTPUT,
-  L2FWD_NEXT_FLOOD,
   L2FWD_NEXT_DROP,
   L2FWD_N_NEXT,
 } l2fwd_next_t;
@@ -123,28 +126,15 @@ l2fwd_process (vlib_main_t * vm,
               vlib_buffer_t * b0,
               u32 sw_if_index0, l2fib_entry_result_t * result0, u32 * next0)
 {
-  if (PREDICT_FALSE (result0->raw == ~0))
-    {
-      /*
-       * lookup miss, so flood
-       * TODO:replicate packet to each intf in bridge-domain
-       * For now just drop
-       */
-      if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD)
-       {
-         *next0 = L2FWD_NEXT_FLOOD;
-       }
-      else
-       {
-         /* Flooding is disabled */
-         b0->error = node->errors[L2FWD_ERROR_FLOOD];
-         *next0 = L2FWD_NEXT_DROP;
-       }
+  int try_flood = result0->raw == ~0;
+  int flood_error;
 
+  if (PREDICT_FALSE (try_flood))
+    {
+      flood_error = L2FWD_ERROR_FLOOD;
     }
   else
     {
-
       /* lookup hit, forward packet  */
 #ifdef COUNTERS
       em->counters[node_counter_base_index + L2FWD_ERROR_HIT] += 1;
@@ -152,23 +142,39 @@ l2fwd_process (vlib_main_t * vm,
 
       vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index;
       *next0 = L2FWD_NEXT_L2_OUTPUT;
+      int l2fib_seq_num_valid = 1;
+
+      /* check l2fib seq num for stale entries */
+      if (!l2fib_entry_result_is_set_AGE_NOT (result0))
+       {
+         l2fib_seq_num_t in_sn = {.as_u16 = vnet_buffer (b0)->l2.l2fib_sn };
+         l2fib_seq_num_t expected_sn = {
+           .bd = in_sn.bd,
+           .swif = *l2fib_swif_seq_num (result0->fields.sw_if_index),
+         };
+         l2fib_seq_num_valid =
+           expected_sn.as_u16 == result0->fields.sn.as_u16;
+       }
 
+      if (PREDICT_FALSE (!l2fib_seq_num_valid))
+       {
+         flood_error = L2FWD_ERROR_STALE_DROP;
+         try_flood = 1;
+       }
       /* perform reflection check */
-      if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index))
+      else if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index))
        {
          b0->error = node->errors[L2FWD_ERROR_REFLECT_DROP];
          *next0 = L2FWD_NEXT_DROP;
-
-         /* perform filter check */
        }
-      else if (PREDICT_FALSE (result0->fields.filter))
+      /* perform filter check */
+      else if (PREDICT_FALSE (l2fib_entry_result_is_set_FILTER (result0)))
        {
          b0->error = node->errors[L2FWD_ERROR_FILTER_DROP];
          *next0 = L2FWD_NEXT_DROP;
-
-         /* perform BVI check */
        }
-      else if (PREDICT_FALSE (result0->fields.bvi))
+      /* perform BVI check */
+      else if (PREDICT_FALSE (l2fib_entry_result_is_set_BVI (result0)))
        {
          u32 rc;
          rc = l2_to_bvi (vm,
@@ -192,12 +198,33 @@ l2fwd_process (vlib_main_t * vm,
            }
        }
     }
+
+  /* flood */
+  if (PREDICT_FALSE (try_flood))
+    {
+      /*
+       * lookup miss, so flood which is typically the next feature
+       * unless some other feature is inserted before uu_flood
+       */
+      if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD)
+       {
+         *next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index,
+                                        L2INPUT_FEAT_FWD);
+       }
+      else
+       {
+         /* Flooding is disabled */
+         b0->error = node->errors[flood_error];
+         *next0 = L2FWD_NEXT_DROP;
+       }
+    }
+
 }
 
 
-static uword
-l2fwd_node_fn (vlib_main_t * vm,
-              vlib_node_runtime_t * node, vlib_frame_t * frame)
+static_always_inline uword
+l2fwd_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
+                  vlib_frame_t * frame, int do_trace)
 {
   u32 n_left_from, *from, *to_next;
   l2fwd_next_t next_index;
@@ -281,7 +308,7 @@ l2fwd_node_fn (vlib_main_t * vm,
          h2 = vlib_buffer_get_current (b2);
          h3 = vlib_buffer_get_current (b3);
 
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+         if (do_trace)
            {
              if (b0->flags & VLIB_BUFFER_IS_TRACED)
                {
@@ -388,8 +415,7 @@ l2fwd_node_fn (vlib_main_t * vm,
 
          h0 = vlib_buffer_get_current (b0);
 
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
-                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+         if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
            {
              l2fwd_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
              t->sw_if_index = sw_if_index0;
@@ -420,6 +446,15 @@ l2fwd_node_fn (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
+static uword
+l2fwd_node_fn (vlib_main_t * vm,
+              vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+    return l2fwd_node_inline (vm, node, frame, 1 /* do_trace */ );
+  return l2fwd_node_inline (vm, node, frame, 0 /* do_trace */ );
+}
+
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (l2fwd_node,static) = {
   .function = l2fwd_node_fn,
@@ -436,7 +471,6 @@ VLIB_REGISTER_NODE (l2fwd_node,static) = {
   /* edit / add dispositions here */
   .next_nodes = {
     [L2FWD_NEXT_L2_OUTPUT] = "l2-output",
-    [L2FWD_NEXT_FLOOD] = "l2-flood",
     [L2FWD_NEXT_DROP] = "error-drop",
   },
 };
@@ -450,6 +484,13 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2fwd_node, l2fwd_node_fn)
   mp->vlib_main = vm;
   mp->vnet_main = vnet_get_main ();
 
+  /* Initialize the feature next-node indexes */
+  feat_bitmap_init_next_nodes (vm,
+                              l2fwd_node.index,
+                              L2INPUT_N_FEAT,
+                              l2input_get_feat_names (),
+                              mp->feat_next_node_index);
+
   /* init the hash table ptr */
   mp->mac_table = get_mac_table ();