# 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
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);
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 */
/*
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);
#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)) \
#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); \
*/
#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); \
#define included_vlib_config_h
#define __PRE_DATA_SIZE @PRE_DATA_SIZE@
+#define VLIB_BUFFER_ALLOC_FAULT_INJECTOR @BUFFER_ALLOC_FAULT_INJECTOR@
#endif
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)
{
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);
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;
;
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);
}
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;
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. */