l2: handle complete clone fail in l2_flood
[vpp.git] / src / vnet / l2 / l2_flood.c
index 6683017..b5eb5fe 100644 (file)
@@ -87,9 +87,11 @@ format_l2flood_trace (u8 * s, va_list * args)
   return s;
 }
 
-l2flood_main_t l2flood_main;
+extern l2flood_main_t l2flood_main;
 
-static vlib_node_registration_t l2flood_node;
+#ifndef CLIB_MARCH_VARIANT
+l2flood_main_t l2flood_main;
+#endif /* CLIB_MARCH_VARIANT */
 
 #define foreach_l2flood_error                                  \
 _(L2FLOOD,           "L2 flood packets")                       \
@@ -134,9 +136,8 @@ typedef enum
  * could be turned into an ICMP reply. If BVI processing is not performed
  * last, the modified packet would be replicated to the remaining members.
  */
-static uword
-l2flood_node_fn (vlib_main_t * vm,
-                vlib_node_runtime_t * node, vlib_frame_t * frame)
+VLIB_NODE_FN (l2flood_node) (vlib_main_t * vm,
+                            vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
   u32 n_left_from, *from, *to_next;
   l2flood_next_t next_index;
@@ -155,11 +156,12 @@ l2flood_node_fn (vlib_main_t * vm,
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
-         u32 next0, sw_if_index0, bi0, ci0;
          u16 n_clones, n_cloned, clone0;
          l2_bridge_domain_t *bd_config;
+         u32 sw_if_index0, bi0, ci0;
          l2_flood_member_t *member;
          vlib_buffer_t *b0, *c0;
+         u16 next0;
          u8 in_shg;
          i32 mi;
 
@@ -208,77 +210,91 @@ l2flood_node_fn (vlib_main_t * vm,
                                               bi0, L2FLOOD_NEXT_DROP);
              continue;
            }
-
-         vec_validate (msm->clones[thread_index], n_clones);
-         vec_reset_length (msm->clones[thread_index]);
-
-         /*
-          * the header offset needs to be large enoguh to incorporate
-          * all the L3 headers that could be touched when doing BVI
-          * processing. So take the current l2 length plus 2 * IPv6
-          * headers (for tunnel encap)
-          */
-         n_cloned = vlib_buffer_clone (vm, bi0,
-                                       msm->clones[thread_index],
-                                       n_clones,
-                                       (vnet_buffer (b0)->l2.l2_len +
-                                        sizeof (udp_header_t) +
-                                        2 * sizeof (ip6_header_t)));
-
-         if (PREDICT_FALSE (n_cloned != n_clones))
+         else if (n_clones > 1)
            {
-             b0->error = node->errors[L2FLOOD_ERROR_REPL_FAIL];
-           }
+             vec_validate (msm->clones[thread_index], n_clones);
+
+             /*
+              * the header offset needs to be large enough to incorporate
+              * all the L3 headers that could be touched when doing BVI
+              * processing. So take the current l2 length plus 2 * IPv6
+              * headers (for tunnel encap)
+              */
+             n_cloned = vlib_buffer_clone (vm, bi0,
+                                           msm->clones[thread_index],
+                                           n_clones,
+                                           VLIB_BUFFER_CLONE_HEAD_SIZE);
+
+             vec_set_len (msm->clones[thread_index], n_cloned);
+
+             if (PREDICT_FALSE (n_cloned != n_clones))
+               {
+                 b0->error = node->errors[L2FLOOD_ERROR_REPL_FAIL];
+                 /* Worst-case, no clones, consume the original buf */
+                 if (n_cloned == 0)
+                   {
+                     ci0 = bi0;
+                     member = msm->members[thread_index][0];
+                     goto use_original_buffer;
+                   }
+               }
 
-         /*
-          * for all but the last clone, these are not BVI bound
-          */
-         for (clone0 = 0; clone0 < n_cloned - 1; clone0++)
-           {
-             member = msm->members[thread_index][clone0];
-             ci0 = msm->clones[thread_index][clone0];
-             c0 = vlib_get_buffer (vm, ci0);
+             /*
+              * for all but the last clone, these are not BVI bound
+              */
+             for (clone0 = 0; clone0 < n_cloned - 1; clone0++)
+               {
+                 member = msm->members[thread_index][clone0];
+                 ci0 = msm->clones[thread_index][clone0];
+                 c0 = vlib_get_buffer (vm, ci0);
 
-             to_next[0] = ci0;
-             to_next += 1;
-             n_left_to_next -= 1;
+                 to_next[0] = ci0;
+                 to_next += 1;
+                 n_left_to_next -= 1;
 
-             if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
-                                (b0->flags & VLIB_BUFFER_IS_TRACED)))
-               {
-                 ethernet_header_t *h0;
-                 l2flood_trace_t *t;
-
-                 if (c0 != b0)
-                   vlib_buffer_copy_trace_flag (vm, b0, ci0);
-
-                 t = vlib_add_trace (vm, node, c0, sizeof (*t));
-                 h0 = vlib_buffer_get_current (c0);
-                 t->sw_if_index = sw_if_index0;
-                 t->bd_index = vnet_buffer (c0)->l2.bd_index;
-                 clib_memcpy (t->src, h0->src_address, 6);
-                 clib_memcpy (t->dst, h0->dst_address, 6);
-               }
+                 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                                    (b0->flags & VLIB_BUFFER_IS_TRACED)))
+                   {
+                     ethernet_header_t *h0;
+                     l2flood_trace_t *t;
+
+                     t = vlib_add_trace (vm, node, c0, sizeof (*t));
+                     h0 = vlib_buffer_get_current (c0);
+                     t->sw_if_index = sw_if_index0;
+                     t->bd_index = vnet_buffer (c0)->l2.bd_index;
+                     clib_memcpy_fast (t->src, h0->src_address, 6);
+                     clib_memcpy_fast (t->dst, h0->dst_address, 6);
+                   }
 
