LCOV - code coverage report
Current view: top level - vlib/unix - plugin.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 218 370 58.9 %
Date: 2023-07-05 22:20:52 Functions: 17 20 85.0 %

          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", &section);
     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", &section);
     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             :                                    &section);
     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 *) &reg->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 *) &reg->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 = &in;
     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             :  */

Generated by: LCOV version 1.14