From 6c3ebcc2bfd36a5835a99225ad667e4403293ffb Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Sun, 2 Oct 2016 21:20:15 +0100 Subject: [PATCH] FIB Memory Usage Diagnostics add two new CLI commands: show fib memory show dpo memory to display the memory usage of the FIB and DPO object types respectively. Change-Id: I759e149a0b6fbb58d59c139362221dc33531cffa Signed-off-by: Neale Ranns --- vnet/Makefile.am | 1 - vnet/vnet/adj/adj.c | 50 +++------ vnet/vnet/adj/adj.h | 6 +- vnet/vnet/adj/adj_alloc.c | 236 ----------------------------------------- vnet/vnet/adj/adj_alloc.h | 53 --------- vnet/vnet/adj/adj_glean.c | 11 +- vnet/vnet/adj/adj_internal.h | 20 +++- vnet/vnet/adj/adj_midchain.c | 2 +- vnet/vnet/adj/adj_nbr.c | 22 ++-- vnet/vnet/adj/adj_rewrite.c | 5 +- vnet/vnet/dpo/classify_dpo.c | 10 ++ vnet/vnet/dpo/dpo.c | 44 ++++++++ vnet/vnet/dpo/dpo.h | 19 +++- vnet/vnet/dpo/load_balance.c | 11 +- vnet/vnet/dpo/lookup_dpo.c | 17 ++- vnet/vnet/dpo/mpls_label_dpo.c | 10 ++ vnet/vnet/dpo/receive_dpo.c | 10 ++ vnet/vnet/fib/fib_entry.c | 37 +++++-- vnet/vnet/fib/fib_entry.h | 14 +-- vnet/vnet/fib/fib_node.c | 59 +++++++++++ vnet/vnet/fib/fib_node.h | 23 ++++ vnet/vnet/fib/fib_node_list.c | 23 ++-- vnet/vnet/fib/fib_node_list.h | 3 + vnet/vnet/fib/fib_path.c | 10 ++ vnet/vnet/fib/fib_path_list.c | 13 +++ vnet/vnet/ip/lookup.c | 7 +- vnet/vnet/ip/lookup.h | 4 - 27 files changed, 333 insertions(+), 387 deletions(-) delete mode 100644 vnet/vnet/adj/adj_alloc.c delete mode 100644 vnet/vnet/adj/adj_alloc.h diff --git a/vnet/Makefile.am b/vnet/Makefile.am index 6aa4254f2af..1b7b96911f9 100644 --- a/vnet/Makefile.am +++ b/vnet/Makefile.am @@ -777,7 +777,6 @@ nobase_include_HEADERS += \ ######################################## libvnet_la_SOURCES += \ - vnet/adj/adj_alloc.c \ vnet/adj/adj_nbr.c \ vnet/adj/adj_rewrite.c \ vnet/adj/adj_glean.c \ diff --git a/vnet/vnet/adj/adj.c b/vnet/vnet/adj/adj.c index b552fdb2bbc..8f9d96efd60 100644 --- a/vnet/vnet/adj/adj.c +++ b/vnet/vnet/adj/adj.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include @@ -30,16 +29,17 @@ static ip_adjacency_t *special_v4_miss_adj_with_index_zero; /* Adjacency packet/byte counters indexed by adjacency index. */ vlib_combined_counter_main_t adjacency_counters; +/* + * the single adj pool + */ +ip_adjacency_t *adj_pool; + always_inline void adj_poison (ip_adjacency_t * adj) { if (CLIB_DEBUG > 0) { - u32 save_handle = adj->heap_handle;; - memset (adj, 0xfe, sizeof (adj[0])); - - adj->heap_handle = save_handle; } } @@ -48,14 +48,14 @@ adj_alloc (fib_protocol_t proto) { ip_adjacency_t *adj; - adj = aa_alloc(); + pool_get(adj_pool, adj); adj_poison(adj); /* Make sure certain fields are always initialized. */ /* Validate adjacency counters. */ vlib_validate_combined_counter(&adjacency_counters, - adj->heap_handle); + adj_get_index(adj)); adj->rewrite_header.sw_if_index = ~0; adj->mcast_group_index = ~0; @@ -66,6 +66,9 @@ adj_alloc (fib_protocol_t proto) FIB_NODE_TYPE_ADJ); adj->ia_nh_proto = proto; + ip4_main.lookup_main.adjacency_heap = adj_pool; + ip6_main.lookup_main.adjacency_heap = adj_pool; + return (adj); } @@ -166,7 +169,7 @@ adj_last_lock_gone (ip_adjacency_t *adj) } fib_node_deinit(&adj->ia_node); - aa_free(adj); + pool_put(adj_pool, adj); } void @@ -181,7 +184,6 @@ adj_lock (adj_index_t adj_index) adj = adj_get(adj_index); ASSERT(adj); - ASSERT(adj->heap_handle!=0); ADJ_DBG(adj, "lock"); fib_node_lock(&adj->ia_node); @@ -199,11 +201,9 @@ adj_unlock (adj_index_t adj_index) adj = adj_get(adj_index); ASSERT(adj); - ASSERT(adj->heap_handle!=0); ADJ_DBG(adj, "unlock"); ASSERT(adj); - ASSERT(adj->heap_handle!=0); fib_node_unlock(&adj->ia_node); } @@ -291,7 +291,6 @@ adj_module_init (vlib_main_t * vm) /* * 4 special adjs for v4 and v6 resp. */ - aa_bootstrap(8); special_v4_miss_adj_with_index_zero = adj_alloc(FIB_PROTOCOL_IP4); return (NULL); @@ -311,33 +310,14 @@ ip_add_adjacency (ip_lookup_main_t * lm, u32 * adj_index_return) { ip_adjacency_t * adj; - u32 ai, i, handle; ASSERT(1==n_adj); - adj = aa_alloc (); - handle = ai = adj->heap_handle; + adj = adj_alloc(FIB_PROTOCOL_IP4); - /* Validate adjacency counters. */ - vlib_validate_combined_counter (&adjacency_counters, ai + n_adj - 1); - - for (i = 0; i < n_adj; i++) - { - /* Make sure certain fields are always initialized. */ - adj[i].rewrite_header.sw_if_index = ~0; - adj[i].mcast_group_index = ~0; - adj[i].saved_lookup_next_index = 0; - - if (copy_adj) - adj[i] = copy_adj[i]; - - adj[i].heap_handle = handle; - adj[i].n_adj = n_adj; - - /* Zero possibly stale counters for re-used adjacencies. */ - vlib_zero_combined_counter (&adjacency_counters, ai + i); - } + if (copy_adj) + *adj = *copy_adj; - *adj_index_return = ai; + *adj_index_return = adj_get_index(adj); return adj; } diff --git a/vnet/vnet/adj/adj.h b/vnet/vnet/adj/adj.h index 3a1236497e1..002dab359ab 100644 --- a/vnet/vnet/adj/adj.h +++ b/vnet/vnet/adj/adj.h @@ -77,9 +77,9 @@ extern void adj_child_remove(adj_index_t adj_index, /** * @brief - * The global adjacnecy heap. Exposed for fast/inline data-plane access + * The global adjacnecy pool. Exposed for fast/inline data-plane access */ -extern ip_adjacency_t *adj_heap; +extern ip_adjacency_t *adj_pool; /** * @brief @@ -94,7 +94,7 @@ extern vlib_combined_counter_main_t adjacency_counters; static inline ip_adjacency_t * adj_get (adj_index_t adj_index) { - return (vec_elt_at_index(adj_heap, adj_index)); + return (vec_elt_at_index(adj_pool, adj_index)); } #endif diff --git a/vnet/vnet/adj/adj_alloc.c b/vnet/vnet/adj/adj_alloc.c deleted file mode 100644 index 5cc8cf6ef04..00000000000 --- a/vnet/vnet/adj/adj_alloc.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2016 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. - */ - -#include -#include - -/* - * the single adj heap - */ -ip_adjacency_t *adj_heap; - -/* - * any operation which could cause the adj vector to be reallocated - * must have a worker thread barrier - */ -static inline int will_reallocate (ip_adjacency_t * adjs, u32 n) -{ - uword aligned_header_bytes, new_data_bytes; - uword data_bytes; - aa_header_t * ah = aa_header (adjs); - - if (adjs == 0) - return 1; - - data_bytes = (vec_len (adjs) + n) * sizeof (*adjs); - - aligned_header_bytes = vec_header_bytes (aa_aligned_header_bytes); - - new_data_bytes = data_bytes + aligned_header_bytes; - - ASSERT (clib_mem_is_heap_object (_vec_find(ah))); - - if (PREDICT_TRUE(new_data_bytes <= clib_mem_size (_vec_find(ah)))) - return 0; - - return 1; -} - -ip_adjacency_t * -aa_alloc (void) -{ - vlib_main_t * vm = &vlib_global_main; - aa_header_t * ah = aa_header (adj_heap); - ip_adjacency_t * adj_block; - u32 freelist_length; - int need_barrier_sync = 0; - u32 n = 1; - - ASSERT(os_get_cpu_number() == 0); - ASSERT (clib_mem_is_heap_object (_vec_find(ah))); - - /* If we don't have a freelist of size N, fresh allocation is required */ - if (vec_len (ah->free_indices_by_size) <= n) - { - if (will_reallocate (adj_heap, n)) - { - need_barrier_sync = 1; - vlib_worker_thread_barrier_sync (vm); - } - /* Workers wont look at the freelists... */ - vec_validate (ah->free_indices_by_size, n); - vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes, - CLIB_CACHE_LINE_BYTES); - if (need_barrier_sync) - vlib_worker_thread_barrier_release (vm); - goto out; - } - /* See if we have a free adj block to dole out */ - if ((freelist_length = vec_len(ah->free_indices_by_size[n]))) - { - u32 index = ah->free_indices_by_size[n][freelist_length-1]; - - adj_block = &adj_heap[index]; - _vec_len(ah->free_indices_by_size[n]) -= 1; - goto out; - } - /* Allocate a new block of size N */ - if (will_reallocate (adj_heap, n)) - { - need_barrier_sync = 1; - vlib_worker_thread_barrier_sync (vm); - } - vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes, - CLIB_CACHE_LINE_BYTES); - - if (need_barrier_sync) - vlib_worker_thread_barrier_release (vm); - - out: - memset (adj_block, 0, n * (sizeof(*adj_block))); - adj_block->heap_handle = adj_block - adj_heap; - adj_block->n_adj = n; - - /* - * the adj heap may have realloc'd. recache. - */ - ip4_main.lookup_main.adjacency_heap = adj_heap; - ip6_main.lookup_main.adjacency_heap = adj_heap; - - return (adj_block); -} - -void aa_free (ip_adjacency_t * adj) -{ - aa_header_t * ah = aa_header (adj_heap); - - ASSERT (adj_heap && adj && (adj->heap_handle < vec_len (adj_heap))); - ASSERT (adj->heap_handle != 0); - - vec_add1 (ah->free_indices_by_size[adj->n_adj], adj->heap_handle); - adj->heap_handle = 0; -} - -void aa_bootstrap (u32 n) -{ - ip_adjacency_t * adj_block; - aa_header_t * ah; - int i; - - vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes, - CLIB_CACHE_LINE_BYTES); - - memset (adj_block, 0, n * sizeof(*adj_block)); - ah = aa_header (adj_heap); - memset (ah, 0, sizeof (*ah)); - - vec_validate (ah->free_indices_by_size, 1); - - for (i = 0 ; i < vec_len (adj_heap); i++) - { - adj_block->n_adj = 1; - adj_block->heap_handle = ~0; - /* Euchre the allocator into returning 0, 1, 2, etc. */ - vec_add1 (ah->free_indices_by_size[1], n - (i+1)); - } - - ip4_main.lookup_main.adjacency_heap = adj_heap; - ip6_main.lookup_main.adjacency_heap = adj_heap; -} - -u8 * format_adjacency_alloc (u8 * s, va_list * args) -{ - vnet_main_t * vnm = va_arg (*args, vnet_main_t *); - int verbose = va_arg (*args, int); - ip_adjacency_t * adj; - u32 inuse = 0, freed = 0; - u32 on_freelist = 0; - int i, j; - aa_header_t * ah = aa_header (adj_heap); - - for (i = 0; i < vec_len (adj_heap); i += adj->n_adj) - { - adj = adj_heap + i; - if ((i == 0) || adj->heap_handle) - inuse += adj->n_adj; - else - freed += adj->n_adj; - } - - for (i = 1; i < vec_len(ah->free_indices_by_size); i++) - { - for (j = 0; j < vec_len(ah->free_indices_by_size[i]); j++) - { - adj = adj_heap + ah->free_indices_by_size[i][j]; - ASSERT(adj->heap_handle == 0); - on_freelist += adj->n_adj; - } - } - - s = format (s, "adj_heap: %d total, %d in use, %d free, %d on freelists\n", - vec_len(adj_heap), inuse, freed, on_freelist); - if (verbose) - { - for (i = 0; i < vec_len (adj_heap); i += adj->n_adj) - { - adj = adj_heap + i; - if ((i == 0) || adj->heap_handle) - { - if (adj->n_adj > 1) - s = format (s, "[%d-%d] ", i, i+adj->n_adj-1); - else - s = format (s, "[%d] ", i); - - for (j = 0; j < adj->n_adj; j++) - { - if (j > 0) - s = format (s, " "); - - s = format(s, "%U\n", format_ip_adjacency, - vnm, i+j, FORMAT_IP_ADJACENCY_NONE); - } - } - } - } - return s; -} - -static clib_error_t * -show_adjacency_alloc_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - int verbose = 0; - vnet_main_t *vnm = vnet_get_main(); - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "verbose")) - verbose = 1; - else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); - } - - vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, verbose); - - return 0; -} - -VLIB_CLI_COMMAND (show_adjacency_alloc_command, static) = { - .path = "show adjacency alloc", - .short_help = "show adjacency alloc", - .function = show_adjacency_alloc_command_fn, -}; diff --git a/vnet/vnet/adj/adj_alloc.h b/vnet/vnet/adj/adj_alloc.h deleted file mode 100644 index 7d1a3fb3133..00000000000 --- a/vnet/vnet/adj/adj_alloc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2016 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. - */ - -#ifndef __adj_alloc_h__ -#define __adj_alloc_h__ - -/** - * @brief - * Adjacency allocator: heap-like in that the code - * will dole out contiguous chunks of n items. In the interests of - * thread safety, we don't bother about coalescing free blocks of size r - * into free blocks of size s, where r < s. - * - * We include explicit references to worker thread barrier synchronization - * where necessary. - */ - -#include -#include -#include - -typedef struct { - u32 ** free_indices_by_size; -} aa_header_t; - -#define aa_aligned_header_bytes \ - vec_aligned_header_bytes (sizeof (aa_header_t), sizeof (void *)) - -/* Pool header from user pointer */ -static inline aa_header_t * aa_header (void * v) -{ - return vec_aligned_header (v, sizeof (aa_header_t), sizeof (void *)); -} - -extern ip_adjacency_t *aa_alloc(void); -extern void aa_free (ip_adjacency_t * adj); -extern void aa_bootstrap (u32 n); - -format_function_t format_adj_allocation; - -#endif /* __adj_alloc_h__ */ diff --git a/vnet/vnet/adj/adj_glean.c b/vnet/vnet/adj/adj_glean.c index 6eb6718e216..f5d181018b6 100644 --- a/vnet/vnet/adj/adj_glean.c +++ b/vnet/vnet/adj/adj_glean.c @@ -14,7 +14,6 @@ */ #include -#include #include #include @@ -62,7 +61,7 @@ adj_glean_add_or_lock (fib_protocol_t proto, adj->lookup_next_index = IP_LOOKUP_NEXT_GLEAN; adj->ia_nh_proto = proto; - adj_gleans[proto][sw_if_index] = adj->heap_handle; + adj_gleans[proto][sw_if_index] = adj_get_index(adj); if (NULL != nh_addr) { @@ -84,9 +83,9 @@ adj_glean_add_or_lock (fib_protocol_t proto, adj = adj_get(adj_gleans[proto][sw_if_index]); } - adj_lock(adj->heap_handle); + adj_lock(adj_get_index(adj)); - return (adj->heap_handle); + return (adj_get_index(adj)); } void @@ -124,7 +123,7 @@ adj_glean_interface_state_change (vnet_main_t * vnm, FIB_NODE_BW_REASON_FLAG_INTERFACE_DOWN), }; - fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx); + fib_walk_sync(FIB_NODE_TYPE_ADJ, adj_get_index(adj), &bw_ctx); } return (NULL); @@ -173,7 +172,7 @@ adj_glean_interface_delete (vnet_main_t * vnm, .fnbw_reason = FIB_NODE_BW_REASON_FLAG_INTERFACE_DELETE, }; - fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx); + fib_walk_sync(FIB_NODE_TYPE_ADJ, adj_get_index(adj), &bw_ctx); } return (NULL); diff --git a/vnet/vnet/adj/adj_internal.h b/vnet/vnet/adj/adj_internal.h index f2d0ce0dbb2..25a477ad007 100644 --- a/vnet/vnet/adj/adj_internal.h +++ b/vnet/vnet/adj/adj_internal.h @@ -31,11 +31,11 @@ * Debug macro */ #ifdef ADJ_DEBUG -#define ADJ_DBG(_adj, _fmt, _args...) \ -{ \ - clib_warning("adj:[%d:%p]:" _fmt, \ - _adj->heap_handle, _adj, \ - ##_args); \ +#define ADJ_DBG(_adj, _fmt, _args...) \ +{ \ + clib_warning("adj:[%d:%p]:" _fmt, \ + _adj - adj_pool, _adj, \ + ##_args); \ } #else #define ADJ_DBG(_e, _fmt, _args...) @@ -90,6 +90,16 @@ adj_fib_proto_2_nd (fib_protocol_t fp) return (0); } +/** + * @brief + * Get a pointer to an adjacency object from its index + */ +static inline adj_index_t +adj_get_index (ip_adjacency_t *adj) +{ + return (adj - adj_pool); +} + extern ip_adjacency_t * adj_alloc(fib_protocol_t proto); extern void adj_nbr_remove(fib_protocol_t nh_proto, diff --git a/vnet/vnet/adj/adj_midchain.c b/vnet/vnet/adj/adj_midchain.c index 562a90d6e1d..c40d4e8bca5 100644 --- a/vnet/vnet/adj/adj_midchain.c +++ b/vnet/vnet/adj/adj_midchain.c @@ -405,7 +405,7 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index, .fnbw_reason = FIB_NODE_BW_REASON_ADJ_UPDATE, }; - fib_walk_sync(FIB_NODE_TYPE_ADJ, adj->heap_handle, &bw_ctx); + fib_walk_sync(FIB_NODE_TYPE_ADJ, adj_get_index(adj), &bw_ctx); } /** diff --git a/vnet/vnet/adj/adj_nbr.c b/vnet/vnet/adj/adj_nbr.c index 0913cfd791c..23e40a6850c 100644 --- a/vnet/vnet/adj/adj_nbr.c +++ b/vnet/vnet/adj/adj_nbr.c @@ -275,7 +275,7 @@ adj_nbr_alloc (fib_protocol_t nh_proto, adj_nbr_insert(nh_proto, link_type, nh_addr, sw_if_index, - adj->heap_handle); + adj_get_index(adj)); /* * since we just added the ADJ we have no rewrite string for it, @@ -362,9 +362,9 @@ adj_nbr_add_or_lock (fib_protocol_t nh_proto, adj = adj_get(adj_index); } - adj_lock(adj->heap_handle); + adj_lock(adj_get_index(adj)); - return (adj->heap_handle); + return (adj_get_index(adj)); } adj_index_t @@ -389,10 +389,10 @@ adj_nbr_add_or_lock_w_rewrite (fib_protocol_t nh_proto, adj = adj_get(adj_index); } - adj_lock(adj->heap_handle); - adj_nbr_update_rewrite(adj->heap_handle, rewrite); + adj_lock(adj_get_index(adj)); + adj_nbr_update_rewrite(adj_get_index(adj), rewrite); - return (adj->heap_handle); + return (adj_get_index(adj)); } /** @@ -760,10 +760,20 @@ adj_dpo_unlock (dpo_id_t *dpo) adj_unlock(dpo->dpoi_index); } +static void +adj_mem_show (void) +{ + fib_show_memory_usage("Adjacency", + pool_elts(adj_pool), + pool_len(adj_pool), + sizeof(ip_adjacency_t)); +} + const static dpo_vft_t adj_nbr_dpo_vft = { .dv_lock = adj_dpo_lock, .dv_unlock = adj_dpo_unlock, .dv_format = format_adj_nbr, + .dv_mem_show = adj_mem_show, }; const static dpo_vft_t adj_nbr_incompl_dpo_vft = { .dv_lock = adj_dpo_lock, diff --git a/vnet/vnet/adj/adj_rewrite.c b/vnet/vnet/adj/adj_rewrite.c index db802e33665..eb93f6a4377 100644 --- a/vnet/vnet/adj/adj_rewrite.c +++ b/vnet/vnet/adj/adj_rewrite.c @@ -14,7 +14,6 @@ */ #include -#include #include /** @@ -46,7 +45,7 @@ adj_rewrite_add_and_lock (fib_protocol_t nh_proto, &adj->rewrite_header, sizeof (adj->rewrite_data)); - adj_lock(adj->heap_handle); + adj_lock(adj_get_index(adj)); - return (adj->heap_handle); + return (adj_get_index(adj)); } diff --git a/vnet/vnet/dpo/classify_dpo.c b/vnet/vnet/dpo/classify_dpo.c index 3b7b98f9da8..93f3f0ae275 100644 --- a/vnet/vnet/dpo/classify_dpo.c +++ b/vnet/vnet/dpo/classify_dpo.c @@ -90,10 +90,20 @@ classify_dpo_unlock (dpo_id_t *dpo) } } +static void +classify_dpo_mem_show (void) +{ + fib_show_memory_usage("Classify", + pool_elts(classify_dpo_pool), + pool_len(classify_dpo_pool), + sizeof(classify_dpo_t)); +} + const static dpo_vft_t cd_vft = { .dv_lock = classify_dpo_lock, .dv_unlock = classify_dpo_unlock, .dv_format = format_classify_dpo, + .dv_mem_show = classify_dpo_mem_show, }; const static char* const classify_ip4_nodes[] = diff --git a/vnet/vnet/dpo/dpo.c b/vnet/vnet/dpo/dpo.c index 5eff52b7b8a..9f09dff81d1 100644 --- a/vnet/vnet/dpo/dpo.c +++ b/vnet/vnet/dpo/dpo.c @@ -422,3 +422,47 @@ dpo_module_init (vlib_main_t * vm) } VLIB_INIT_FUNCTION(dpo_module_init); + +static clib_error_t * +dpo_memory_show (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + dpo_vft_t *vft; + + vlib_cli_output (vm, "DPO memory"); + vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s totals", + "Name","Size", "in-use", "allocated"); + + vec_foreach(vft, dpo_vfts) + { + if (NULL != vft->dv_mem_show) + vft->dv_mem_show(); + } + + return (NULL); +} + +/* *INDENT-OFF* */ +/*? + * The 'sh dpo memory ' command displays the memory usage for each + * data-plane object type. + * + * @cliexpar + * @cliexstart{show dpo memory} + * DPO memory + * Name Size in-use /allocated totals + * load-balance 64 12 / 12 768/768 + * Adjacency 256 1 / 1 256/256 + * Receive 24 5 / 5 120/120 + * Lookup 12 0 / 0 0/0 + * Classify 12 0 / 0 0/0 + * MPLS label 24 0 / 0 0/0 + * @cliexend +?*/ +VLIB_CLI_COMMAND (show_fib_memory, static) = { + .path = "show dpo memory", + .function = dpo_memory_show, + .short_help = "show dpo memory", +}; +/* *INDENT-ON* */ diff --git a/vnet/vnet/dpo/dpo.h b/vnet/vnet/dpo/dpo.h index 452a07e3104..7ba47569d8d 100644 --- a/vnet/vnet/dpo/dpo.h +++ b/vnet/vnet/dpo/dpo.h @@ -300,6 +300,11 @@ typedef void (*dpo_lock_fn_t)(dpo_id_t *dpo); */ typedef void (*dpo_unlock_fn_t)(dpo_id_t *dpo); +/** + * @brief An memory usage show command + */ +typedef void (*dpo_mem_show_t)(void); + /** * @brief A virtual function table regisitered for a DPO type */ @@ -317,6 +322,10 @@ typedef struct dpo_vft_t_ * A format function */ format_function_t *dv_format; + /** + * A show memory usage function + */ + dpo_mem_show_t dv_mem_show; } dpo_vft_t; @@ -337,9 +346,9 @@ typedef struct dpo_vft_t_ * @param nodes * The string description of the per-protocol VLIB graph nodes. */ -void dpo_register(dpo_type_t type, - const dpo_vft_t *vft, - const char * const * const * nodes); +extern void dpo_register(dpo_type_t type, + const dpo_vft_t *vft, + const char * const * const * nodes); /** * @brief Create and register a new DPO type. @@ -355,7 +364,7 @@ void dpo_register(dpo_type_t type, * * @return The new dpo_type_t */ -dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, - const char * const * const * nodes); +extern dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, + const char * const * const * nodes); #endif diff --git a/vnet/vnet/dpo/load_balance.c b/vnet/vnet/dpo/load_balance.c index 1250694a9e3..093661d8578 100644 --- a/vnet/vnet/dpo/load_balance.c +++ b/vnet/vnet/dpo/load_balance.c @@ -19,7 +19,6 @@ #include #include /* for fabs */ #include -#include #include /* @@ -671,10 +670,20 @@ load_balance_unlock (dpo_id_t *dpo) } } +static void +load_balance_mem_show (void) +{ + fib_show_memory_usage("load-balance", + pool_elts(load_balance_pool), + pool_len(load_balance_pool), + sizeof(load_balance_t)); +} + const static dpo_vft_t lb_vft = { .dv_lock = load_balance_lock, .dv_unlock = load_balance_unlock, .dv_format = format_load_balance_dpo, + .dv_mem_show = load_balance_mem_show, }; /** diff --git a/vnet/vnet/dpo/lookup_dpo.c b/vnet/vnet/dpo/lookup_dpo.c index 6e3f0792d07..f775417287c 100644 --- a/vnet/vnet/dpo/lookup_dpo.c +++ b/vnet/vnet/dpo/lookup_dpo.c @@ -734,11 +734,26 @@ VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = { }; VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_itf_node, lookup_mpls_dst_itf) +static void +lookup_dpo_mem_show (void) +{ + fib_show_memory_usage("Lookup", + pool_elts(lookup_dpo_pool), + pool_len(lookup_dpo_pool), + sizeof(lookup_dpo_t)); +} + const static dpo_vft_t lkd_vft = { .dv_lock = lookup_dpo_lock, .dv_unlock = lookup_dpo_unlock, .dv_format = format_lookup_dpo, }; +const static dpo_vft_t lkd_vft_w_mem_show = { + .dv_lock = lookup_dpo_lock, + .dv_unlock = lookup_dpo_unlock, + .dv_format = format_lookup_dpo, + .dv_mem_show = lookup_dpo_mem_show, +}; const static char* const lookup_src_ip4_nodes[] = { @@ -805,7 +820,7 @@ const static char* const * const lookup_dst_from_interface_nodes[DPO_PROTO_NUM] void lookup_dpo_module_init (void) { - dpo_register(DPO_LOOKUP, &lkd_vft, NULL); + dpo_register(DPO_LOOKUP, &lkd_vft_w_mem_show, NULL); /* * There are various sorts of lookup; src or dst addr v4 /v6 etc. diff --git a/vnet/vnet/dpo/mpls_label_dpo.c b/vnet/vnet/dpo/mpls_label_dpo.c index 0ec840ecfbd..532d0447db6 100644 --- a/vnet/vnet/dpo/mpls_label_dpo.c +++ b/vnet/vnet/dpo/mpls_label_dpo.c @@ -227,10 +227,20 @@ VLIB_REGISTER_NODE (mpls_label_imposition_node) = { }; VLIB_NODE_FUNCTION_MULTIARCH (mpls_label_imposition_node, mpls_label_imposition) +static void +mpls_label_dpo_mem_show (void) +{ + fib_show_memory_usage("MPLS label", + pool_elts(mpls_label_dpo_pool), + pool_len(mpls_label_dpo_pool), + sizeof(mpls_label_dpo_t)); +} + const static dpo_vft_t mld_vft = { .dv_lock = mpls_label_dpo_lock, .dv_unlock = mpls_label_dpo_unlock, .dv_format = format_mpls_label_dpo, + .dv_mem_show = mpls_label_dpo_mem_show, }; const static char* const mpls_label_imp_ip4_nodes[] = diff --git a/vnet/vnet/dpo/receive_dpo.c b/vnet/vnet/dpo/receive_dpo.c index ee7d82b0980..ad78850daf3 100644 --- a/vnet/vnet/dpo/receive_dpo.c +++ b/vnet/vnet/dpo/receive_dpo.c @@ -117,10 +117,20 @@ format_receive_dpo (u8 *s, va_list *ap) } } +static void +receive_dpo_mem_show (void) +{ + fib_show_memory_usage("Receive", + pool_elts(receive_dpo_pool), + pool_len(receive_dpo_pool), + sizeof(receive_dpo_t)); +} + const static dpo_vft_t receive_vft = { .dv_lock = receive_dpo_lock, .dv_unlock = receive_dpo_unlock, .dv_format = format_receive_dpo, + .dv_mem_show = receive_dpo_mem_show, }; /** diff --git a/vnet/vnet/fib/fib_entry.c b/vnet/vnet/fib/fib_entry.c index a75d5c9cf8c..1821319dbf7 100644 --- a/vnet/vnet/fib/fib_entry.c +++ b/vnet/vnet/fib/fib_entry.c @@ -435,6 +435,34 @@ fib_entry_back_walk_notify (fib_node_t *node, return (FIB_NODE_BACK_WALK_CONTINUE); } +static void +fib_entry_show_memory (void) +{ + u32 n_srcs = 0, n_exts = 0; + fib_entry_src_t *esrc; + fib_entry_t *entry; + + fib_show_memory_usage("Entry", + pool_elts(fib_entry_pool), + pool_len(fib_entry_pool), + sizeof(fib_entry_t)); + + pool_foreach(entry, fib_entry_pool, + ({ + n_srcs += vec_len(entry->fe_srcs); + vec_foreach(esrc, entry->fe_srcs) + { + n_exts += vec_len(esrc->fes_path_exts); + } + })); + + fib_show_memory_usage("Entry Source", + n_srcs, n_srcs, sizeof(fib_entry_src_t)); + fib_show_memory_usage("Entry Path-Extensions", + n_exts, n_exts, + sizeof(fib_path_ext_t)); +} + /* * The FIB path-list's graph node virtual function table */ @@ -442,6 +470,7 @@ static const fib_node_vft_t fib_entry_vft = { .fnv_get = fib_entry_get_node, .fnv_last_lock = fib_entry_last_lock_gone, .fnv_back_walk = fib_entry_back_walk_notify, + .fnv_mem_show = fib_entry_show_memory, }; /* @@ -516,14 +545,6 @@ fib_entry_get_path_list (fib_node_index_t fib_entry_index) return (fib_entry->fe_parent); } -u32 -fib_entry_get_fib_table_id(fib_node_index_t fib_entry_index) -{ - - - return (0); -} - u32 fib_entry_child_add (fib_node_index_t fib_entry_index, fib_node_type_t child_type, diff --git a/vnet/vnet/fib/fib_entry.h b/vnet/vnet/fib/fib_entry.h index 1ed9d619515..1016bb21948 100644 --- a/vnet/vnet/fib/fib_entry.h +++ b/vnet/vnet/fib/fib_entry.h @@ -261,6 +261,11 @@ _Static_assert (sizeof(fib_entry_src_flag_t) <= 2, * Information related to the source of a FIB entry */ typedef struct fib_entry_src_t_ { + /** + * A vector of path extensions + */ + struct fib_path_ext_t_ *fes_path_exts; + /** * The path-list created by the source */ @@ -273,10 +278,6 @@ typedef struct fib_entry_src_t_ { * Flags on the source */ fib_entry_src_flag_t fes_flags; - /** - * Flags the source contributes to the entry - */ - fib_entry_flag_t fes_entry_flags; /** * 1 bytes ref count. This is not the number of users of the Entry @@ -286,9 +287,9 @@ typedef struct fib_entry_src_t_ { u8 fes_ref_count; /** - * A vector of path extensions + * Flags the source contributes to the entry */ - struct fib_path_ext_t_ *fes_path_exts; + fib_entry_flag_t fes_entry_flags; /** * Source specific info @@ -502,7 +503,6 @@ extern int fib_entry_is_sourced(fib_node_index_t fib_entry_index, fib_source_t source); extern fib_node_index_t fib_entry_get_path_list(fib_node_index_t fib_entry_index); -extern u32 fib_entry_get_fib_table_id(fib_node_index_t fib_entry_index); extern void fib_entry_module_init(void); diff --git a/vnet/vnet/fib/fib_node.c b/vnet/vnet/fib/fib_node.c index 8ac67d2ef92..5ecc9a7fb2f 100644 --- a/vnet/vnet/fib/fib_node.c +++ b/vnet/vnet/fib/fib_node.c @@ -205,3 +205,62 @@ fib_node_unlock (fib_node_t *node) node->fn_vft->fnv_last_lock(node); } } + +void +fib_show_memory_usage (const char *name, + u32 in_use_elts, + u32 allocd_elts, + size_t size_elt) +{ + vlib_cli_output (vlib_get_main(), "%=30s %=5d %=8d/%=9d %d/%d ", + name, size_elt, + in_use_elts, allocd_elts, + in_use_elts*size_elt, allocd_elts*size_elt); +} + +static clib_error_t * +fib_memory_show (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + fib_node_vft_t *vft; + + vlib_cli_output (vm, "FIB memory"); + vlib_cli_output (vm, "%=30s %=5s %=8s/%=9s totals", + "Name","Size", "in-use", "allocated"); + + vec_foreach(vft, fn_vfts) + { + if (NULL != vft->fnv_mem_show) + vft->fnv_mem_show(); + } + + fib_node_list_memory_show(); + + return (NULL); +} + +/* *INDENT-OFF* */ +/*? + * The 'sh fib memory ' command displays the memory usage for each + * FIB object type. + * + * @cliexpar + * @cliexstart{show fib memory} + * FIB memory + * Name Size in-use /allocated totals + * Entry 120 11 / 11 1320/1320 + * Entry Source 32 11 / 11 352/352 + * Entry Path-Extensions 44 0 / 0 0/0 + * Path-list 40 11 / 11 440/440 + * Path 88 11 / 11 968/968 + * Node-list elements 20 11 / 11 220/220 + * Node-list heads 8 13 / 13 104/104 + * @cliexend +?*/ +VLIB_CLI_COMMAND (show_fib_memory, static) = { + .path = "show fib memory", + .function = fib_memory_show, + .short_help = "show fib memory", +}; +/* *INDENT-ON* */ diff --git a/vnet/vnet/fib/fib_node.h b/vnet/vnet/fib/fib_node.h index 6a54c6f565b..2f9a107ab8b 100644 --- a/vnet/vnet/fib/fib_node.h +++ b/vnet/vnet/fib/fib_node.h @@ -219,6 +219,12 @@ typedef struct fib_node_t_* (*fib_node_get_t)(fib_node_index_t index); */ typedef void (*fib_node_last_lock_gone_t)(struct fib_node_t_ *node); +/** + * Function definition to display the amount of memory used by a type. + * Implementations should call fib_show_memory_usage() + */ +typedef void (*fib_node_memory_show_t)(void); + /** * A FIB graph nodes virtual function table */ @@ -227,6 +233,7 @@ typedef struct fib_node_vft_t_ { fib_node_last_lock_gone_t fnv_last_lock; fib_node_back_walk_t fnv_back_walk; format_function_t *fnv_format; + fib_node_memory_show_t fnv_mem_show; } fib_node_vft_t; /** @@ -284,6 +291,22 @@ extern void fib_node_register_type (fib_node_type_t ft, */ extern fib_node_type_t fib_node_register_new_type (const fib_node_vft_t *vft); +/** + * @brief Show the memory usage for a type + * + * This should be invoked by the type in response to the infra calling + * its registered memory show function + * + * @param name the name of the type + * @param in_use_elts The number of elements in use + * @param allocd_elts The number of allocated pool elemenets + * @param size_elt The size of one element + */ +extern void fib_show_memory_usage(const char *name, + u32 in_use_elts, + u32 allocd_elts, + size_t size_elt); + extern void fib_node_init(fib_node_t *node, fib_node_type_t ft); extern void fib_node_deinit(fib_node_t *node); diff --git a/vnet/vnet/fib/fib_node_list.c b/vnet/vnet/fib/fib_node_list.c index 1d2e75ecec2..ceb951b466b 100644 --- a/vnet/vnet/fib/fib_node_list.c +++ b/vnet/vnet/fib/fib_node_list.c @@ -25,12 +25,6 @@ */ typedef struct fib_node_list_elt_t_ { - /** - * An opaque indentifier set by the FIB node owning this element - * that will allow the owner to identify which element it is. - */ - int fnle_owner_id; - /** * The index of the list this element is in */ @@ -108,7 +102,6 @@ fib_node_list_elt_create (fib_node_list_head_t *head, pool_get(fib_node_list_elt_pool, elt); elt->fnle_list = fib_node_list_head_get_index(head); - elt->fnle_owner_id = id; elt->fnle_owner.fnp_type = type; elt->fnle_owner.fnp_index = index; @@ -126,8 +119,7 @@ fib_node_list_head_init (fib_node_list_head_t *head) } /** - * @brief Create a new node list. The expectation is that these are few in number - * so straight from the memory subsystem + * @brief Create a new node list. */ fib_node_list_t fib_node_list_create (void) @@ -383,3 +375,16 @@ fib_node_list_walk (fib_node_list_t list, fn(&elt->fnle_owner, args); } } + +void +fib_node_list_memory_show (void) +{ + fib_show_memory_usage("Node-list elements", + pool_elts(fib_node_list_elt_pool), + pool_len(fib_node_list_elt_pool), + sizeof(fib_node_list_elt_t)); + fib_show_memory_usage("Node-list heads", + pool_elts(fib_node_list_head_pool), + pool_len(fib_node_list_head_pool), + sizeof(fib_node_list_head_t)); +} diff --git a/vnet/vnet/fib/fib_node_list.h b/vnet/vnet/fib/fib_node_list.h index afee3c6152c..9567b9669e8 100644 --- a/vnet/vnet/fib/fib_node_list.h +++ b/vnet/vnet/fib/fib_node_list.h @@ -58,4 +58,7 @@ typedef int (*fib_node_list_walk_cb_t)(fib_node_ptr_t *owner, extern void fib_node_list_walk(fib_node_list_t head, fib_node_list_walk_cb_t fn, void *args); + +extern void fib_node_list_memory_show(void); + #endif diff --git a/vnet/vnet/fib/fib_path.c b/vnet/vnet/fib/fib_path.c index d5453fde256..03cc7be5d9c 100644 --- a/vnet/vnet/fib/fib_path.c +++ b/vnet/vnet/fib/fib_path.c @@ -848,6 +848,15 @@ FIXME comment return (FIB_NODE_BACK_WALK_CONTINUE); } +static void +fib_path_memory_show (void) +{ + fib_show_memory_usage("Path", + pool_elts(fib_path_pool), + pool_len(fib_path_pool), + sizeof(fib_path_t)); +} + /* * The FIB path's graph node virtual function table */ @@ -855,6 +864,7 @@ static const fib_node_vft_t fib_path_vft = { .fnv_get = fib_path_get_node, .fnv_last_lock = fib_path_last_lock_gone, .fnv_back_walk = fib_path_back_walk_notify, + .fnv_mem_show = fib_path_memory_show, }; static fib_path_cfg_flags_t diff --git a/vnet/vnet/fib/fib_path_list.c b/vnet/vnet/fib/fib_path_list.c index 3523d93a7bb..611fe9fb5ae 100644 --- a/vnet/vnet/fib/fib_path_list.c +++ b/vnet/vnet/fib/fib_path_list.c @@ -451,6 +451,18 @@ fib_path_list_back_walk_notify (fib_node_t *node, return (FIB_NODE_BACK_WALK_CONTINUE); } +/* + * Display the path-list memory usage + */ +static void +fib_path_list_memory_show (void) +{ + fib_show_memory_usage("Path-list", + pool_elts(fib_path_list_pool), + pool_len(fib_path_list_pool), + sizeof(fib_path_list_t)); +} + /* * The FIB path-list's graph node virtual function table */ @@ -458,6 +470,7 @@ static const fib_node_vft_t fib_path_list_vft = { .fnv_get = fib_path_list_get_node, .fnv_last_lock = fib_path_list_last_lock_gone, .fnv_back_walk = fib_path_list_back_walk_notify, + .fnv_mem_show = fib_path_list_memory_show, }; static fib_path_list_t * diff --git a/vnet/vnet/ip/lookup.c b/vnet/vnet/ip/lookup.c index a695ef765a0..5cfdc23ea01 100644 --- a/vnet/vnet/ip/lookup.c +++ b/vnet/vnet/ip/lookup.c @@ -38,7 +38,7 @@ */ #include -#include +#include #include #include #include @@ -162,7 +162,7 @@ void ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6) ASSERT(STRUCT_OFFSET_OF(ip_adjacency_t, cacheline1) == CLIB_CACHE_LINE_BYTES); /* Preallocate three "special" adjacencies */ - lm->adjacency_heap = adj_heap; + lm->adjacency_heap = adj_pool; if (! lm->fib_result_n_bytes) lm->fib_result_n_bytes = sizeof (uword); @@ -345,6 +345,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, is_del = 0; table_id = 0; count = 1; + memset(&pfx, 0, sizeof(pfx)); /* Get a line of input. */ if (! unformat_user (main_input, unformat_line_input, line_input)) @@ -353,7 +354,6 @@ vnet_ip_route_cmd (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { memset(&rpath, 0, sizeof(rpath)); - memset(&pfx, 0, sizeof(pfx)); if (unformat (line_input, "table %d", &table_id)) ; @@ -510,6 +510,7 @@ vnet_ip_route_cmd (vlib_main_t * vm, { rpath.frp_label = MPLS_LABEL_INVALID; rpath.frp_proto = pfx.fp_proto; + rpath.frp_sw_if_index = ~0; vec_add1(rpaths, rpath); } else if (vec_len (prefixs) > 0 && diff --git a/vnet/vnet/ip/lookup.h b/vnet/vnet/ip/lookup.h index a21e1810983..97f776cb09d 100644 --- a/vnet/vnet/ip/lookup.h +++ b/vnet/vnet/ip/lookup.h @@ -173,8 +173,6 @@ typedef void (*adj_midchain_fixup_t)(vlib_main_t * vm, */ typedef struct ip_adjacency_t_ { CLIB_CACHE_LINE_ALIGN_MARK(cacheline0); - /* Handle for this adjacency in adjacency heap. */ - u32 heap_handle; /** Number of adjecencies in block. Greater than 1 means multipath; otherwise equal to 1. */ @@ -399,8 +397,6 @@ ip_get_adjacency (ip_lookup_main_t * lm, adj = vec_elt_at_index (lm->adjacency_heap, adj_index); - ASSERT (adj->heap_handle != ~0); - return adj; } -- 2.16.6