-             /* Do normal L2 forwarding */
-             vnet_buffer (c0)->sw_if_index[VLIB_TX] = member->sw_if_index;
+                 /* Do normal L2 forwarding */
+                 vnet_buffer (c0)->sw_if_index[VLIB_TX] =
+                   member->sw_if_index;
 
-             vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                              to_next, n_left_to_next,
-                                              ci0, next0);
-             if (PREDICT_FALSE (0 == n_left_to_next))
-               {
-                 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-                 vlib_get_next_frame (vm, node, next_index,
-                                      to_next, n_left_to_next);
+                 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+                                                  to_next, n_left_to_next,
+                                                  ci0, next0);
+                 if (PREDICT_FALSE (0 == n_left_to_next))
+                   {
+                     vlib_put_next_frame (vm, node, next_index,
+                                          n_left_to_next);
+                     vlib_get_next_frame (vm, node, next_index, to_next,
+                                          n_left_to_next);
+                   }
                }
+             member = msm->members[thread_index][clone0];
+             ci0 = msm->clones[thread_index][clone0];
+           }
+         else
+           {
+             /* one clone */
+             ci0 = bi0;
+             member = msm->members[thread_index][0];
            }
 
+       use_original_buffer:
          /*
           * the last clone that might go to a BVI
           */
-         member = msm->members[thread_index][clone0];
-         ci0 = msm->clones[thread_index][clone0];
          c0 = vlib_get_buffer (vm, ci0);
 
          to_next[0] = ci0;
@@ -291,18 +307,13 @@ l2flood_node_fn (vlib_main_t * vm,
              ethernet_header_t *h0;
              l2flood_trace_t *t;
 
-             if (c0 != b0)
-               vlib_buffer_copy_trace_flag (vm, b0, ci0);
-
              t = vlib_add_trace (vm, node, c0, sizeof (*t));
              h0 = vlib_buffer_get_current (c0);
              t->sw_if_index = sw_if_index0;
              t->bd_index = vnet_buffer (c0)->l2.bd_index;
-             clib_memcpy (t->src, h0->src_address, 6);
-             clib_memcpy (t->dst, h0->dst_address, 6);
+             clib_memcpy_fast (t->src, h0->src_address, 6);
+             clib_memcpy_fast (t->dst, h0->dst_address, 6);
            }
-
-
          /* Forward packet to the current member */
          if (PREDICT_FALSE (member->flags & L2_FLOOD_MEMBER_BVI))
            {
@@ -353,8 +364,7 @@ l2flood_node_fn (vlib_main_t * vm,
 
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (l2flood_node,static) = {
-  .function = l2flood_node_fn,
+VLIB_REGISTER_NODE (l2flood_node) = {
   .name = "l2-flood",
   .vector_size = sizeof (u32),
   .format_trace = format_l2flood_trace,
@@ -373,8 +383,9 @@ VLIB_REGISTER_NODE (l2flood_node,static) = {
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (l2flood_node, l2flood_node_fn)
-     clib_error_t *l2flood_init (vlib_main_t * vm)
+#ifndef CLIB_MARCH_VARIANT
+clib_error_t *
+l2flood_init (vlib_main_t * vm)
 {
   l2flood_main_t *mp = &l2flood_main;
 
@@ -410,6 +421,7 @@ l2flood_register_input_type (vlib_main_t * vm,
 
   next_by_ethertype_register (&mp->l3_next, type, next_index);
 }
+#endif /* CLIB_MARCH_VARIANT */
 
 
 /**