summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2020-04-09 17:24:07 -0400
committerFlorin Coras <florin.coras@gmail.com>2020-04-13 15:54:31 +0000
commitc74b43c80789f5e437dfe4cc491157b45a7f222e (patch)
tree0d149b8147d8225b5a872e709c6845476575fd1f
parentc54162981cdd41d65ed283df36955007552ddffe (diff)
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
-rw-r--r--src/vlib/CMakeLists.txt8
-rw-r--r--src/vlib/buffer.c26
-rw-r--r--src/vlib/buffer_funcs.h11
-rw-r--r--src/vlib/buffer_node.h7
-rw-r--r--src/vlib/config.h.in1
-rw-r--r--src/vlib/main.c51
-rw-r--r--src/vlib/main.h4
7 files changed, 108 insertions, 0 deletions
diff --git a/src/vlib/CMakeLists.txt b/src/vlib/CMakeLists.txt
index c2a0d63f4d8..67d1f6d05c7 100644
--- a/src/vlib/CMakeLists.txt
+++ b/src/vlib/CMakeLists.txt
@@ -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
diff --git a/src/vlib/buffer.c b/src/vlib/buffer.c
index 43b1dd63761..f5b813793a3 100644
--- a/src/vlib/buffer.c
+++ b/src/vlib/buffer.c
@@ -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 */
/*
diff --git a/src/vlib/buffer_funcs.h b/src/vlib/buffer_funcs.h
index 98ee2055833..b2076e60de4 100644
--- a/src/vlib/buffer_funcs.h
+++ b/src/vlib/buffer_funcs.h
@@ -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);
diff --git a/src/vlib/buffer_node.h b/src/vlib/buffer_node.h
index bd82b1037a9..0fa18d6dde2 100644
--- a/src/vlib/buffer_node.h
+++ b/src/vlib/buffer_node.h
@@ -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); \
diff --git a/src/vlib/config.h.in b/src/vlib/config.h.in
index a24cb848b82..5b7d5da64e4 100644
--- a/src/vlib/config.h.in
+++ b/src/vlib/config.h.in
@@ -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
diff --git a/src/vlib/main.c b/src/vlib/main.c
index f723d106120..fb3eb108736 100644
--- a/src/vlib/main.c
+++ b/src/vlib/main.c
@@ -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;
diff --git a/src/vlib/main.h b/src/vlib/main.h
index 0e65c817ae1..598c3ba836f 100644
--- a/src/vlib/main.h
+++ b/src/vlib/main.h
@@ -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. */