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/ip/adj_alloc.h>
17 #include <vnet/ip/ip.h>
20 * any operation which could cause the adj vector to be reallocated
21 * must have a worker thread barrier
24 static inline int will_reallocate (ip_adjacency_t * adjs, u32 n)
26 uword aligned_header_bytes, new_data_bytes;
28 aa_header_t * ah = aa_header (adjs);
33 data_bytes = (vec_len (adjs) + n) * sizeof (*adjs);
35 aligned_header_bytes = vec_header_bytes (aa_aligned_header_bytes);
37 new_data_bytes = data_bytes + aligned_header_bytes;
39 ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
41 if (PREDICT_TRUE(new_data_bytes <= clib_mem_size (_vec_find(ah))))
48 aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n)
50 vlib_main_t * vm = &vlib_global_main;
51 aa_header_t * ah = aa_header (adjs);
52 ip_adjacency_t * adj_block;
54 int need_barrier_sync = 0;
56 ASSERT(os_get_cpu_number() == 0);
57 ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
59 /* If we don't have a freelist of size N, fresh allocation is required */
60 if (vec_len (ah->free_indices_by_size) <= n)
62 if (will_reallocate (adjs, n))
64 need_barrier_sync = 1;
65 vlib_worker_thread_barrier_sync (vm);
67 /* Workers wont look at the freelists... */
68 vec_validate (ah->free_indices_by_size, n);
69 vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes,
70 CLIB_CACHE_LINE_BYTES);
71 if (need_barrier_sync)
72 vlib_worker_thread_barrier_release (vm);
75 /* See if we have a free adj block to dole out */
76 if ((freelist_length = vec_len(ah->free_indices_by_size[n])))
78 u32 index = ah->free_indices_by_size[n][freelist_length-1];
80 adj_block = &adjs[index];
81 _vec_len(ah->free_indices_by_size[n]) -= 1;
84 /* Allocate a new block of size N */
85 if (will_reallocate (adjs, n))
87 need_barrier_sync = 1;
88 vlib_worker_thread_barrier_sync (vm);
90 vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes,
91 CLIB_CACHE_LINE_BYTES);
93 if (need_barrier_sync)
94 vlib_worker_thread_barrier_release (vm);
97 memset (adj_block, 0, n * (sizeof(*adj_block)));
98 adj_block->heap_handle = adj_block - adjs;
104 void aa_free (ip_adjacency_t * adjs, ip_adjacency_t * adj)
106 aa_header_t * ah = aa_header (adjs);
108 ASSERT (adjs && adj && (adj->heap_handle < vec_len (adjs)));
109 ASSERT (adj->n_adj < vec_len (ah->free_indices_by_size));
110 ASSERT (adj->heap_handle != 0);
112 vec_add1 (ah->free_indices_by_size[adj->n_adj], adj->heap_handle);
113 adj->heap_handle = 0;
116 ip_adjacency_t * aa_bootstrap (ip_adjacency_t * adjs, u32 n)
118 ip_adjacency_t * adj_block;
122 vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes,
123 CLIB_CACHE_LINE_BYTES);
125 memset (adj_block, 0, n * sizeof(*adj_block));
126 ah = aa_header (adjs);
127 memset (ah, 0, sizeof (*ah));
129 vec_validate (ah->free_indices_by_size, 1);
131 for (i = 0 ; i < vec_len (adjs); i++)
133 adj_block->n_adj = 1;
134 adj_block->heap_handle = ~0;
135 /* Euchre the allocator into returning 0, 1, 2, etc. */
136 vec_add1 (ah->free_indices_by_size[1], n - (i+1));
142 u8 * format_adjacency_alloc (u8 * s, va_list * args)
144 vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
145 ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
146 ip_adjacency_t * adjs = va_arg (*args, ip_adjacency_t *);
147 int verbose = va_arg (*args, int);
148 ip_adjacency_t * adj;
149 u32 inuse = 0, freed = 0;
152 aa_header_t * ah = aa_header (adjs);
154 for (i = 0; i < vec_len (adjs); i += adj->n_adj)
157 if ((i == 0) || adj->heap_handle)
163 for (i = 1; i < vec_len(ah->free_indices_by_size); i++)
165 for (j = 0; j < vec_len(ah->free_indices_by_size[i]); j++)
167 adj = adjs + ah->free_indices_by_size[i][j];
168 ASSERT(adj->heap_handle == 0);
169 on_freelist += adj->n_adj;
173 s = format (s, "adjs: %d total, %d in use, %d free, %d on freelists\n",
174 vec_len(adjs), inuse, freed, on_freelist);
177 for (i = 0; i < vec_len (adjs); i += adj->n_adj)
180 if ((i == 0) || adj->heap_handle)
183 s = format (s, "[%d-%d] ", i, i+adj->n_adj-1);
185 s = format (s, "[%d] ", i);
187 for (j = 0; j < adj->n_adj; j++)
192 s = format(s, "%U\n", format_ip_adjacency,
201 static clib_error_t *
202 show_adjacency_alloc_command_fn (vlib_main_t * vm,
203 unformat_input_t * input,
204 vlib_cli_command_t * cmd)
207 vnet_main_t *vnm = vnet_get_main();
208 ip_lookup_main_t *lm = 0;
209 ip_adjacency_t * adjs = 0;
212 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
214 if (unformat (input, "verbose"))
216 else if (unformat (input, "ip4"))
218 else if (unformat (input, "ip6"))
221 return clib_error_return (0, "unknown input `%U'",
222 format_unformat_error, input);
226 lm = &ip4_main.lookup_main;
228 lm = &ip6_main.lookup_main;
230 adjs = lm->adjacency_heap;
232 vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, lm, adjs, verbose);
237 VLIB_CLI_COMMAND (show_adjacency_alloc_command, static) = {
238 .path = "show adjacency alloc",
239 .short_help = "show adjacency alloc",
240 .function = show_adjacency_alloc_command_fn,