aboutsummaryrefslogtreecommitdiffstats
path: root/src/vlib
diff options
context:
space:
mode:
authorDamjan Marion <damarion@cisco.com>2018-07-20 18:47:05 +0200
committerDamjan Marion <damarion@cisco.com>2018-07-20 19:43:36 +0200
commit78fd7e810c24b9d638ac7c7f08edabf692543743 (patch)
treec676d0f4bc9a7471fd5c60cb02fb995868fa65d6 /src/vlib
parent508498f74d2df98e70a961d030cf0128a63a926d (diff)
Add congestion drop in interface handoff
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>
Diffstat (limited to 'src/vlib')
-rw-r--r--src/vlib/buffer_node.h53
-rw-r--r--src/vlib/threads.c15
-rw-r--r--src/vlib/threads.h10
3 files changed, 57 insertions, 21 deletions
diff --git a/src/vlib/buffer_node.h b/src/vlib/buffer_node.h
index cfdb0567a0c..93ffb1e9dce 100644
--- a/src/vlib/buffer_node.h
+++ b/src/vlib/buffer_node.h
@@ -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 */
diff --git a/src/vlib/threads.c b/src/vlib/threads.c
index c53c5d6c170..70f22b10fa1 100644
--- a/src/vlib/threads.c
+++ b/src/vlib/threads.c
@@ -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);
diff --git a/src/vlib/threads.h b/src/vlib/threads.h
index f78ec1b9fa5..b47a633c2cc 100644
--- a/src/vlib/threads.h
+++ b/src/vlib/threads.h
@@ -163,8 +163,18 @@ 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;