Line data Source code
1 : /*
2 : * plugin.c: plugin handling
3 : *
4 : * Copyright (c) 2011 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vlib/unix/plugin.h>
19 : #include <vppinfra/elf.h>
20 : #include <dlfcn.h>
21 : #include <dirent.h>
22 :
23 : plugin_main_t vlib_plugin_main;
24 :
25 : #define PLUGIN_LOG_DBG(...) \
26 : do {vlib_log_debug (vlib_plugin_main.logger, __VA_ARGS__);} while(0)
27 : #define PLUGIN_LOG_ERR(...) \
28 : do {vlib_log_err (vlib_plugin_main.logger, __VA_ARGS__);} while(0)
29 : #define PLUGIN_LOG_NOTICE(...) \
30 : do {vlib_log_notice (vlib_plugin_main.logger, __VA_ARGS__);} while(0)
31 :
32 : char *vlib_plugin_path __attribute__ ((weak));
33 : char *vlib_plugin_path = "";
34 : char *vlib_plugin_app_version __attribute__ ((weak));
35 : char *vlib_plugin_app_version = "";
36 :
37 : void *
38 1139 : vlib_get_plugin_symbol (const char *plugin_name, const char *symbol_name)
39 : {
40 1139 : plugin_main_t *pm = &vlib_plugin_main;
41 : uword *p;
42 : plugin_info_t *pi;
43 :
44 1139 : if ((p = hash_get_mem (pm->plugin_by_name_hash, plugin_name)) == 0)
45 0 : return 0;
46 :
47 1139 : pi = vec_elt_at_index (pm->plugin_info, p[0]);
48 1139 : return dlsym (pi->handle, symbol_name);
49 : }
50 :
51 : static char *
52 85585 : str_array_to_vec (char *array, int len)
53 : {
54 85585 : char c, *r = 0;
55 85585 : int n = 0;
56 :
57 : do
58 : {
59 1190920 : c = array[n];
60 1190920 : vec_add1 (r, c);
61 : }
62 1190920 : while (c && ++n < len);
63 :
64 85585 : if (c)
65 0 : vec_add1 (r, 0);
66 :
67 85585 : return r;
68 : }
69 :
70 : static u8 *
71 0 : extract (u8 * sp, u8 * ep)
72 : {
73 0 : u8 *rv = 0;
74 :
75 0 : while (sp <= ep)
76 : {
77 0 : vec_add1 (rv, *sp);
78 0 : sp++;
79 : }
80 0 : vec_add1 (rv, 0);
81 0 : return rv;
82 : }
83 :
84 : /*
85 : * If a plugin .so contains a ".vlib_plugin_r2" section,
86 : * this function converts the vlib_plugin_r2_t to
87 : * a vlib_plugin_registration_t.
88 : */
89 :
90 : static clib_error_t *
91 0 : r2_to_reg (elf_main_t * em, vlib_plugin_r2_t * r2,
92 : vlib_plugin_registration_t * reg)
93 : {
94 : clib_error_t *error;
95 : elf_section_t *section;
96 : uword data_segment_offset;
97 : u8 *data;
98 :
99 : /* It turns out that the strings land in the ".data" section */
100 0 : error = elf_get_section_by_name (em, ".data", §ion);
101 0 : if (error)
102 0 : return error;
103 0 : data = elf_get_section_contents (em, section->index, 1);
104 :
105 : /*
106 : * Offsets in the ".vlib_plugin_r2" section
107 : * need to have the data section base subtracted from them.
108 : * The offset is in the first 8 bytes of the ".data" section
109 : */
110 :
111 0 : data_segment_offset = *((uword *) data);
112 :
113 : /* Relocate pointers, subtract data_segment_offset */
114 : #define _(a) r2->a.data_segment_offset -= data_segment_offset;
115 0 : foreach_r2_string_field;
116 : #undef _
117 :
118 0 : if (r2->version.length >= ARRAY_LEN (reg->version) - 1)
119 0 : return clib_error_return (0, "Version string too long");
120 :
121 0 : if (r2->version_required.length >= ARRAY_LEN (reg->version_required) - 1)
122 0 : return clib_error_return (0, "Version-required string too long");
123 :
124 0 : if (r2->overrides.length >= ARRAY_LEN (reg->overrides) - 1)
125 0 : return clib_error_return (0, "Override string too long");
126 :
127 : /* Compatibility with C-initializer */
128 0 : memcpy ((void *) reg->version, data + r2->version.data_segment_offset,
129 : r2->version.length);
130 0 : memcpy ((void *) reg->version_required,
131 0 : data + r2->version_required.data_segment_offset,
132 : r2->version_required.length);
133 0 : memcpy ((void *) reg->overrides, data + r2->overrides.data_segment_offset,
134 : r2->overrides.length);
135 :
136 0 : if (r2->early_init.length > 0)
137 : {
138 0 : u8 *ei = 0;
139 0 : vec_validate (ei, r2->early_init.length + 1);
140 0 : memcpy (ei, data + r2->early_init.data_segment_offset,
141 : r2->early_init.length);
142 0 : reg->early_init = (void *) ei;
143 : }
144 :
145 0 : if (r2->description.length > 0)
146 : {
147 0 : u8 *desc = 0;
148 0 : vec_validate (desc, r2->description.length + 1);
149 0 : memcpy (desc, data + r2->description.data_segment_offset,
150 : r2->description.length);
151 0 : reg->description = (void *) desc;
152 : }
153 0 : vec_free (data);
154 0 : return 0;
155 : }
156 :
157 :
158 : static int
159 46956 : load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init)
160 : {
161 : void *handle;
162 46956 : int reread_reg = 1;
163 : clib_error_t *error;
164 46956 : elf_main_t em = { 0 };
165 : elf_section_t *section;
166 : u8 *data;
167 : char *version_required;
168 : vlib_plugin_registration_t *reg;
169 : vlib_plugin_r2_t *r2;
170 46956 : plugin_config_t *pc = 0;
171 : uword *p;
172 :
173 46956 : if (elf_read_file (&em, (char *) pi->filename))
174 0 : return -1;
175 :
176 : /* New / improved (well, not really) registration structure? */
177 46956 : error = elf_get_section_by_name (&em, ".vlib_plugin_r2", §ion);
178 46956 : if (error == 0)
179 : {
180 0 : data = elf_get_section_contents (&em, section->index, 1);
181 0 : r2 = (vlib_plugin_r2_t *) data;
182 0 : reg = clib_mem_alloc (sizeof (*reg));
183 0 : memset (reg, 0, sizeof (*reg));
184 :
185 0 : reg->default_disabled = r2->default_disabled != 0;
186 0 : error = r2_to_reg (&em, r2, reg);
187 0 : if (error)
188 : {
189 0 : PLUGIN_LOG_ERR ("Bad r2 registration: %s\n", (char *) pi->name);
190 0 : return -1;
191 : }
192 0 : if (pm->plugins_default_disable)
193 0 : reg->default_disabled = 1;
194 0 : reread_reg = 0;
195 0 : goto process_reg;
196 : }
197 : else
198 46956 : clib_error_free (error);
199 :
200 46956 : error = elf_get_section_by_name (&em, ".vlib_plugin_registration",
201 : §ion);
202 46956 : if (error)
203 : {
204 0 : PLUGIN_LOG_ERR ("Not a plugin: %s\n", (char *) pi->name);
205 0 : return -1;
206 : }
207 :
208 46956 : data = elf_get_section_contents (&em, section->index, 1);
209 46956 : reg = (vlib_plugin_registration_t *) data;
210 :
211 46956 : if (vec_len (data) != sizeof (*reg))
212 : {
213 0 : PLUGIN_LOG_ERR ("vlib_plugin_registration size mismatch in plugin %s\n",
214 : (char *) pi->name);
215 0 : goto error;
216 : }
217 :
218 46956 : if (pm->plugins_default_disable)
219 0 : reg->default_disabled = 1;
220 :
221 46956 : process_reg:
222 93912 : p = hash_get_mem (pm->config_index_by_name, pi->name);
223 46956 : if (p)
224 : {
225 2265 : pc = vec_elt_at_index (pm->configs, p[0]);
226 2265 : if (pc->is_disabled)
227 : {
228 1118 : PLUGIN_LOG_NOTICE ("Plugin disabled: %s", pi->name);
229 1118 : goto error;
230 : }
231 1147 : if (reg->default_disabled && pc->is_enabled == 0)
232 : {
233 0 : PLUGIN_LOG_NOTICE ("Plugin disabled (default): %s", pi->name);
234 0 : goto error;
235 : }
236 : }
237 44691 : else if (reg->default_disabled)
238 : {
239 2766 : PLUGIN_LOG_NOTICE ("Plugin disabled (default): %s", pi->name);
240 2766 : goto error;
241 : }
242 :
243 43072 : version_required = str_array_to_vec ((char *) ®->version_required,
244 : sizeof (reg->version_required));
245 :
246 43072 : if ((strlen (version_required) > 0) &&
247 0 : (strncmp (vlib_plugin_app_version, version_required,
248 : strlen (version_required))))
249 : {
250 0 : PLUGIN_LOG_ERR ("Plugin %s version mismatch: %s != %s",
251 : pi->name, vlib_plugin_app_version,
252 : reg->version_required);
253 0 : if (!(pc && pc->skip_version_check == 1))
254 : {
255 0 : vec_free (version_required);
256 0 : goto error;
257 : }
258 : }
259 :
260 : /*
261 : * Collect names of plugins overridden (disabled) by the
262 : * current plugin.
263 : */
264 43072 : if (reg->overrides[0])
265 : {
266 0 : const char *overrides = reg->overrides;
267 : u8 *override_name_copy, *overridden_by_name_copy;
268 : u8 *sp, *ep;
269 : uword *p;
270 :
271 0 : sp = ep = (u8 *) overrides;
272 :
273 : while (1)
274 : {
275 0 : if (*sp == 0
276 0 : || (sp >= (u8 *) overrides + ARRAY_LEN (reg->overrides)))
277 : break;
278 0 : if (*sp == ' ' || *sp == ',')
279 : {
280 0 : sp++;
281 0 : continue;
282 : }
283 0 : ep = sp;
284 0 : while (*ep && *ep != ' ' && *ep != ',' &&
285 0 : ep < (u8 *) overrides + ARRAY_LEN (reg->overrides))
286 0 : ep++;
287 0 : if (*ep == ' ' || *ep == ',')
288 0 : ep--;
289 :
290 0 : override_name_copy = extract (sp, ep);
291 :
292 :
293 0 : p = hash_get_mem (pm->plugin_overrides_by_name_hash,
294 : override_name_copy);
295 : /* Already overridden... */
296 0 : if (p)
297 0 : vec_free (override_name_copy);
298 : else
299 : {
300 0 : overridden_by_name_copy = format (0, "%s%c", pi->name, 0);
301 0 : hash_set_mem (pm->plugin_overrides_by_name_hash,
302 : override_name_copy, overridden_by_name_copy);
303 : }
304 0 : sp = *ep ? ep + 1 : ep;
305 : }
306 : }
307 43072 : vec_free (version_required);
308 :
309 43072 : handle = dlopen ((char *) pi->filename,
310 43072 : RTLD_LAZY | (reg->deep_bind ? RTLD_DEEPBIND : 0));
311 :
312 43072 : if (handle == 0)
313 : {
314 559 : PLUGIN_LOG_ERR ("%s", dlerror ());
315 559 : PLUGIN_LOG_ERR ("Failed to load plugin '%s'", pi->name);
316 559 : goto error;
317 : }
318 :
319 42513 : pi->handle = handle;
320 :
321 42513 : if (reread_reg)
322 42513 : reg = dlsym (pi->handle, "vlib_plugin_registration");
323 :
324 42513 : pi->reg = reg;
325 42513 : pi->version = str_array_to_vec ((char *) ®->version,
326 : sizeof (reg->version));
327 :
328 42513 : if (reg->early_init)
329 : {
330 : clib_error_t *(*ei) (vlib_main_t *);
331 : void *h;
332 :
333 0 : h = dlsym (pi->handle, reg->early_init);
334 0 : if (h)
335 : {
336 0 : ei = h;
337 0 : error = (*ei) (pm->vlib_main);
338 0 : if (error)
339 : {
340 0 : u8 *err = format (0, "%s: %U%c", pi->name,
341 : format_clib_error, error, 0);
342 0 : PLUGIN_LOG_ERR ((char *) err);
343 0 : clib_error_free (error);
344 0 : dlclose (pi->handle);
345 0 : pi->handle = 0;
346 0 : goto error;
347 : }
348 : }
349 : else
350 0 : PLUGIN_LOG_ERR ("Plugin %s: early init function %s set but not found",
351 : (char *) pi->name, reg->early_init);
352 : }
353 :
354 42513 : if (reg->description)
355 42513 : PLUGIN_LOG_NOTICE ("Loaded plugin: %s (%s)", pi->name, reg->description);
356 : else
357 0 : PLUGIN_LOG_NOTICE ("Loaded plugin: %s", pi->name);
358 :
359 42513 : vec_free (data);
360 42513 : elf_main_free (&em);
361 42513 : return 0;
362 :
363 4443 : error:
364 4443 : vec_free (data);
365 4443 : elf_main_free (&em);
366 4443 : return -1;
367 : }
368 :
369 : static u8 **
370 559 : split_plugin_path (plugin_main_t * pm)
371 : {
372 : int i;
373 559 : u8 **rv = 0;
374 559 : u8 *path = pm->plugin_path;
375 559 : u8 *this = 0;
376 :
377 70434 : for (i = 0; i < vec_len (pm->plugin_path); i++)
378 : {
379 69875 : if (path[i] != ':')
380 : {
381 69875 : vec_add1 (this, path[i]);
382 69875 : continue;
383 : }
384 0 : vec_add1 (this, 0);
385 0 : vec_add1 (rv, this);
386 0 : this = 0;
387 : }
388 559 : if (this)
389 : {
390 559 : vec_add1 (this, 0);
391 559 : vec_add1 (rv, this);
392 : }
393 559 : return rv;
394 : }
395 :
396 : static int
397 249314 : plugin_name_sort_cmp (void *a1, void *a2)
398 : {
399 249314 : plugin_info_t *p1 = a1;
400 249314 : plugin_info_t *p2 = a2;
401 :
402 249314 : return strcmp ((char *) p1->name, (char *) p2->name);
403 : }
404 :
405 : static int
406 6623 : index_cmp (void *a1, void *a2)
407 : {
408 6623 : uword *i1 = (uword *) a1, *i2 = (uword *) a2;
409 :
410 6623 : if (*i1 < *i2)
411 6623 : return -1;
412 0 : else if (*i1 > *i2)
413 0 : return 1;
414 : else
415 0 : return 0;
416 : }
417 :
418 : int
419 559 : vlib_load_new_plugins (plugin_main_t * pm, int from_early_init)
420 : {
421 : DIR *dp;
422 : struct dirent *entry;
423 : struct stat statb;
424 : uword *p;
425 : plugin_info_t *pi;
426 : u8 **plugin_path;
427 559 : uword *not_loaded_indices = 0;
428 : int i;
429 :
430 559 : plugin_path = split_plugin_path (pm);
431 :
432 1118 : for (i = 0; i < vec_len (plugin_path); i++)
433 : {
434 559 : dp = opendir ((char *) plugin_path[i]);
435 :
436 559 : if (dp == 0)
437 0 : continue;
438 :
439 48633 : while ((entry = readdir (dp)))
440 : {
441 : u8 *plugin_name;
442 : u8 *filename;
443 :
444 48074 : if (pm->plugin_name_filter)
445 : {
446 : int j;
447 0 : for (j = 0; j < vec_len (pm->plugin_name_filter); j++)
448 0 : if (entry->d_name[j] != pm->plugin_name_filter[j])
449 0 : goto next;
450 : }
451 :
452 48074 : filename = format (0, "%s/%s%c", plugin_path[i], entry->d_name, 0);
453 :
454 : /* Only accept .so */
455 48074 : char *ext = strrchr ((const char *) filename, '.');
456 : /* unreadable */
457 95030 : if (!ext || (strcmp (ext, ".so") != 0) ||
458 46956 : stat ((char *) filename, &statb) < 0)
459 : {
460 1118 : ignore:
461 1118 : vec_free (filename);
462 1118 : continue;
463 : }
464 :
465 : /* a dir or other things which aren't plugins */
466 46956 : if (!S_ISREG (statb.st_mode))
467 0 : goto ignore;
468 :
469 46956 : plugin_name = format (0, "%s%c", entry->d_name, 0);
470 : /* Have we seen this plugin already? */
471 46956 : p = hash_get_mem (pm->plugin_by_name_hash, plugin_name);
472 46956 : if (p == 0)
473 : {
474 : /* No, add it to the plugin vector */
475 46956 : vec_add2 (pm->plugin_info, pi, 1);
476 46956 : pi->name = plugin_name;
477 46956 : pi->filename = filename;
478 46956 : pi->file_info = statb;
479 46956 : pi->handle = 0;
480 93912 : hash_set_mem (pm->plugin_by_name_hash, plugin_name,
481 : pi - pm->plugin_info);
482 : }
483 46956 : next:
484 : ;
485 : }
486 559 : closedir (dp);
487 559 : vec_free (plugin_path[i]);
488 : }
489 559 : vec_free (plugin_path);
490 :
491 :
492 : /*
493 : * Sort the plugins by name. This is important.
494 : * API traces contain absolute message numbers.
495 : * Loading plugins in directory (vs. alphabetical) order
496 : * makes trace replay incredibly fragile.
497 : */
498 559 : vec_sort_with_function (pm->plugin_info, plugin_name_sort_cmp);
499 :
500 : /*
501 : * Attempt to load the plugins
502 : */
503 47515 : for (i = 0; i < vec_len (pm->plugin_info); i++)
504 : {
505 46956 : pi = vec_elt_at_index (pm->plugin_info, i);
506 :
507 46956 : if (load_one_plugin (pm, pi, from_early_init))
508 : {
509 : /* Make a note of any which fail to load */
510 4443 : vec_add1 (not_loaded_indices, i);
511 : }
512 : }
513 :
514 : /*
515 : * Honor override list
516 : */
517 47515 : for (i = 0; i < vec_len (pm->plugin_info); i++)
518 : {
519 : uword *p;
520 :
521 46956 : pi = vec_elt_at_index (pm->plugin_info, i);
522 :
523 93912 : p = hash_get_mem (pm->plugin_overrides_by_name_hash, pi->name);
524 :
525 : /* Plugin overridden? */
526 46956 : if (p)
527 : {
528 0 : PLUGIN_LOG_NOTICE ("Plugin '%s' overridden by '%s'", pi->name,
529 : p[0]);
530 0 : vec_add1 (not_loaded_indices, i);
531 : }
532 : }
533 :
534 : /*
535 : * Sort the vector of indices to delete to avoid screwing up
536 : * the indices as we delete them.
537 : */
538 559 : vec_sort_with_function (not_loaded_indices, index_cmp);
539 :
540 : /*
541 : * Remove duplicates, which can happen if a plugin is
542 : * disabled from the command line and disabled by
543 : * a plugin which is loaded.
544 : */
545 5002 : for (i = 0; i < vec_len (not_loaded_indices); i++)
546 : {
547 4443 : if (i < vec_len (not_loaded_indices) - 1)
548 : {
549 3884 : if (not_loaded_indices[i + 1] == not_loaded_indices[i])
550 : {
551 0 : vec_delete (not_loaded_indices, 1, i);
552 0 : i--;
553 : }
554 : }
555 : }
556 :
557 : /* Remove plugin info vector elements corresponding to load failures */
558 559 : if (vec_len (not_loaded_indices) > 0)
559 : {
560 5002 : for (i = vec_len (not_loaded_indices) - 1; i >= 0; i--)
561 : {
562 4443 : pi = vec_elt_at_index (pm->plugin_info, not_loaded_indices[i]);
563 8886 : hash_unset_mem (pm->plugin_by_name_hash, pi->name);
564 4443 : if (pi->handle)
565 : {
566 0 : dlclose (pi->handle);
567 0 : PLUGIN_LOG_NOTICE ("Unloaded plugin: %s", pi->name);
568 : }
569 4443 : vec_free (pi->name);
570 4443 : vec_free (pi->filename);
571 4443 : vec_delete (pm->plugin_info, 1, not_loaded_indices[i]);
572 : }
573 559 : vec_free (not_loaded_indices);
574 : }
575 :
576 : /* Recreate the plugin name hash */
577 559 : hash_free (pm->plugin_by_name_hash);
578 559 : pm->plugin_by_name_hash = hash_create_string (0, sizeof (uword));
579 :
580 43072 : for (i = 0; i < vec_len (pm->plugin_info); i++)
581 : {
582 42513 : pi = vec_elt_at_index (pm->plugin_info, i);
583 85026 : hash_set_mem (pm->plugin_by_name_hash, pi->name, pi - pm->plugin_info);
584 : }
585 :
586 559 : return 0;
587 : }
588 :
589 : int
590 559 : vlib_plugin_early_init (vlib_main_t * vm)
591 : {
592 559 : plugin_main_t *pm = &vlib_plugin_main;
593 :
594 559 : pm->logger =
595 559 : vlib_log_register_class_rate_limit ("plugin", "load",
596 : 0x7FFFFFFF /* aka no rate limit */ );
597 :
598 559 : if (pm->plugin_path == 0)
599 559 : pm->plugin_path = format (0, "%s", vlib_plugin_path);
600 :
601 559 : if (pm->plugin_path_add)
602 0 : pm->plugin_path = format (pm->plugin_path, ":%s", pm->plugin_path_add);
603 :
604 559 : pm->plugin_path = format (pm->plugin_path, "%c", 0);
605 :
606 559 : PLUGIN_LOG_DBG ("plugin path %s", pm->plugin_path);
607 :
608 559 : pm->plugin_by_name_hash = hash_create_string (0, sizeof (uword));
609 559 : pm->plugin_overrides_by_name_hash = hash_create_string (0, sizeof (uword));
610 559 : pm->vlib_main = vm;
611 :
612 559 : return vlib_load_new_plugins (pm, 1 /* from_early_init */ );
613 : }
614 :
615 : u8 *
616 559 : vlib_get_vat_plugin_path (void)
617 : {
618 559 : plugin_main_t *pm = &vlib_plugin_main;
619 559 : return (pm->vat_plugin_path);
620 : }
621 :
622 : u8 *
623 559 : vlib_get_vat_plugin_name_filter (void)
624 : {
625 559 : plugin_main_t *pm = &vlib_plugin_main;
626 559 : return (pm->vat_plugin_name_filter);
627 : }
628 :
629 : static clib_error_t *
630 0 : vlib_plugins_show_cmd_fn (vlib_main_t * vm,
631 : unformat_input_t * input, vlib_cli_command_t * cmd)
632 : {
633 0 : plugin_main_t *pm = &vlib_plugin_main;
634 0 : u8 *s = 0;
635 0 : u8 *key = 0;
636 0 : uword value = 0;
637 0 : int index = 1;
638 : plugin_info_t *pi;
639 :
640 0 : s = format (s, " Plugin path is: %s\n\n", pm->plugin_path);
641 0 : s = format (s, " %-41s%-33s%s\n", "Plugin", "Version", "Description");
642 :
643 : /* *INDENT-OFF* */
644 0 : hash_foreach_mem (key, value, pm->plugin_by_name_hash,
645 : {
646 : if (key != 0)
647 : {
648 : pi = vec_elt_at_index (pm->plugin_info, value);
649 : s = format (s, "%3d. %-40s %-32s %s\n", index, key, pi->version,
650 : (pi->reg && pi->reg->description) ?
651 : pi->reg->description : "");
652 : index++;
653 : }
654 : });
655 : /* *INDENT-ON* */
656 :
657 0 : vlib_cli_output (vm, "%v", s);
658 0 : vec_free (s);
659 0 : return 0;
660 : }
661 :
662 : /* *INDENT-OFF* */
663 272887 : VLIB_CLI_COMMAND (plugins_show_cmd, static) =
664 : {
665 : .path = "show plugins",
666 : .short_help = "show loaded plugins",
667 : .function = vlib_plugins_show_cmd_fn,
668 : };
669 : /* *INDENT-ON* */
670 :
671 : static clib_error_t *
672 2265 : config_one_plugin (vlib_main_t * vm, char *name, unformat_input_t * input)
673 : {
674 2265 : plugin_main_t *pm = &vlib_plugin_main;
675 : plugin_config_t *pc;
676 2265 : clib_error_t *error = 0;
677 : uword *p;
678 2265 : int is_enable = 0;
679 2265 : int is_disable = 0;
680 2265 : int skip_version_check = 0;
681 :
682 2265 : if (pm->config_index_by_name == 0)
683 559 : pm->config_index_by_name = hash_create_string (0, sizeof (uword));
684 :
685 2265 : p = hash_get_mem (pm->config_index_by_name, name);
686 :
687 2265 : if (p)
688 : {
689 0 : error = clib_error_return (0, "plugin '%s' already configured", name);
690 0 : goto done;
691 : }
692 :
693 4530 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
694 : {
695 2265 : if (unformat (input, "enable"))
696 1147 : is_enable = 1;
697 1118 : else if (unformat (input, "disable"))
698 1118 : is_disable = 1;
699 0 : else if (unformat (input, "skip-version-check"))
700 0 : skip_version_check = 1;
701 : else
702 : {
703 0 : error = clib_error_return (0, "unknown input '%U'",
704 : format_unformat_error, input);
705 0 : goto done;
706 : }
707 : }
708 :
709 2265 : if (is_enable && is_disable)
710 : {
711 0 : error = clib_error_return (0, "please specify either enable or disable"
712 : " for plugin '%s'", name);
713 0 : goto done;
714 : }
715 :
716 2265 : vec_add2 (pm->configs, pc, 1);
717 4530 : hash_set_mem (pm->config_index_by_name, name, pc - pm->configs);
718 2265 : pc->is_enabled = is_enable;
719 2265 : pc->is_disabled = is_disable;
720 2265 : pc->skip_version_check = skip_version_check;
721 2265 : pc->name = name;
722 :
723 2265 : done:
724 2265 : return error;
725 : }
726 :
727 : clib_error_t *
728 559 : vlib_plugin_config (vlib_main_t * vm, unformat_input_t * input)
729 : {
730 559 : plugin_main_t *pm = &vlib_plugin_main;
731 559 : clib_error_t *error = 0;
732 : unformat_input_t in;
733 :
734 559 : unformat_init (&in, 0, 0);
735 :
736 6236 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
737 : {
738 : u8 *s, *v;
739 5677 : if (unformat (input, "%s %v", &s, &v))
740 : {
741 5677 : if (strncmp ((const char *) s, "plugins", 8) == 0)
742 : {
743 559 : if (vec_len (in.buffer) > 0)
744 0 : vec_add1 (in.buffer, ' ');
745 559 : vec_add (in.buffer, v, vec_len (v));
746 : }
747 : }
748 : else
749 : {
750 0 : error = clib_error_return (0, "unknown input '%U'",
751 : format_unformat_error, input);
752 0 : goto done;
753 : }
754 :
755 5677 : vec_free (v);
756 5677 : vec_free (s);
757 : }
758 559 : done:
759 559 : input = ∈
760 2824 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
761 : {
762 : unformat_input_t sub_input;
763 2265 : u8 *s = 0;
764 2265 : if (unformat (input, "path %s", &s))
765 0 : pm->plugin_path = s;
766 2265 : else if (unformat (input, "add-path %s", &s))
767 0 : pm->plugin_path_add = s;
768 2265 : else if (unformat (input, "name-filter %s", &s))
769 0 : pm->plugin_name_filter = s;
770 2265 : else if (unformat (input, "vat-path %s", &s))
771 0 : pm->vat_plugin_path = s;
772 2265 : else if (unformat (input, "vat-name-filter %s", &s))
773 0 : pm->vat_plugin_name_filter = s;
774 2265 : else if (unformat (input, "plugin default %U",
775 : unformat_vlib_cli_sub_input, &sub_input))
776 : {
777 0 : pm->plugins_default_disable =
778 0 : unformat (&sub_input, "disable") ? 1 : 0;
779 0 : unformat_free (&sub_input);
780 : }
781 2265 : else if (unformat (input, "plugin %s %U", &s,
782 : unformat_vlib_cli_sub_input, &sub_input))
783 : {
784 2265 : error = config_one_plugin (vm, (char *) s, &sub_input);
785 2265 : unformat_free (&sub_input);
786 2265 : if (error)
787 0 : goto done2;
788 : }
789 : else
790 : {
791 0 : error = clib_error_return (0, "unknown input '%U'",
792 : format_unformat_error, input);
793 : {
794 0 : vec_free (s);
795 0 : goto done2;
796 : }
797 : }
798 : }
799 :
800 559 : done2:
801 559 : unformat_free (&in);
802 559 : return error;
803 : }
804 :
805 : /* discard whole 'plugins' section, as it is already consumed prior to
806 : plugin load */
807 : static clib_error_t *
808 559 : plugins_config (vlib_main_t * vm, unformat_input_t * input)
809 : {
810 : u8 *junk;
811 :
812 559 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
813 : {
814 559 : if (unformat (input, "%s", &junk))
815 : {
816 559 : vec_free (junk);
817 559 : return 0;
818 : }
819 : else
820 0 : return clib_error_return (0, "unknown input '%U'",
821 : format_unformat_error, input);
822 : }
823 0 : return 0;
824 : }
825 :
826 7306 : VLIB_CONFIG_FUNCTION (plugins_config, "plugins");
827 :
828 : /*
829 : * fd.io coding-style-patch-verification: ON
830 : *
831 : * Local Variables:
832 : * eval: (c-set-style "gnu")
833 : * End:
834 : */
|