VPP-650: handle buffer failure in vlib_buffer_copy(...)
[vpp.git] / src / vnet / dpo / replicate_dpo.c
index 8bad75e..a67b19c 100644 (file)
 #define REP_DBG(_p, _fmt, _args...)
 #endif
 
+#define foreach_replicate_dpo_error                       \
+_(BUFFER_ALLOCATION_FAILURE, "Buffer Allocation Failure")
+
+typedef enum {
+#define _(sym,str) REPLICATE_DPO_ERROR_##sym,
+  foreach_replicate_dpo_error
+#undef _
+  REPLICATE_DPO_N_ERROR,
+} replicate_dpo_error_t;
+
+static char * replicate_dpo_error_strings[] = {
+#define _(sym,string) string,
+  foreach_replicate_dpo_error
+#undef _
+};
 
 /**
  * Pool of all DPOs. It's not static so the DP can have fast access
@@ -664,8 +679,31 @@ replicate_inline (vlib_main_t * vm,
             /* ship copies to the rest of the buckets */
             for (bucket = 1; bucket < rep0->rep_n_buckets; bucket++)
             {
-                /* Make a copy */
+                /*
+                 * After the enqueue of the first buffer, and of all subsequent
+                 * buffers in this loop, it is possible that we over-flow the
+                 * frame of the to-next node. When this happens we need to 'put'
+                 * that full frame to the node and get a fresh empty one.
+                 * Note that these are macros with side effects that change
+                 * to_next & n_left_to_next
+                 */
+                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);
+                }
+
+                /* Make a copy. This can fail, so deal with it. */
                 c0 = vlib_buffer_copy(vm, b0);
+                if (PREDICT_FALSE (c0 == 0))
+                  {
+                    vlib_node_increment_counter 
+                      (vm, node->node_index, 
+                       REPLICATE_DPO_ERROR_BUFFER_ALLOCATION_FAILURE,
+                       1);
+                    continue;
+                  }
+                
                 ci0 = vlib_get_buffer_index(vm, c0);
 
                 to_next[0] = ci0;
@@ -676,9 +714,9 @@ replicate_inline (vlib_main_t * vm,
                 next0 = dpo0->dpoi_next_node;
                 vnet_buffer (c0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
 
-                if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+                if (PREDICT_FALSE(c0->flags & VLIB_BUFFER_IS_TRACED))
                 {
-                    replicate_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+                    replicate_trace_t *t = vlib_add_trace (vm, node, c0, sizeof (*t));
                     t->rep_index = repi0;
                     t->dpo = *dpo0;
                 }
@@ -724,6 +762,9 @@ VLIB_REGISTER_NODE (ip4_replicate_node) = {
   .name = "ip4-replicate",
   .vector_size = sizeof (u32),
 
+  .n_errors = ARRAY_LEN(replicate_dpo_error_strings),
+  .error_strings = replicate_dpo_error_strings,
+
   .format_trace = format_replicate_trace,
   .n_next_nodes = 1,
   .next_nodes = {
@@ -747,6 +788,9 @@ VLIB_REGISTER_NODE (ip6_replicate_node) = {
   .name = "ip6-replicate",
   .vector_size = sizeof (u32),
 
+  .n_errors = ARRAY_LEN(replicate_dpo_error_strings),
+  .error_strings = replicate_dpo_error_strings,
+
   .format_trace = format_replicate_trace,
   .n_next_nodes = 1,
   .next_nodes = {