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>
This commit is contained in:
Damjan Marion
2018-07-20 18:47:05 +02:00
parent 508498f74d
commit 78fd7e810c
4 changed files with 84 additions and 24 deletions

View 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 */

View 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);

View 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;

View 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 = {