diff options
Diffstat (limited to 'vnet/vnet/adj/adj_alloc.c')
-rw-r--r-- | vnet/vnet/adj/adj_alloc.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/vnet/vnet/adj/adj_alloc.c b/vnet/vnet/adj/adj_alloc.c new file mode 100644 index 00000000000..5cc8cf6ef04 --- /dev/null +++ b/vnet/vnet/adj/adj_alloc.c @@ -0,0 +1,236 @@ +/* + * 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 <vnet/adj/adj_alloc.h> +#include <vnet/ip/ip.h> + +/* + * 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, +}; |