bufmon: add buffer monitoring plugin
This plugin allow to keep track of buffer usage in VPP graph nodes. The main use is to detect buffer leakages. Type: feature Change-Id: Iadcf4ab98207fab6e2fa375060879bc2a25b711e Signed-off-by: Benoît Ganne <bganne@cisco.com>
This commit is contained in:
Benoît Ganne
committed by
Damjan Marion
parent
a13100f3aa
commit
e09a2337b8
@ -764,6 +764,11 @@ I: srtp
|
||||
M: Florin Coras <fcoras@cisco.com>
|
||||
F: src/plugins/srtp/
|
||||
|
||||
Plugin - bufmon
|
||||
I: bufmon
|
||||
M: Benoît Ganne <bganne@cisco.com>
|
||||
F: src/plugins/bufmon/
|
||||
|
||||
cJSON
|
||||
I: cjson
|
||||
M: Ole Troan <ot@cisco.com>
|
||||
|
17
src/plugins/bufmon/CMakeLists.txt
Normal file
17
src/plugins/bufmon/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (c) 2020 Cisco and/or its affiliates.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_vpp_plugin(bufmon
|
||||
SOURCES
|
||||
bufmon.c
|
||||
)
|
8
src/plugins/bufmon/FEATURE.yaml
Normal file
8
src/plugins/bufmon/FEATURE.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
name: Buffers monitoring plugin
|
||||
maintainer: Benoît Ganne <bganne@cisco.com>
|
||||
features:
|
||||
- monitor buffer utiization in VPP graph nodes
|
||||
description: "monitor buffer utiization in VPP graph nodes"
|
||||
state: production
|
||||
properties: [CLI, MULTITHREAD]
|
313
src/plugins/bufmon/bufmon.c
Normal file
313
src/plugins/bufmon/bufmon.c
Normal file
File diff suppressed because it is too large
Load Diff
24
src/plugins/bufmon/bufmon_doc.md
Normal file
24
src/plugins/bufmon/bufmon_doc.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Buffers monitoring plugin {#bufmon_doc}
|
||||
|
||||
This plugin enables to track buffer utilization in the VPP graph nodes. The
|
||||
main use is to detect buffer leakage.
|
||||
It works by keeping track of number of buffer allocations and free in graph
|
||||
nodes and also of number of buffers received in input frames and in output
|
||||
frames.
|
||||
The formula to compute the number of "buffered" buffers in a node is simply:
|
||||
#buffered = #alloc + #input - #free - #output
|
||||
Note: monitoring will impact performances.
|
||||
|
||||
## Basic usage
|
||||
1. Turn buffer traces on:
|
||||
```
|
||||
~# vppctl set buffer traces on
|
||||
```
|
||||
2. Monitor buffer usage:
|
||||
```
|
||||
~# vppctl show buffer traces verbose
|
||||
```
|
||||
3. Turn buffer traces off:
|
||||
```
|
||||
~# vppctl set buffer traces off
|
||||
```
|
@ -615,20 +615,26 @@ format_vlib_buffer_pool (u8 * s, va_list * va)
|
||||
return s;
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
show_buffers (vlib_main_t * vm,
|
||||
unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||
u8 *
|
||||
format_vlib_buffer_pool_all (u8 *s, va_list *va)
|
||||
{
|
||||
vlib_main_t *vm = va_arg (*va, vlib_main_t *);
|
||||
vlib_buffer_main_t *bm = vm->buffer_main;
|
||||
vlib_buffer_pool_t *bp;
|
||||
|
||||
vlib_cli_output (vm, "%U", format_vlib_buffer_pool, vm, 0);
|
||||
s = format (s, "%U", format_vlib_buffer_pool, vm, 0);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
vec_foreach (bp, bm->buffer_pools)
|
||||
vlib_cli_output (vm, "%U", format_vlib_buffer_pool, vm, bp);
|
||||
/* *INDENT-ON* */
|
||||
s = format (s, "\n%U", format_vlib_buffer_pool, vm, bp);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
show_buffers (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
vlib_cli_output (vm, "%U", format_vlib_buffer_pool_all, vm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -971,6 +977,20 @@ vlib_buffer_alloc_may_fail (vlib_main_t * vm, u32 n_buffers)
|
||||
}
|
||||
#endif
|
||||
|
||||
__clib_export int
|
||||
vlib_buffer_set_alloc_free_callback (
|
||||
vlib_main_t *vm, vlib_buffer_alloc_free_callback_t *alloc_callback_fn,
|
||||
vlib_buffer_alloc_free_callback_t *free_callback_fn)
|
||||
{
|
||||
vlib_buffer_main_t *bm = vm->buffer_main;
|
||||
if ((alloc_callback_fn && bm->alloc_callback_fn) ||
|
||||
(free_callback_fn && bm->free_callback_fn))
|
||||
return 1;
|
||||
bm->alloc_callback_fn = alloc_callback_fn;
|
||||
bm->free_callback_fn = free_callback_fn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @endcond */
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
|
@ -472,6 +472,10 @@ typedef struct
|
||||
|
||||
#define VLIB_BUFFER_MAX_NUMA_NODES 32
|
||||
|
||||
typedef u32 (vlib_buffer_alloc_free_callback_t) (struct vlib_main_t *vm,
|
||||
u8 buffer_pool_index,
|
||||
u32 *buffers, u32 n_buffers);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
|
||||
@ -481,12 +485,9 @@ typedef struct
|
||||
uword buffer_mem_size;
|
||||
vlib_buffer_pool_t *buffer_pools;
|
||||
|
||||
/* Hash table mapping buffer index into number
|
||||
0 => allocated but free, 1 => allocated and not-free.
|
||||
If buffer index is not in hash table then this buffer
|
||||
has never been allocated. */
|
||||
uword *buffer_known_hash;
|
||||
clib_spinlock_t buffer_known_hash_lockp;
|
||||
vlib_buffer_alloc_free_callback_t *alloc_callback_fn;
|
||||
vlib_buffer_alloc_free_callback_t *free_callback_fn;
|
||||
|
||||
u8 default_buffer_pool_index_for_numa[VLIB_BUFFER_MAX_NUMA_NODES];
|
||||
|
||||
/* config */
|
||||
@ -495,12 +496,25 @@ typedef struct
|
||||
u32 default_data_size;
|
||||
clib_mem_page_sz_t log2_page_size;
|
||||
|
||||
/* Hash table mapping buffer index into number
|
||||
0 => allocated but free, 1 => allocated and not-free.
|
||||
If buffer index is not in hash table then this buffer
|
||||
has never been allocated. */
|
||||
uword *buffer_known_hash;
|
||||
clib_spinlock_t buffer_known_hash_lockp;
|
||||
|
||||
/* logging */
|
||||
vlib_log_class_t log_default;
|
||||
} vlib_buffer_main_t;
|
||||
|
||||
clib_error_t *vlib_buffer_main_init (struct vlib_main_t *vm);
|
||||
|
||||
format_function_t format_vlib_buffer_pool_all;
|
||||
|
||||
int vlib_buffer_set_alloc_free_callback (
|
||||
struct vlib_main_t *vm, vlib_buffer_alloc_free_callback_t *alloc_callback_fn,
|
||||
vlib_buffer_alloc_free_callback_t *free_callback_fn);
|
||||
|
||||
extern u16 __vlib_buffer_external_hdr_size;
|
||||
#define VLIB_BUFFER_SET_EXT_HDR_SIZE(x) \
|
||||
static void __clib_constructor \
|
||||
|
@ -626,11 +626,7 @@ vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
|
||||
src = bpt->cached_buffers + len - n_buffers;
|
||||
vlib_buffer_copy_indices (dst, src, n_buffers);
|
||||
bpt->n_cached -= n_buffers;
|
||||
|
||||
if (CLIB_DEBUG > 0)
|
||||
vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
|
||||
VLIB_BUFFER_KNOWN_FREE);
|
||||
return n_buffers;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* alloc bigger than cache - take buffers directly from main pool */
|
||||
@ -638,11 +634,7 @@ vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
|
||||
{
|
||||
n_buffers = vlib_buffer_pool_get (vm, buffer_pool_index, buffers,
|
||||
n_buffers);
|
||||
|
||||
if (CLIB_DEBUG > 0)
|
||||
vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
|
||||
VLIB_BUFFER_KNOWN_FREE);
|
||||
return n_buffers;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* take everything available in the cache */
|
||||
@ -670,11 +662,13 @@ vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
|
||||
|
||||
n_buffers -= n_left;
|
||||
|
||||
done:
|
||||
/* Verify that buffers are known free. */
|
||||
if (CLIB_DEBUG > 0)
|
||||
vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
|
||||
VLIB_BUFFER_KNOWN_FREE);
|
||||
|
||||
if (PREDICT_FALSE (bm->alloc_callback_fn != 0))
|
||||
bm->alloc_callback_fn (vm, buffer_pool_index, buffers, n_buffers);
|
||||
return n_buffers;
|
||||
}
|
||||
|
||||
@ -776,6 +770,7 @@ static_always_inline void
|
||||
vlib_buffer_pool_put (vlib_main_t * vm, u8 buffer_pool_index,
|
||||
u32 * buffers, u32 n_buffers)
|
||||
{
|
||||
vlib_buffer_main_t *bm = vm->buffer_main;
|
||||
vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
|
||||
vlib_buffer_pool_thread_t *bpt = vec_elt_at_index (bp->threads,
|
||||
vm->thread_index);
|
||||
@ -784,6 +779,8 @@ vlib_buffer_pool_put (vlib_main_t * vm, u8 buffer_pool_index,
|
||||
if (CLIB_DEBUG > 0)
|
||||
vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
|
||||
VLIB_BUFFER_KNOWN_ALLOCATED);
|
||||
if (PREDICT_FALSE (bm->free_callback_fn != 0))
|
||||
bm->free_callback_fn (vm, buffer_pool_index, buffers, n_buffers);
|
||||
|
||||
n_cached = bpt->n_cached;
|
||||
n_empty = VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ - n_cached;
|
||||
|
Reference in New Issue
Block a user