Move doxytags file to html output directory
[vpp.git] / vnet / vnet / adj / adj_alloc.c
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #include <vnet/adj/adj_alloc.h>
17 #include <vnet/ip/ip.h>
18
19 /*
20  * the single adj heap
21  */
22 ip_adjacency_t *adj_heap;
23
24 /* 
25  * any operation which could cause the adj vector to be reallocated
26  * must have a worker thread barrier
27  */
28 static inline int will_reallocate (ip_adjacency_t * adjs, u32 n)
29 {
30   uword aligned_header_bytes, new_data_bytes;
31   uword data_bytes;
32   aa_header_t * ah = aa_header (adjs);
33
34   if (adjs == 0)
35     return 1;
36
37   data_bytes = (vec_len (adjs) + n) * sizeof (*adjs);
38
39   aligned_header_bytes = vec_header_bytes (aa_aligned_header_bytes);
40   
41   new_data_bytes = data_bytes + aligned_header_bytes;
42
43   ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
44
45   if (PREDICT_TRUE(new_data_bytes <= clib_mem_size (_vec_find(ah))))
46     return 0;
47
48   return 1;
49 }
50
51 ip_adjacency_t * 
52 aa_alloc (void)
53 {
54   vlib_main_t * vm = &vlib_global_main;
55   aa_header_t * ah = aa_header (adj_heap);
56   ip_adjacency_t * adj_block;
57   u32 freelist_length;
58   int need_barrier_sync = 0;
59   u32 n = 1;
60   
61   ASSERT(os_get_cpu_number() == 0);
62   ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
63   
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)
66     {
67       if (will_reallocate (adj_heap, n))
68         {
69           need_barrier_sync = 1;
70           vlib_worker_thread_barrier_sync (vm);
71         }
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);
78       goto out;
79     }
80   /* See if we have a free adj block to dole out */
81   if ((freelist_length = vec_len(ah->free_indices_by_size[n])))
82     {
83       u32 index = ah->free_indices_by_size[n][freelist_length-1];
84
85       adj_block = &adj_heap[index];
86       _vec_len(ah->free_indices_by_size[n]) -= 1;
87       goto out;
88     }
89   /* Allocate a new block of size N */
90   if (will_reallocate (adj_heap, n))
91     {
92       need_barrier_sync = 1;
93       vlib_worker_thread_barrier_sync (vm);
94     }
95   vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes, 
96                CLIB_CACHE_LINE_BYTES);
97   
98   if (need_barrier_sync)
99     vlib_worker_thread_barrier_release (vm);
100
101  out:
102   memset (adj_block, 0, n * (sizeof(*adj_block)));
103   adj_block->heap_handle = adj_block - adj_heap;
104   adj_block->n_adj = n;
105
106   /*
107    * the adj heap may have realloc'd. recache.
108    */
109   ip4_main.lookup_main.adjacency_heap = adj_heap;
110   ip6_main.lookup_main.adjacency_heap = adj_heap;
111
112   return (adj_block);
113 }
114
115 void aa_free (ip_adjacency_t * adj)
116 {
117   aa_header_t * ah = aa_header (adj_heap);
118   
119   ASSERT (adj_heap && adj && (adj->heap_handle < vec_len (adj_heap)));
120   ASSERT (adj->heap_handle != 0);
121   
122   vec_add1 (ah->free_indices_by_size[adj->n_adj], adj->heap_handle);
123   adj->heap_handle = 0;
124 }
125
126 void aa_bootstrap (u32 n)
127 {
128   ip_adjacency_t * adj_block;
129   aa_header_t * ah;
130   int i;
131
132   vec_add2_ha (adj_heap, adj_block, n, aa_aligned_header_bytes, 
133                CLIB_CACHE_LINE_BYTES);
134
135   memset (adj_block, 0, n * sizeof(*adj_block));
136   ah = aa_header (adj_heap);
137   memset (ah, 0, sizeof (*ah));
138
139   vec_validate (ah->free_indices_by_size, 1);
140
141   for (i = 0 ; i < vec_len (adj_heap); i++)
142     {
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));
147     }
148
149   ip4_main.lookup_main.adjacency_heap = adj_heap;
150   ip6_main.lookup_main.adjacency_heap = adj_heap;
151 }
152
153 u8 * format_adjacency_alloc (u8 * s, va_list * args)
154 {
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;
159   u32 on_freelist = 0;
160   int i, j;
161   aa_header_t * ah = aa_header (adj_heap);
162
163   for (i = 0; i < vec_len (adj_heap); i += adj->n_adj)
164     {
165       adj = adj_heap + i;
166       if ((i == 0) || adj->heap_handle)
167         inuse += adj->n_adj;
168       else
169         freed += adj->n_adj;
170     }
171
172   for (i = 1; i < vec_len(ah->free_indices_by_size); i++)
173     {
174       for (j = 0; j < vec_len(ah->free_indices_by_size[i]); j++)
175         {
176           adj = adj_heap + ah->free_indices_by_size[i][j];
177           ASSERT(adj->heap_handle == 0);
178           on_freelist += adj->n_adj;
179         }
180     }
181       
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);
184   if (verbose)
185     {
186       for (i = 0; i < vec_len (adj_heap); i += adj->n_adj)
187         {
188           adj = adj_heap + i;
189           if ((i == 0) || adj->heap_handle)
190             {
191               if (adj->n_adj > 1)
192                 s = format (s, "[%d-%d] ", i, i+adj->n_adj-1);
193               else
194                 s = format (s, "[%d] ", i);
195
196               for (j = 0; j < adj->n_adj; j++)
197                 {
198                   if (j > 0)
199                     s = format (s, "      ");
200
201                   s = format(s, "%U\n", format_ip_adjacency, 
202                              vnm, i+j, FORMAT_IP_ADJACENCY_NONE);
203                 }
204             }
205         }
206     }
207   return s;
208 }
209
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)
214 {
215   int verbose = 0;
216   vnet_main_t *vnm = vnet_get_main();
217   
218   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) 
219     {
220       if (unformat (input, "verbose"))
221         verbose = 1;
222       else
223         return clib_error_return (0, "unknown input `%U'",
224                                   format_unformat_error, input);
225     }
226
227   vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, verbose);
228
229   return 0;
230 }
231
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,
236 };