Line data Source code
1 : /*
2 : * Copyright (c) 2015 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 : * config.c: feature configuration
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 :
40 : #include <vnet/vnet.h>
41 :
42 : static vnet_config_feature_t *
43 87798 : duplicate_feature_vector (vnet_config_feature_t * feature_vector)
44 : {
45 : vnet_config_feature_t *result, *f;
46 :
47 87798 : result = vec_dup (feature_vector);
48 153215 : vec_foreach (f, result) f->feature_config = vec_dup (f->feature_config);
49 :
50 87798 : return result;
51 : }
52 :
53 : static void
54 100382 : free_feature_vector (vnet_config_feature_t * feature_vector)
55 : {
56 : vnet_config_feature_t *f;
57 :
58 169223 : vec_foreach (f, feature_vector) vnet_config_feature_free (f);
59 100382 : vec_free (feature_vector);
60 100382 : }
61 :
62 : static u32
63 215310 : add_next (vlib_main_t * vm,
64 : vnet_config_main_t * cm, u32 last_node_index, u32 this_node_index)
65 : {
66 215310 : u32 i, ni = ~0;
67 :
68 215310 : if (last_node_index != ~0)
69 71225 : return vlib_node_add_next (vm, last_node_index, this_node_index);
70 :
71 350453 : for (i = 0; i < vec_len (cm->start_node_indices); i++)
72 : {
73 : u32 tmp;
74 206368 : tmp =
75 206368 : vlib_node_add_next (vm, cm->start_node_indices[i], this_node_index);
76 206368 : if (ni == ~0)
77 144085 : ni = tmp;
78 : /* Start nodes to first must agree on next indices. */
79 206368 : ASSERT (ni == tmp);
80 : }
81 :
82 144085 : return ni;
83 : }
84 :
85 : static vnet_config_t *
86 144085 : find_config_with_features (vlib_main_t * vm,
87 : vnet_config_main_t * cm,
88 : vnet_config_feature_t * feature_vector,
89 : u32 end_node_index)
90 : {
91 144085 : u32 last_node_index = ~0;
92 : vnet_config_feature_t *f;
93 : u32 *config_string;
94 : uword *p;
95 : vnet_config_t *c;
96 :
97 144085 : config_string = cm->config_string_temp;
98 144085 : cm->config_string_temp = 0;
99 144085 : if (config_string)
100 95932 : vec_set_len (config_string, 0);
101 :
102 236228 : vec_foreach (f, feature_vector)
103 : {
104 : /* Connect node graph. */
105 92143 : f->next_index = add_next (vm, cm, last_node_index, f->node_index);
106 92143 : last_node_index = f->node_index;
107 :
108 : /* Store next index in config string. */
109 92143 : vec_add1 (config_string, f->next_index);
110 :
111 : /* Store feature config. */
112 92143 : vec_add (config_string, f->feature_config, vec_len (f->feature_config));
113 : }
114 :
115 : /* Terminate config string with next for end node. */
116 144085 : if (last_node_index == ~0 || last_node_index != end_node_index)
117 : {
118 123167 : u32 next_index = add_next (vm, cm, last_node_index, end_node_index);
119 123167 : vec_add1 (config_string, next_index);
120 : }
121 :
122 : /* Add the end node index to the config string so that it is part of
123 : * the key used to detect string sharing. If this is not included then
124 : * a modification of the end node would affect all the user of a shared
125 : * string. */
126 144085 : vec_add1 (config_string, end_node_index);
127 :
128 : /* See if config string is unique. */
129 288170 : p = hash_get_mem (cm->config_string_hash, config_string);
130 144085 : if (p)
131 : {
132 : /* Not unique. Share existing config. */
133 100382 : cm->config_string_temp = config_string; /* we'll use it again later. */
134 100382 : free_feature_vector (feature_vector);
135 100382 : c = pool_elt_at_index (cm->config_pool, p[0]);
136 : }
137 : else
138 : {
139 : u32 *d;
140 :
141 43703 : pool_get (cm->config_pool, c);
142 43703 : c->index = c - cm->config_pool;
143 43703 : c->features = feature_vector;
144 43703 : c->config_string_vector = config_string;
145 :
146 : /* Allocate copy of config string in heap.
147 : VLIB buffers will maintain pointers to heap as they read out
148 : configuration data. */
149 43703 : c->config_string_heap_index
150 43703 : = heap_alloc (cm->config_string_heap, vec_len (config_string) + 1,
151 : c->config_string_heap_handle);
152 :
153 : /* First element in heap points back to pool index. */
154 43703 : d =
155 43703 : vec_elt_at_index (cm->config_string_heap,
156 : c->config_string_heap_index);
157 43703 : d[0] = c->index;
158 43703 : clib_memcpy (d + 1, config_string, vec_bytes (config_string));
159 87406 : hash_set_mem (cm->config_string_hash, config_string, c->index);
160 :
161 43703 : c->reference_count = 0; /* will be incremented by caller. */
162 :
163 73213 : vec_validate_init_empty (cm->end_node_indices_by_user_index,
164 : c->config_string_heap_index + 1,
165 : cm->default_end_node_index);
166 43703 : cm->end_node_indices_by_user_index[c->config_string_heap_index + 1]
167 43703 : = end_node_index;
168 : }
169 :
170 144085 : return c;
171 : }
172 :
173 : void
174 16516 : vnet_config_init (vlib_main_t * vm,
175 : vnet_config_main_t * cm,
176 : char *start_node_names[],
177 : int n_start_node_names,
178 : char *feature_node_names[], int n_feature_node_names)
179 : {
180 : vlib_node_t *n;
181 : u32 i;
182 :
183 16516 : clib_memset (cm, 0, sizeof (cm[0]));
184 :
185 16516 : cm->config_string_hash =
186 16516 : hash_create_vec (0,
187 : STRUCT_SIZE_OF (vnet_config_t, config_string_vector[0]),
188 : sizeof (uword));
189 :
190 16516 : ASSERT (n_feature_node_names >= 1);
191 :
192 16516 : vec_resize (cm->start_node_indices, n_start_node_names);
193 38782 : for (i = 0; i < n_start_node_names; i++)
194 : {
195 22266 : n = vlib_get_node_by_name (vm, (u8 *) start_node_names[i]);
196 : /* Given node name must exist. */
197 22266 : ASSERT (n != 0);
198 22266 : cm->start_node_indices[i] = n->index;
199 : }
200 :
201 16516 : vec_resize (cm->node_index_by_feature_index, n_feature_node_names);
202 164674 : for (i = 0; i < n_feature_node_names; i++)
203 : {
204 148158 : if (!feature_node_names[i])
205 4698 : cm->node_index_by_feature_index[i] = ~0;
206 : else
207 : {
208 143460 : n = vlib_get_node_by_name (vm, (u8 *) feature_node_names[i]);
209 : /* Given node may exist in plug-in library which is not present */
210 143460 : if (n)
211 : {
212 140585 : if (i + 1 == n_feature_node_names)
213 16516 : cm->default_end_node_index = n->index;
214 140585 : cm->node_index_by_feature_index[i] = n->index;
215 : }
216 : else
217 2875 : cm->node_index_by_feature_index[i] = ~0;
218 : }
219 : }
220 16516 : }
221 :
222 : static void
223 115062 : remove_reference (vnet_config_main_t * cm, vnet_config_t * c)
224 : {
225 115062 : ASSERT (c->reference_count > 0);
226 115062 : c->reference_count -= 1;
227 115062 : if (c->reference_count == 0)
228 : {
229 37549 : hash_unset (cm->config_string_hash, c->config_string_vector);
230 37549 : vnet_config_free (cm, c);
231 37549 : pool_put (cm->config_pool, c);
232 : }
233 115062 : }
234 :
235 : static int
236 4786 : feature_cmp (void *a1, void *a2)
237 : {
238 4786 : vnet_config_feature_t *f1 = a1;
239 4786 : vnet_config_feature_t *f2 = a2;
240 :
241 4786 : return (int) f1->feature_index - f2->feature_index;
242 : }
243 :
244 : always_inline u32 *
245 116837 : vnet_get_config_heap (vnet_config_main_t * cm, u32 ci)
246 : {
247 116837 : return heap_elt_at_index (cm->config_string_heap, ci);
248 : }
249 :
250 : void
251 24767 : vnet_config_del (vnet_config_main_t * cm, u32 config_id)
252 : {
253 24767 : u32 *p = vnet_get_config_heap (cm, config_id);
254 24767 : vnet_config_t *old = pool_elt_at_index (cm->config_pool, p[-1]);
255 24767 : remove_reference (cm, old);
256 24767 : }
257 :
258 : u32
259 0 : vnet_config_reset_end_node (vlib_main_t *vm, vnet_config_main_t *cm, u32 ci)
260 : {
261 0 : cm->end_node_indices_by_user_index[ci] = cm->default_end_node_index;
262 :
263 : return (
264 0 : vnet_config_modify_end_node (vm, cm, ci, cm->default_end_node_index));
265 : }
266 :
267 : u32
268 4547 : vnet_config_modify_end_node (vlib_main_t * vm,
269 : vnet_config_main_t * cm,
270 : u32 config_string_heap_index, u32 end_node_index)
271 : {
272 : vnet_config_feature_t *new_features;
273 : vnet_config_t *old, *new;
274 :
275 4547 : if (end_node_index == ~0) // feature node does not exist
276 0 : return ~0;
277 :
278 4547 : if (config_string_heap_index == ~0)
279 : {
280 2024 : old = 0;
281 2024 : new_features = 0;
282 : }
283 : else
284 : {
285 2523 : u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
286 2523 : old = pool_elt_at_index (cm->config_pool, p[-1]);
287 2523 : new_features = old->features;
288 2523 : if (new_features)
289 196 : new_features = duplicate_feature_vector (new_features);
290 : }
291 :
292 4547 : if (vec_len (new_features))
293 : {
294 : /* is the last feature the cuurent end node */
295 26 : u32 last = vec_len (new_features) - 1;
296 26 : if (new_features[last].node_index == cm->default_end_node_index)
297 : {
298 0 : vec_free (new_features->feature_config);
299 0 : vec_set_len (new_features, last);
300 : }
301 : }
302 :
303 4547 : if (old)
304 2523 : remove_reference (cm, old);
305 :
306 4547 : new = find_config_with_features (vm, cm, new_features, end_node_index);
307 4547 : new->reference_count += 1;
308 :
309 : /*
310 : * User gets pointer to config string first element
311 : * (which defines the pool index
312 : * this config string comes from).
313 : */
314 4547 : vec_validate (cm->config_pool_index_by_user_index,
315 : new->config_string_heap_index + 1);
316 4547 : cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
317 4547 : = new - cm->config_pool;
318 4547 : return new->config_string_heap_index + 1;
319 : }
320 :
321 : u32
322 972 : vnet_config_get_end_node (vlib_main_t *vm, vnet_config_main_t *cm,
323 : u32 config_string_heap_index)
324 : {
325 972 : if (config_string_heap_index >= vec_len (cm->end_node_indices_by_user_index))
326 0 : return cm->default_end_node_index;
327 972 : if (~0 == cm->end_node_indices_by_user_index[config_string_heap_index])
328 0 : return cm->default_end_node_index;
329 :
330 972 : return (cm->end_node_indices_by_user_index[config_string_heap_index]);
331 : }
332 :
333 : u32
334 83132 : vnet_config_add_feature (vlib_main_t * vm,
335 : vnet_config_main_t * cm,
336 : u32 config_string_heap_index,
337 : u32 feature_index,
338 : void *feature_config, u32 n_feature_config_bytes)
339 : {
340 : vnet_config_t *old, *new;
341 : vnet_config_feature_t *new_features, *f;
342 : u32 n_feature_config_u32s, end_node_index;
343 83132 : u32 node_index = vec_elt (cm->node_index_by_feature_index, feature_index);
344 :
345 83132 : if (node_index == ~0) // feature node does not exist
346 0 : return ~0;
347 :
348 83132 : if (config_string_heap_index == ~0)
349 : {
350 51766 : old = 0;
351 51766 : new_features = 0;
352 51766 : end_node_index = cm->default_end_node_index;
353 : }
354 : else
355 : {
356 31366 : u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
357 31366 : old = pool_elt_at_index (cm->config_pool, p[-1]);
358 31366 : new_features = old->features;
359 31366 : end_node_index =
360 31366 : cm->end_node_indices_by_user_index[config_string_heap_index];
361 31366 : if (new_features)
362 31196 : new_features = duplicate_feature_vector (new_features);
363 : }
364 :
365 83132 : vec_add2 (new_features, f, 1);
366 83132 : f->feature_index = feature_index;
367 83132 : f->node_index = node_index;
368 :
369 83132 : if (n_feature_config_bytes)
370 : {
371 24374 : n_feature_config_u32s =
372 24374 : round_pow2 (n_feature_config_bytes,
373 24374 : sizeof (f->feature_config[0])) /
374 : sizeof (f->feature_config[0]);
375 24374 : vec_validate (f->feature_config, n_feature_config_u32s - 1);
376 24374 : clib_memcpy_fast (f->feature_config, feature_config,
377 : n_feature_config_bytes);
378 : }
379 :
380 : /* Sort (prioritize) features. */
381 83132 : if (vec_len (new_features) > 1)
382 4308 : vec_sort_with_function (new_features, feature_cmp);
383 :
384 83132 : if (old)
385 31366 : remove_reference (cm, old);
386 :
387 83132 : new = find_config_with_features (vm, cm, new_features, end_node_index);
388 83132 : new->reference_count += 1;
389 :
390 : /*
391 : * User gets pointer to config string first element
392 : * (which defines the pool index
393 : * this config string comes from).
394 : */
395 83132 : vec_validate (cm->config_pool_index_by_user_index,
396 : new->config_string_heap_index + 1);
397 83132 : cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
398 83132 : = new - cm->config_pool;
399 83132 : return new->config_string_heap_index + 1;
400 : }
401 :
402 : u32
403 58181 : vnet_config_del_feature (vlib_main_t * vm,
404 : vnet_config_main_t * cm,
405 : u32 config_string_heap_index,
406 : u32 feature_index,
407 : void *feature_config, u32 n_feature_config_bytes)
408 : {
409 : vnet_config_t *old, *new;
410 : vnet_config_feature_t *new_features, *f;
411 : u32 n_feature_config_u32s;
412 :
413 : {
414 58181 : u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
415 :
416 58181 : old = pool_elt_at_index (cm->config_pool, p[-1]);
417 : }
418 :
419 58181 : n_feature_config_u32s =
420 58181 : round_pow2 (n_feature_config_bytes,
421 58181 : sizeof (f->feature_config[0])) /
422 : sizeof (f->feature_config[0]);
423 :
424 : /* Find feature with same index and opaque data. */
425 61077 : vec_foreach (f, old->features)
426 : {
427 59302 : if (f->feature_index == feature_index
428 56406 : && vec_len (f->feature_config) == n_feature_config_u32s
429 56406 : && (n_feature_config_u32s == 0
430 16209 : || !memcmp (f->feature_config, feature_config,
431 : n_feature_config_bytes)))
432 : break;
433 : }
434 :
435 : /* Feature not found. */
436 58181 : if (f >= vec_end (old->features))
437 1775 : return ~0;
438 :
439 56406 : new_features = duplicate_feature_vector (old->features);
440 56406 : f = new_features + (f - old->features);
441 56406 : vnet_config_feature_free (f);
442 56406 : vec_delete (new_features, 1, f - new_features);
443 :
444 : /* must remove old from config_pool now as it may be expanded and change
445 : memory location if the following function find_config_with_features()
446 : adds a new config because none of existing config's has matching features
447 : and so can be reused */
448 56406 : remove_reference (cm, old);
449 56406 : new = find_config_with_features (vm, cm, new_features,
450 56406 : cm->end_node_indices_by_user_index
451 56406 : [config_string_heap_index]);
452 56406 : new->reference_count += 1;
453 :
454 56406 : vec_validate (cm->config_pool_index_by_user_index,
455 : new->config_string_heap_index + 1);
456 56406 : cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
457 56406 : = new - cm->config_pool;
458 56406 : return new->config_string_heap_index + 1;
459 : }
460 :
461 : /*
462 : * fd.io coding-style-patch-verification: ON
463 : *
464 : * Local Variables:
465 : * eval: (c-set-style "gnu")
466 : * End:
467 : */
|