3ae7a199f1981b8abd9b2b217ad772be5cebc0ec
[vpp.git] / vnet / vnet / ip / 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/ip/adj_alloc.h>
17 #include <vnet/ip/ip.h>
18
19 /* 
20  * any operation which could cause the adj vector to be reallocated
21  * must have a worker thread barrier
22  */
23
24 static inline int will_reallocate (ip_adjacency_t * adjs, u32 n)
25 {
26   uword aligned_header_bytes, new_data_bytes;
27   uword data_bytes;
28   aa_header_t * ah = aa_header (adjs);
29
30   if (adjs == 0)
31     return 1;
32
33   data_bytes = (vec_len (adjs) + n) * sizeof (*adjs);
34
35   aligned_header_bytes = vec_header_bytes (aa_aligned_header_bytes);
36   
37   new_data_bytes = data_bytes + aligned_header_bytes;
38
39   ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
40
41   if (PREDICT_TRUE(new_data_bytes <= clib_mem_size (_vec_find(ah))))
42     return 0;
43
44   return 1;
45 }
46
47 ip_adjacency_t * 
48 aa_alloc (ip_adjacency_t * adjs, ip_adjacency_t **blockp, u32 n)
49 {
50   vlib_main_t * vm = &vlib_global_main;
51   aa_header_t * ah = aa_header (adjs);
52   ip_adjacency_t * adj_block;
53   u32 freelist_length;
54   int need_barrier_sync = 0;
55   
56   ASSERT(os_get_cpu_number() == 0);
57   ASSERT (clib_mem_is_heap_object (_vec_find(ah)));
58   
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)
61     {
62       if (will_reallocate (adjs, n))
63         {
64           need_barrier_sync = 1;
65           vlib_worker_thread_barrier_sync (vm);
66         }
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);
73       goto out;
74     }
75   /* See if we have a free adj block to dole out */
76   if ((freelist_length = vec_len(ah->free_indices_by_size[n])))
77     {
78       u32 index = ah->free_indices_by_size[n][freelist_length-1];
79
80       adj_block = &adjs[index];
81       _vec_len(ah->free_indices_by_size[n]) -= 1;
82       goto out;
83     }
84   /* Allocate a new block of size N */
85   if (will_reallocate (adjs, n))
86     {
87       need_barrier_sync = 1;
88       vlib_worker_thread_barrier_sync (vm);
89     }
90   vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes, 
91                CLIB_CACHE_LINE_BYTES);
92   
93   if (need_barrier_sync)
94     vlib_worker_thread_barrier_release (vm);
95
96  out:
97   memset (adj_block, 0, n * (sizeof(*adj_block)));
98   adj_block->heap_handle = adj_block - adjs;
99   adj_block->n_adj = n;
100   *blockp = adj_block;
101   return adjs;
102 }
103
104 void aa_free (ip_adjacency_t * adjs, ip_adjacency_t * adj)
105 {
106   aa_header_t * ah = aa_header (adjs);
107   
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);
111   
112   vec_add1 (ah->free_indices_by_size[adj->n_adj], adj->heap_handle);
113   adj->heap_handle = 0;
114 }
115
116 ip_adjacency_t * aa_bootstrap (ip_adjacency_t * adjs, u32 n)
117 {
118   ip_adjacency_t * adj_block;
119   aa_header_t * ah;
120   int i;
121
122   vec_add2_ha (adjs, adj_block, n, aa_aligned_header_bytes, 
123                CLIB_CACHE_LINE_BYTES);
124
125   memset (adj_block, 0, n * sizeof(*adj_block));
126   ah = aa_header (adjs);
127   memset (ah, 0, sizeof (*ah));
128
129   vec_validate (ah->free_indices_by_size, 1);
130
131   for (i = 0 ; i < vec_len (adjs); i++)
132     {
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));
137     }
138
139   return adjs;
140 }
141
142 u8 * format_adjacency_alloc (u8 * s, va_list * args)
143 {
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;
150   u32 on_freelist = 0;
151   int i, j;
152   aa_header_t * ah = aa_header (adjs);
153
154   for (i = 0; i < vec_len (adjs); i += adj->n_adj)
155     {
156       adj = adjs + i;
157       if ((i == 0) || adj->heap_handle)
158         inuse += adj->n_adj;
159       else
160         freed += adj->n_adj;
161     }
162
163   for (i = 1; i < vec_len(ah->free_indices_by_size); i++)
164     {
165       for (j = 0; j < vec_len(ah->free_indices_by_size[i]); j++)
166         {
167           adj = adjs + ah->free_indices_by_size[i][j];
168           ASSERT(adj->heap_handle == 0);
169           on_freelist += adj->n_adj;
170         }
171     }
172       
173   s = format (s, "adjs: %d total, %d in use, %d free, %d on freelists\n",
174               vec_len(adjs), inuse, freed, on_freelist);
175   if (verbose)
176     {
177       for (i = 0; i < vec_len (adjs); i += adj->n_adj)
178         {
179           adj = adjs + i;
180           if ((i == 0) || adj->heap_handle)
181             {
182               if (adj->n_adj > 1)
183                 s = format (s, "[%d-%d] ", i, i+adj->n_adj-1);
184               else
185                 s = format (s, "[%d] ", i);
186
187               for (j = 0; j < adj->n_adj; j++)
188                 {
189                   if (j > 0)
190                     s = format (s, "      ");
191
192                   s = format(s, "%U\n", format_ip_adjacency, 
193                          vnm, lm, i+j);
194                 }
195             }
196         }
197     }
198   return s;
199 }
200
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)
205 {
206   int verbose = 0;
207   vnet_main_t *vnm = vnet_get_main();
208   ip_lookup_main_t *lm = 0;
209   ip_adjacency_t * adjs = 0;
210   int is_ip4 = 1;
211   
212   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) 
213     {
214       if (unformat (input, "verbose"))
215         verbose = 1;
216       else if (unformat (input, "ip4"))
217         ;
218       else if (unformat (input, "ip6"))
219         is_ip4 = 0;
220       else
221         return clib_error_return (0, "unknown input `%U'",
222                                   format_unformat_error, input);
223     }
224
225   if (is_ip4)
226       lm = &ip4_main.lookup_main;
227   else
228       lm = &ip6_main.lookup_main;
229
230   adjs = lm->adjacency_heap;
231
232   vlib_cli_output (vm, "%U", format_adjacency_alloc, vnm, lm, adjs, verbose);
233
234   return 0;
235 }
236
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,
241 };