buffers: configurable buffer fault injector
When configured at compile time via the cmake VPP_BUFFER_FAULT_INJECTOR option, the buffer allocator will appear to fail a certain fraction of the time. By default, the allocator succeeds 80% of the time. Detailed command line configuration options are available, but only when the image has been compiled with cmake option described above: vlib { buffer-alloc-success-rate [0.0 ... 1.0] buffer-alloc-success-seed <nnnn> } Modify vlib_buffer_pool_create(...) so 0 is always an invalid buffer index. Debug images: add checks for bad buffer index enqueues, and also verify that f->n_vectors doesn't accidentally map one or more instances of the frame poison pattern 0xfefefefe. Type: improvement Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: Iab939858014463d1e664682805013d334d6fcbe5
This commit is contained in:

committed by
Florin Coras

parent
c54162981c
commit
c74b43c807
@ -11,9 +11,17 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
option(VPP_BUFFER_FAULT_INJECTOR "Include the buffer fault injector" OFF)
|
||||
|
||||
##############################################################################
|
||||
# Generate vlib/config.h
|
||||
##############################################################################
|
||||
if(VPP_BUFFER_FAULT_INJECTOR)
|
||||
set(BUFFER_ALLOC_FAULT_INJECTOR 1 CACHE STRING "fault injector on")
|
||||
else()
|
||||
set(BUFFER_ALLOC_FAULT_INJECTOR 0 CACHE STRING "fault injector off")
|
||||
endif()
|
||||
|
||||
set(PRE_DATA_SIZE 128 CACHE STRING "Buffer headroom size.")
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/vlib/config.h.in
|
||||
|
@ -578,6 +578,14 @@ vlib_buffer_pool_create (vlib_main_t * vm, char *name, u32 data_size,
|
||||
p = m->base + (j << m->log2_page_size) + i * alloc_size;
|
||||
p += bm->ext_hdr_size;
|
||||
|
||||
/*
|
||||
* Waste 1 buffer (maximum) so that 0 is never a valid buffer index.
|
||||
* Allows various places to ASSERT (bi != 0). Much easier
|
||||
* than debugging downstream crashes in successor nodes.
|
||||
*/
|
||||
if (p == m->base)
|
||||
continue;
|
||||
|
||||
vlib_buffer_copy_template ((vlib_buffer_t *) p, &bp->buffer_template);
|
||||
|
||||
bi = vlib_get_buffer_index (vm, (vlib_buffer_t *) p);
|
||||
@ -923,6 +931,24 @@ vlib_buffers_configure (vlib_main_t * vm, unformat_input_t * input)
|
||||
|
||||
VLIB_EARLY_CONFIG_FUNCTION (vlib_buffers_configure, "buffers");
|
||||
|
||||
#if VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0
|
||||
u32
|
||||
vlib_buffer_alloc_may_fail (vlib_main_t * vm, u32 n_buffers)
|
||||
{
|
||||
f64 r;
|
||||
|
||||
r = random_f64 (&vm->buffer_alloc_success_seed);
|
||||
|
||||
/* Fail this request? */
|
||||
if (r > vm->buffer_alloc_success_rate)
|
||||
n_buffers--;
|
||||
/* 5% chance of returning nothing at all */
|
||||
if (r > vm->buffer_alloc_success_rate && r > 0.95)
|
||||
n_buffers = 0;
|
||||
|
||||
return n_buffers;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
/*
|
||||
|
@ -571,6 +571,17 @@ vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
|
||||
vlib_buffer_pool_thread_t *bpt;
|
||||
u32 *src, *dst, len, n_left;
|
||||
|
||||
/* If buffer allocation fault injection is configured */
|
||||
if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0)
|
||||
{
|
||||
u32 vlib_buffer_alloc_may_fail (vlib_main_t *, u32);
|
||||
|
||||
/* See how many buffers we're willing to allocate */
|
||||
n_buffers = vlib_buffer_alloc_may_fail (vm, n_buffers);
|
||||
if (n_buffers == 0)
|
||||
return (n_buffers);
|
||||
}
|
||||
|
||||
bp = vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
|
||||
bpt = vec_elt_at_index (bp->threads, vm->thread_index);
|
||||
|
||||
|
@ -69,6 +69,8 @@
|
||||
|
||||
#define vlib_validate_buffer_enqueue_x2(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,next0,next1) \
|
||||
do { \
|
||||
ASSERT (bi0 != 0); \
|
||||
ASSERT (bi1 != 0); \
|
||||
int enqueue_code = (next0 != next_index) + 2*(next1 != next_index); \
|
||||
\
|
||||
if (PREDICT_FALSE (enqueue_code != 0)) \
|
||||
@ -137,6 +139,10 @@ do { \
|
||||
|
||||
#define vlib_validate_buffer_enqueue_x4(vm,node,next_index,to_next,n_left_to_next,bi0,bi1,bi2,bi3,next0,next1,next2,next3) \
|
||||
do { \
|
||||
ASSERT (bi0 != 0); \
|
||||
ASSERT (bi1 != 0); \
|
||||
ASSERT (bi2 != 0); \
|
||||
ASSERT (bi3 != 0); \
|
||||
/* After the fact: check the [speculative] enqueue to "next" */ \
|
||||
u32 fix_speculation = (next_index ^ next0) | (next_index ^ next1) \
|
||||
| (next_index ^ next2) | (next_index ^ next3); \
|
||||
@ -217,6 +223,7 @@ do { \
|
||||
*/
|
||||
#define vlib_validate_buffer_enqueue_x1(vm,node,next_index,to_next,n_left_to_next,bi0,next0) \
|
||||
do { \
|
||||
ASSERT (bi0 != 0); \
|
||||
if (PREDICT_FALSE (next0 != next_index)) \
|
||||
{ \
|
||||
vlib_put_next_frame (vm, node, next_index, n_left_to_next + 1); \
|
||||
|
@ -17,5 +17,6 @@
|
||||
#define included_vlib_config_h
|
||||
|
||||
#define __PRE_DATA_SIZE @PRE_DATA_SIZE@
|
||||
#define VLIB_BUFFER_ALLOC_FAULT_INJECTOR @BUFFER_ALLOC_FAULT_INJECTOR@
|
||||
|
||||
#endif
|
||||
|
@ -190,6 +190,31 @@ vlib_get_frame_to_node (vlib_main_t * vm, u32 to_node_index)
|
||||
return vlib_get_frame (vm, f);
|
||||
}
|
||||
|
||||
static inline void
|
||||
vlib_validate_frame_indices (vlib_frame_t * f)
|
||||
{
|
||||
if (CLIB_DEBUG > 0)
|
||||
{
|
||||
int i;
|
||||
u32 *from = vlib_frame_vector_args (f);
|
||||
|
||||
/* Check for bad buffer index values */
|
||||
for (i = 0; i < f->n_vectors; i++)
|
||||
{
|
||||
if (from[i] == 0)
|
||||
{
|
||||
clib_warning ("BUG: buffer index 0 at index %d", i);
|
||||
ASSERT (0);
|
||||
}
|
||||
else if (from[i] == 0xfefefefe)
|
||||
{
|
||||
clib_warning ("BUG: frame poison pattern at index %d", i);
|
||||
ASSERT (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vlib_put_frame_to_node (vlib_main_t * vm, u32 to_node_index, vlib_frame_t * f)
|
||||
{
|
||||
@ -199,6 +224,8 @@ vlib_put_frame_to_node (vlib_main_t * vm, u32 to_node_index, vlib_frame_t * f)
|
||||
if (f->n_vectors == 0)
|
||||
return;
|
||||
|
||||
vlib_validate_frame_indices (f);
|
||||
|
||||
to_node = vlib_get_node (vm, to_node_index);
|
||||
|
||||
vec_add2 (vm->node_main.pending_frames, p, 1);
|
||||
@ -432,6 +459,9 @@ vlib_put_next_frame_validate (vlib_main_t * vm,
|
||||
f = vlib_get_frame (vm, nf->frame);
|
||||
|
||||
ASSERT (n_vectors_left <= VLIB_FRAME_SIZE);
|
||||
|
||||
vlib_validate_frame_indices (f);
|
||||
|
||||
n_after = VLIB_FRAME_SIZE - n_vectors_left;
|
||||
n_before = f->n_vectors;
|
||||
|
||||
@ -1986,6 +2016,20 @@ vlib_main_configure (vlib_main_t * vm, unformat_input_t * input)
|
||||
;
|
||||
else if (unformat (input, "elog-post-mortem-dump"))
|
||||
vm->elog_post_mortem_dump = 1;
|
||||
else if (unformat (input, "buffer-alloc-success-rate %f",
|
||||
&vm->buffer_alloc_success_rate))
|
||||
{
|
||||
if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR == 0)
|
||||
return clib_error_return
|
||||
(0, "Buffer fault injection not configured");
|
||||
}
|
||||
else if (unformat (input, "buffer-alloc-success-seed %u",
|
||||
&vm->buffer_alloc_success_seed))
|
||||
{
|
||||
if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR == 0)
|
||||
return clib_error_return
|
||||
(0, "Buffer fault injection not configured");
|
||||
}
|
||||
else
|
||||
return unformat_parse_error (input);
|
||||
}
|
||||
@ -2147,6 +2191,13 @@ vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
|
||||
vec_validate (vm->processing_rpc_requests, 0);
|
||||
_vec_len (vm->processing_rpc_requests) = 0;
|
||||
|
||||
/* Default params for the buffer allocator fault injector, if configured */
|
||||
if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0)
|
||||
{
|
||||
vm->buffer_alloc_success_seed = 0xdeaddabe;
|
||||
vm->buffer_alloc_success_rate = 0.80;
|
||||
}
|
||||
|
||||
if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))
|
||||
goto done;
|
||||
|
||||
|
@ -276,6 +276,10 @@ typedef struct vlib_main_t
|
||||
uword *processing_rpc_requests;
|
||||
clib_spinlock_t pending_rpc_lock;
|
||||
|
||||
/* buffer fault injector */
|
||||
u32 buffer_alloc_success_seed;
|
||||
f64 buffer_alloc_success_rate;
|
||||
|
||||
} vlib_main_t;
|
||||
|
||||
/* Global main structure. */
|
||||
|
Reference in New Issue
Block a user