blob: 4039909098364aba1dea993ea6c675dedf31db29 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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 <dlfcn.h>
20#include <dirent.h>
21
22plugin_main_t vlib_plugin_main;
23
Dave Barach9b8ffd92016-07-08 08:13:45 -040024void
25vlib_set_get_handoff_structure_cb (void *cb)
Ed Warnickecb9cada2015-12-08 15:45:58 -070026{
Dave Barach9b8ffd92016-07-08 08:13:45 -040027 plugin_main_t *pm = &vlib_plugin_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070028 pm->handoff_structure_get_cb = cb;
29}
30
Dave Barach9b8ffd92016-07-08 08:13:45 -040031static void *
32vnet_get_handoff_structure (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070033{
Dave Barach9b8ffd92016-07-08 08:13:45 -040034 void *(*fp) (void);
Ed Warnickecb9cada2015-12-08 15:45:58 -070035
36 fp = vlib_plugin_main.handoff_structure_get_cb;
37 if (fp == 0)
38 return 0;
39 else
Dave Barach9b8ffd92016-07-08 08:13:45 -040040 return (*fp) ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070041}
42
Damjan Marionf935e332017-01-06 14:33:05 +010043void *
44vlib_get_plugin_symbol (char *plugin_name, char *symbol_name)
45{
46 plugin_main_t *pm = &vlib_plugin_main;
47 uword *p;
48 plugin_info_t *pi;
49
50 if ((p = hash_get_mem (pm->plugin_by_name_hash, plugin_name)) == 0)
51 return 0;
52
53 pi = vec_elt_at_index (pm->plugin_info, p[0]);
54 return dlsym (pi->handle, symbol_name);
55}
56
Dave Barach9b8ffd92016-07-08 08:13:45 -040057static int
58load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init)
Ed Warnickecb9cada2015-12-08 15:45:58 -070059{
60 void *handle, *register_handle;
Dave Barach9b8ffd92016-07-08 08:13:45 -040061 clib_error_t *(*fp) (vlib_main_t *, void *, int);
62 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -070063 void *handoff_structure;
Ed Warnickecb9cada2015-12-08 15:45:58 -070064
Damjan Marionf935e332017-01-06 14:33:05 +010065 handle = dlopen ((char *) pi->filename, RTLD_LAZY);
Dave Barach9b8ffd92016-07-08 08:13:45 -040066
67 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -070068 * Note: this can happen if the plugin has an undefined symbol reference,
69 * so print a warning. Otherwise, the poor slob won't know what happened.
70 * Ask me how I know that...
71 */
72 if (handle == 0)
73 {
Dave Barach9b8ffd92016-07-08 08:13:45 -040074 clib_warning ("%s", dlerror ());
Ed Warnickecb9cada2015-12-08 15:45:58 -070075 return -1;
76 }
Dave Barach9b8ffd92016-07-08 08:13:45 -040077
Ed Warnickecb9cada2015-12-08 15:45:58 -070078 pi->handle = handle;
79
Ole Troan3b3688f2016-06-15 14:29:08 +020080
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 register_handle = dlsym (pi->handle, "vlib_plugin_register");
82 if (register_handle == 0)
83 {
84 dlclose (handle);
Dave Barach9b8ffd92016-07-08 08:13:45 -040085 clib_warning ("Plugin missing vlib_plugin_register: %s\n",
86 (char *) pi->name);
Ole Troan3b3688f2016-06-15 14:29:08 +020087 return 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 }
89
90 fp = register_handle;
91
Dave Barach9b8ffd92016-07-08 08:13:45 -040092 handoff_structure = vnet_get_handoff_structure ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070093
94 if (handoff_structure == 0)
95 error = clib_error_return (0, "handoff structure callback returned 0");
96 else
Dave Barach9b8ffd92016-07-08 08:13:45 -040097 error = (*fp) (pm->vlib_main, handoff_structure, from_early_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 if (error)
100 {
101 clib_error_report (error);
102 dlclose (handle);
103 return 1;
104 }
105
106 clib_warning ("Loaded plugin: %s", pi->name);
107
108 return 0;
109}
110
Dave Barach9b8ffd92016-07-08 08:13:45 -0400111static u8 **
112split_plugin_path (plugin_main_t * pm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113{
114 int i;
115 u8 **rv = 0;
116 u8 *path = pm->plugin_path;
117 u8 *this = 0;
118
119 for (i = 0; i < vec_len (pm->plugin_path); i++)
120 {
121 if (path[i] != ':')
Dave Barach9b8ffd92016-07-08 08:13:45 -0400122 {
123 vec_add1 (this, path[i]);
124 continue;
125 }
126 vec_add1 (this, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 vec_add1 (rv, this);
128 this = 0;
129 }
130 if (this)
131 {
132 vec_add1 (this, 0);
133 vec_add1 (rv, this);
134 }
135 return rv;
136}
137
Dave Barach9b8ffd92016-07-08 08:13:45 -0400138int
139vlib_load_new_plugins (plugin_main_t * pm, int from_early_init)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140{
141 DIR *dp;
142 struct dirent *entry;
143 struct stat statb;
144 uword *p;
145 plugin_info_t *pi;
146 u8 **plugin_path;
147 int i;
148
149 plugin_path = split_plugin_path (pm);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400150
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 for (i = 0; i < vec_len (plugin_path); i++)
152 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153 dp = opendir ((char *) plugin_path[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154
Dave Barach9b8ffd92016-07-08 08:13:45 -0400155 if (dp == 0)
156 continue;
157
158 while ((entry = readdir (dp)))
159 {
160 u8 *plugin_name;
Damjan Marionf935e332017-01-06 14:33:05 +0100161 u8 *filename;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400162
163 if (pm->plugin_name_filter)
164 {
165 int j;
166 for (j = 0; j < vec_len (pm->plugin_name_filter); j++)
167 if (entry->d_name[j] != pm->plugin_name_filter[j])
168 goto next;
169 }
170
Damjan Marionf935e332017-01-06 14:33:05 +0100171 filename = format (0, "%s/%s%c", plugin_path[i], entry->d_name, 0);
Ole Troan3b3688f2016-06-15 14:29:08 +0200172
173 /* Only accept .so */
Damjan Marionf935e332017-01-06 14:33:05 +0100174 char *ext = strrchr ((const char *) filename, '.');
Dave Barach9b8ffd92016-07-08 08:13:45 -0400175 /* unreadable */
176 if (!ext || (strcmp (ext, ".so") != 0) ||
Damjan Marionf935e332017-01-06 14:33:05 +0100177 stat ((char *) filename, &statb) < 0)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400178 {
179 ignore:
Damjan Marionf935e332017-01-06 14:33:05 +0100180 vec_free (filename);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400181 continue;
182 }
183
184 /* a dir or other things which aren't plugins */
185 if (!S_ISREG (statb.st_mode))
186 goto ignore;
187
Damjan Marionf935e332017-01-06 14:33:05 +0100188 plugin_name = format (0, "%s%c", entry->d_name, 0);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400189 p = hash_get_mem (pm->plugin_by_name_hash, plugin_name);
190 if (p == 0)
191 {
192 vec_add2 (pm->plugin_info, pi, 1);
193 pi->name = plugin_name;
Damjan Marionf935e332017-01-06 14:33:05 +0100194 pi->filename = filename;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400195 pi->file_info = statb;
196
197 if (load_one_plugin (pm, pi, from_early_init))
198 {
199 vec_free (plugin_name);
Damjan Marionf935e332017-01-06 14:33:05 +0100200 vec_free (filename);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400201 _vec_len (pm->plugin_info) = vec_len (pm->plugin_info) - 1;
Damjan Marionf935e332017-01-06 14:33:05 +0100202 memset (pi, 0, sizeof (*pi));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400203 continue;
204 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400205 hash_set_mem (pm->plugin_by_name_hash, plugin_name,
206 pi - pm->plugin_info);
207 }
208 next:
209 ;
210 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 closedir (dp);
212 vec_free (plugin_path[i]);
213 }
214 vec_free (plugin_path);
215 return 0;
216}
Dave Barach9b8ffd92016-07-08 08:13:45 -0400217
218char *vlib_plugin_path __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219char *vlib_plugin_path = "";
Dave Barach9b8ffd92016-07-08 08:13:45 -0400220char *vlib_plugin_name_filter __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221char *vlib_plugin_name_filter = 0;
222
Dave Barach9b8ffd92016-07-08 08:13:45 -0400223int
224vlib_plugin_early_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225{
226 plugin_main_t *pm = &vlib_plugin_main;
227
228 pm->plugin_path = format (0, "%s%c", vlib_plugin_path, 0);
229
230 clib_warning ("plugin path %s", pm->plugin_path);
231
232 if (vlib_plugin_name_filter)
233 pm->plugin_name_filter = format (0, "%s%c", vlib_plugin_name_filter, 0);
234
235 pm->plugin_by_name_hash = hash_create_string (0, sizeof (uword));
236 pm->vlib_main = vm;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400237
238 return vlib_load_new_plugins (pm, 1 /* from_early_init */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239}
Dave Barach9b8ffd92016-07-08 08:13:45 -0400240
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100241static clib_error_t *
242vlib_plugins_show_cmd_fn (vlib_main_t * vm,
Ed Warnicke853e7202016-08-12 11:42:26 -0700243 unformat_input_t * input, vlib_cli_command_t * cmd)
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100244{
245 plugin_main_t *pm = &vlib_plugin_main;
246 u8 *s = 0;
247 u8 *key = 0;
248 uword *value = 0;
249 int index = 1;
250
Ed Warnicke853e7202016-08-12 11:42:26 -0700251 s = format (s, " Plugin path is: %s\n", pm->plugin_path);
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100252 if (vlib_plugin_name_filter)
Ed Warnicke853e7202016-08-12 11:42:26 -0700253 s = format (s, " Plugin filter: %s\n", vlib_plugin_name_filter);
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100254
Ed Warnicke853e7202016-08-12 11:42:26 -0700255 s = format (s, " Plugins loaded: \n");
256 hash_foreach_mem (key, value, pm->plugin_by_name_hash,
257 {
258 if (key != 0)
259 s = format (s, " %d.%s\n", index, key); index++;}
260 );
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100261
Ed Warnicke853e7202016-08-12 11:42:26 -0700262 vlib_cli_output (vm, "%v", s);
263 vec_free (s);
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100264 return 0;
265}
266
Dave Barachfe6bdfd2017-01-20 19:50:09 -0500267/* *INDENT-OFF* */
Ed Warnicke853e7202016-08-12 11:42:26 -0700268VLIB_CLI_COMMAND (plugins_show_cmd, static) =
269{
Dave Barachfe6bdfd2017-01-20 19:50:09 -0500270 .path = "show plugins",
271 .short_help = "show loaded plugins",
272 .function = vlib_plugins_show_cmd_fn,
273};
274/* *INDENT-ON* */
275
Dave Barach9b8ffd92016-07-08 08:13:45 -0400276/*
277 * fd.io coding-style-patch-verification: ON
278 *
279 * Local Variables:
280 * eval: (c-set-style "gnu")
281 * End:
282 */