Add congestion drop in interface handoff 92/13592/1
authorDamjan Marion <damarion@cisco.com>
Fri, 20 Jul 2018 16:47:05 +0000 (18:47 +0200)
committerDamjan Marion <damarion@cisco.com>
Fri, 20 Jul 2018 17:43:36 +0000 (19:43 +0200)
This prevents deadlock in case when worker A sends to B and worker B
sends to A

Change-Id: Id9436960f932c58325fe4f5ef8ec67b50031aeda
Signed-off-by: Damjan Marion <damarion@cisco.com>
src/vlib/buffer_node.h
src/vlib/threads.c
src/vlib/threads.h
src/vnet/handoff.c

index cfdb056..93ffb1e 100644 (file)
@@ -443,28 +443,23 @@ vlib_buffer_enqueue_to_next (vlib_main_t * vm, vlib_node_runtime_t * node,
   vlib_put_next_frame (vm, node, next_index, n_left_to_next);
 }
 
-static_always_inline void
+static_always_inline u32
 vlib_buffer_enqueue_to_thread (vlib_main_t * vm, u32 frame_queue_index,
                               u32 * buffer_indices, u16 * thread_indices,
-                              u32 n_left)
+                              u32 n_packets, int drop_on_congestion)
 {
   vlib_thread_main_t *tm = vlib_get_thread_main ();
-  static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_thread_index =
-    0;
-  static __thread vlib_frame_queue_t **congested_handoff_queue_by_thread_index
-    = 0;
+  vlib_frame_queue_main_t *fqm;
+  vlib_frame_queue_per_thread_data_t *ptd;
+  u32 n_left = n_packets;
+  u32 drop_list[VLIB_FRAME_SIZE], *dbi = drop_list, n_drop = 0;
   vlib_frame_queue_elt_t *hf = 0;
   u32 n_left_to_next_thread = 0, *to_next_thread = 0;
   u32 next_thread_index, current_thread_index = ~0;
   int i;
 
-  if (PREDICT_FALSE (handoff_queue_elt_by_thread_index == 0))
-    {
-      vec_validate (handoff_queue_elt_by_thread_index, tm->n_vlib_mains - 1);
-      vec_validate_init_empty (congested_handoff_queue_by_thread_index,
-                              tm->n_vlib_mains - 1,
-                              (vlib_frame_queue_t *) (~0));
-    }
+  fqm = vec_elt_at_index (tm->frame_queue_mains, frame_queue_index);
+  ptd = vec_elt_at_index (fqm->per_thread_data, vm->thread_index);
 
   while (n_left)
     {
@@ -472,12 +467,24 @@ vlib_buffer_enqueue_to_thread (vlib_main_t * vm, u32 frame_queue_index,
 
       if (next_thread_index != current_thread_index)
        {
+
+         if (drop_on_congestion &&
+             is_vlib_frame_queue_congested
+             (frame_queue_index, next_thread_index, fqm->queue_hi_thresh,
+              ptd->congested_handoff_queue_by_thread_index))
+           {
+             dbi[0] = buffer_indices[0];
+             dbi++;
+             n_drop++;
+             goto next;
+           }
+
          if (hf)
            hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_thread;
 
          hf = vlib_get_worker_handoff_queue_elt (frame_queue_index,
                                                  next_thread_index,
-                                                 handoff_queue_elt_by_thread_index);
+                                                 ptd->handoff_queue_elt_by_thread_index);
 
          n_left_to_next_thread = VLIB_FRAME_SIZE - hf->n_vectors;
          to_next_thread = &hf->buffer_index[hf->n_vectors];
@@ -493,11 +500,12 @@ vlib_buffer_enqueue_to_thread (vlib_main_t * vm, u32 frame_queue_index,
          hf->n_vectors = VLIB_FRAME_SIZE;
          vlib_put_frame_queue_elt (hf);
          current_thread_index = ~0;
-         handoff_queue_elt_by_thread_index[next_thread_index] = 0;
+         ptd->handoff_queue_elt_by_thread_index[next_thread_index] = 0;
          hf = 0;
        }
 
       /* next */
+    next:
       thread_indices += 1;
       buffer_indices += 1;
       n_left -= 1;
@@ -507,11 +515,11 @@ vlib_buffer_enqueue_to_thread (vlib_main_t * vm, u32 frame_queue_index,
     hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_thread;
 
   /* Ship frames to the thread nodes */
-  for (i = 0; i < vec_len (handoff_queue_elt_by_thread_index); i++)
+  for (i = 0; i < vec_len (ptd->handoff_queue_elt_by_thread_index); i++)
     {
-      if (handoff_queue_elt_by_thread_index[i])
+      if (ptd->handoff_queue_elt_by_thread_index[i])
        {
-         hf = handoff_queue_elt_by_thread_index[i];
+         hf = ptd->handoff_queue_elt_by_thread_index[i];
          /*
           * It works better to let the handoff node
           * rate-adapt, always ship the handoff queue element.
@@ -519,14 +527,19 @@ vlib_buffer_enqueue_to_thread (vlib_main_t * vm, u32 frame_queue_index,
          if (1 || hf->n_vectors == hf->last_n_vectors)
            {
              vlib_put_frame_queue_elt (hf);
-             handoff_queue_elt_by_thread_index[i] = 0;
+             ptd->handoff_queue_elt_by_thread_index[i] = 0;
            }
          else
            hf->last_n_vectors = hf->n_vectors;
        }
-      congested_handoff_queue_by_thread_index[i] =
+      ptd->congested_handoff_queue_by_thread_index[i] =
        (vlib_frame_queue_t *) (~0);
     }
+
+  if (drop_on_congestion && n_drop)
+    vlib_buffer_free (vm, drop_list, n_drop);
+
+  return n_packets - n_drop;
 }
 
 #endif /* included_vlib_buffer_node_h */
index c53c5d6..70f22b1 100644 (file)
@@ -24,7 +24,7 @@
 
 DECLARE_CJ_GLOBAL_LOG;
 
-#define FRAME_QUEUE_NELTS 32
+#define FRAME_QUEUE_NELTS 64
 
 u32
 vl (void *p)
@@ -1795,16 +1795,29 @@ vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts)
   if (frame_queue_nelts == 0)
     frame_queue_nelts = FRAME_QUEUE_NELTS;
 
+  ASSERT (frame_queue_nelts >= 8);
+
   vec_add2 (tm->frame_queue_mains, fqm, 1);
 
   fqm->node_index = node_index;
+  fqm->frame_queue_nelts = frame_queue_nelts;
+  fqm->queue_hi_thresh = frame_queue_nelts - 2;
 
   vec_validate (fqm->vlib_frame_queues, tm->n_vlib_mains - 1);
+  vec_validate (fqm->per_thread_data, tm->n_vlib_mains - 1);
   _vec_len (fqm->vlib_frame_queues) = 0;
   for (i = 0; i < tm->n_vlib_mains; i++)
     {
+      vlib_frame_queue_per_thread_data_t *ptd;
       fq = vlib_frame_queue_alloc (frame_queue_nelts);
       vec_add1 (fqm->vlib_frame_queues, fq);
+
+      ptd = vec_elt_at_index (fqm->per_thread_data, i);
+      vec_validate (ptd->handoff_queue_elt_by_thread_index,
+                   tm->n_vlib_mains - 1);
+      vec_validate_init_empty (ptd->congested_handoff_queue_by_thread_index,
+                              tm->n_vlib_mains - 1,
+                              (vlib_frame_queue_t *) (~0));
     }
 
   return (fqm - tm->frame_queue_mains);
index f78ec1b..b47a633 100644 (file)
@@ -161,10 +161,20 @@ typedef struct
 }
 vlib_frame_queue_t;
 
+typedef struct
+{
+  vlib_frame_queue_elt_t **handoff_queue_elt_by_thread_index;
+  vlib_frame_queue_t **congested_handoff_queue_by_thread_index;
+} vlib_frame_queue_per_thread_data_t;
+
 typedef struct
 {
   u32 node_index;
+  u32 frame_queue_nelts;
+  u32 queue_hi_thresh;
+
   vlib_frame_queue_t **vlib_frame_queues;
+  vlib_frame_queue_per_thread_data_t *per_thread_data;
 
   /* for frame queue tracing */
   frame_queue_trace_t *frame_queue_traces;
index 11b877e..4e635e5 100644 (file)
@@ -49,6 +49,23 @@ typedef struct
   u32 buffer_index;
 } worker_handoff_trace_t;
 
+#define foreach_worker_handoff_error                   \
+  _(CONGESTION_DROP, "congestion drop")
+
+typedef enum
+{
+#define _(sym,str) WORKER_HANDOFF_ERROR_##sym,
+  foreach_worker_handoff_error
+#undef _
+    WORKER_HANDOFF_N_ERROR,
+} worker_handoff_error_t;
+
+static char *worker_handoff_error_strings[] = {
+#define _(sym,string) string,
+  foreach_worker_handoff_error
+#undef _
+};
+
 /* packet trace format function */
 static u8 *
 format_worker_handoff_trace (u8 * s, va_list * args)
@@ -71,7 +88,7 @@ worker_handoff_node_fn (vlib_main_t * vm,
 {
   handoff_main_t *hm = &handoff_main;
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
-  u32 n_left_from, *from;
+  u32 n_enq, n_left_from, *from;
   u16 thread_indices[VLIB_FRAME_SIZE], *ti;
 
   from = vlib_frame_vector_args (frame);
@@ -130,8 +147,13 @@ worker_handoff_node_fn (vlib_main_t * vm,
       b += 1;
     }
 
-  vlib_buffer_enqueue_to_thread (vm, hm->frame_queue_index, from,
-                                thread_indices, frame->n_vectors);
+  n_enq = vlib_buffer_enqueue_to_thread (vm, hm->frame_queue_index, from,
+                                        thread_indices, frame->n_vectors, 1);
+
+  if (n_enq < frame->n_vectors)
+    vlib_node_increment_counter (vm, node->node_index,
+                                WORKER_HANDOFF_ERROR_CONGESTION_DROP,
+                                frame->n_vectors - n_enq);
   return frame->n_vectors;
 }
 
@@ -142,6 +164,8 @@ VLIB_REGISTER_NODE (worker_handoff_node) = {
   .vector_size = sizeof (u32),
   .format_trace = format_worker_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(worker_handoff_error_strings),
+  .error_strings = worker_handoff_error_strings,
 
   .n_next_nodes = 1,
   .next_nodes = {