2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/adj/adj_alloc.h>
17 #include <vnet/ip/ip.h>
22 ip_adjacency_t *adj_heap;
25 * any operation which could cause the adj vector to be reallocated
26 * must have a worker thread barrier
28 static inline int will_reallocate (ip_adjacency_t * adjs, u32 n)
30 uword aligned_header_bytes, new_data_bytes;
32 aa_header_t * ah = aa_header (adjs);
37 data_bytes = (vec_len (adjs) + n) * sizeof (*adjs);
39 aligned_header_bytes = vec_header_bytes (aa_aligned_header_bytes);
41 new_data_bytes = data_bytes + aligned_header_bytes;
43 ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
45 if (PREDICT_TRUE(new_data_bytes <= clib_mem_size (_vec_find(ah))))
54 vlib_main_t * vm = &vlib_global_main;
55 aa_header_t * ah = aa_header (adj_heap);
56 ip_adjacency_t * adj_block;
58 int need_barrier_sync = 0;
61 ASSERT(os_get_cpu_number() == 0);
62 ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
64 /* If we don't have a freelist of size N, fresh allocation is required */
65 if (vec_len (ah->free_indices_by_size) <= n)
67 if (will_reallocate (adj_heap, n))
69 need_barrier_sync = 1;
70 vlib_worker_thread_barrier_sync (vm);
72 /* Workers wont look at the freelists... */
73 vec_validate (ah->free_indices_by_size, n);
74 vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes,
75 CLIB_CACHE_LINE_BYTES);
76 if (need_barrier_sync)
77 vlib_worker_thread_barrier_release (vm);
80 /* See if we have a free adj block to dole out */
81 if ((freelist_length = vec_len(ah->free_indices_by_size[n])))
83 u32 index = ah->free_indices_by_size[n][freelist_length-1];
85 adj_block = &adj_heap[index];
86 _vec_len(ah->free_indices_by_size[n]) -= 1;
89 /* Allocate a new block of size N */
90 if (will_reallocate (adj_heap, n))
92 need_barrier_sync = 1;
93 vlib_worker_thread_barrier_sync (vm);
95 vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes,
96 CLIB_CACHE_LINE_BYTES);
98 if (need_barrier_sync)
99 vlib_worker_thread_barrier_release (vm);
102 memset (adj_block, 0, n * (sizeof(*adj_block)));
103 adj_block->heap_handle = adj_block - adj_heap;
104 adj_block->n_adj = n;
107 * the adj heap may have realloc'd. recache.
109 ip4_main.lookup_main.adjacency_heap = adj_heap;
110 ip6_main.lookup_main.adjacency_heap = adj_heap;
115 void aa_free (ip_adjacency_t * adj)
117 aa_header_t * ah = aa_header (adj_heap);
119 ASSERT (adj_heap && adj && (adj->heap_handle < vec_len (adj_heap)));
120 ASSERT (adj->heap_handle != 0);
122 vec_add1 (ah->free_indices_by_size[adj->n_adj], adj->heap_handle);
123 adj->heap_handle = 0;
126 void aa_bootstrap (u32 n)
128 ip_adjacency_t * adj_block;
132 vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes,
133 CLIB_CACHE_LINE_BYTES);
135 memset (adj_block, 0, n * sizeof(*adj_block));
136 ah = aa_header (adj_heap);
137 memset (ah, 0, sizeof (*ah));
139 vec_validate (ah->free_indices_by_size, 1);
141 for (i = 0 ; i < vec_len (adj_heap); i++)
143 adj_block->n_adj = 1;
144 adj_block->heap_handle = ~0;
145 /* Euchre the allocator into returning 0, 1, 2, etc. */
146 vec_add1 (ah->free_indices_by_size[1], n - (i+1));
149 ip4_main.lookup_main.adjacency_heap = adj_heap;
150 ip6_main.lookup_main.adjacency_heap = adj_heap;
153 u8 * format_adjacency_alloc (u8 * s, va_list * args)
155 vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
156 int verbose = va_arg (*args, int);
157 ip_adjacency_t * adj;
158 u32 inuse = 0, freed = 0;
161 aa_header_t * ah = aa_header (adj_heap);
163 for (i = 0; i < vec_len (adj_heap); i += adj->n_adj)
166 if ((i == 0) || adj->heap_handle)
172 for (i = 1; i < vec_len(ah->free_indices_by_size); i++)
174 for (j = 0; j < vec_len(ah->free_indices_by_size[i]); j++)
176 adj = adj_heap + ah->free_indices_by_size[i][j];
177 ASSERT(adj->heap_handle == 0);
178 on_freelist += adj->n_adj;
182 s = format (s, "adj_heap: %d total, %d in use, %d free, %d on freelists\n",
183 vec_len(adj_heap), inuse, freed, on_freelist);
186 for (i = 0; i < vec_len (adj_heap); i += adj->n_adj)
189 if ((i == 0) || adj->heap_handle)
192 s = format (s, "[%d-%d] ", i, i+adj->n_adj-1);
194 s = format (s, "[%d] ", i);
196 for (j = 0; j < adj->n_adj; j++)
201 s = format(s, "%U\n", format_ip_adjacency,
202 vnm, i+j, FORMAT_IP_ADJACENCY_NONE);
210 static clib_error_t *
211 show_adjacency_alloc_command_fn (vlib_main_t * vm,
212 unformat_input_t * input,
213 vlib_cli_command_t * cmd)
216 vnet_main_t *vnm = vnet_get_main();
218 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
220 if (unformat (input, "verbose"))
223 return clib_error_return (0, "unknown input `%U'",
224 format_unformat_error, input);
227 vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, verbose);
232 VLIB_CLI_COMMAND (show_adjacency_alloc_command, static) = {
233 .path = "show adjacency alloc",
234 .short_help = "show adjacency alloc",
235 .function = show_adjacency_alloc_command_fn,