blob: f8805b803cce336d1c6ecb1694beb4ed8a892254 [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
Dave Barach9b8ffd92016-07-08 08:13:45 -040043static int
44load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init)
Ed Warnickecb9cada2015-12-08 15:45:58 -070045{
46 void *handle, *register_handle;
Dave Barach9b8ffd92016-07-08 08:13:45 -040047 clib_error_t *(*fp) (vlib_main_t *, void *, int);
48 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -070049 void *handoff_structure;
Ed Warnickecb9cada2015-12-08 15:45:58 -070050
Dave Barach9b8ffd92016-07-08 08:13:45 -040051 handle = dlopen ((char *) pi->name, RTLD_LAZY);
52
53 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -070054 * Note: this can happen if the plugin has an undefined symbol reference,
55 * so print a warning. Otherwise, the poor slob won't know what happened.
56 * Ask me how I know that...
57 */
58 if (handle == 0)
59 {
Dave Barach9b8ffd92016-07-08 08:13:45 -040060 clib_warning ("%s", dlerror ());
Ed Warnickecb9cada2015-12-08 15:45:58 -070061 return -1;
62 }
Dave Barach9b8ffd92016-07-08 08:13:45 -040063
Ed Warnickecb9cada2015-12-08 15:45:58 -070064 pi->handle = handle;
65
Ole Troan3b3688f2016-06-15 14:29:08 +020066
Ed Warnickecb9cada2015-12-08 15:45:58 -070067 register_handle = dlsym (pi->handle, "vlib_plugin_register");
68 if (register_handle == 0)
69 {
70 dlclose (handle);
Dave Barach9b8ffd92016-07-08 08:13:45 -040071 clib_warning ("Plugin missing vlib_plugin_register: %s\n",
72 (char *) pi->name);
Ole Troan3b3688f2016-06-15 14:29:08 +020073 return 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070074 }
75
76 fp = register_handle;
77
Dave Barach9b8ffd92016-07-08 08:13:45 -040078 handoff_structure = vnet_get_handoff_structure ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 if (handoff_structure == 0)
81 error = clib_error_return (0, "handoff structure callback returned 0");
82 else
Dave Barach9b8ffd92016-07-08 08:13:45 -040083 error = (*fp) (pm->vlib_main, handoff_structure, from_early_init);
Ed Warnickecb9cada2015-12-08 15:45:58 -070084
85 if (error)
86 {
87 clib_error_report (error);
88 dlclose (handle);
89 return 1;
90 }
91
92 clib_warning ("Loaded plugin: %s", pi->name);
93
94 return 0;
95}
96
Dave Barach9b8ffd92016-07-08 08:13:45 -040097static u8 **
98split_plugin_path (plugin_main_t * pm)
Ed Warnickecb9cada2015-12-08 15:45:58 -070099{
100 int i;
101 u8 **rv = 0;
102 u8 *path = pm->plugin_path;
103 u8 *this = 0;
104
105 for (i = 0; i < vec_len (pm->plugin_path); i++)
106 {
107 if (path[i] != ':')
Dave Barach9b8ffd92016-07-08 08:13:45 -0400108 {
109 vec_add1 (this, path[i]);
110 continue;
111 }
112 vec_add1 (this, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113 vec_add1 (rv, this);
114 this = 0;
115 }
116 if (this)
117 {
118 vec_add1 (this, 0);
119 vec_add1 (rv, this);
120 }
121 return rv;
122}
123
Dave Barach9b8ffd92016-07-08 08:13:45 -0400124int
125vlib_load_new_plugins (plugin_main_t * pm, int from_early_init)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126{
127 DIR *dp;
128 struct dirent *entry;
129 struct stat statb;
130 uword *p;
131 plugin_info_t *pi;
132 u8 **plugin_path;
133 int i;
134
135 plugin_path = split_plugin_path (pm);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400136
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137 for (i = 0; i < vec_len (plugin_path); i++)
138 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400139 dp = opendir ((char *) plugin_path[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140
Dave Barach9b8ffd92016-07-08 08:13:45 -0400141 if (dp == 0)
142 continue;
143
144 while ((entry = readdir (dp)))
145 {
146 u8 *plugin_name;
147
148 if (pm->plugin_name_filter)
149 {
150 int j;
151 for (j = 0; j < vec_len (pm->plugin_name_filter); j++)
152 if (entry->d_name[j] != pm->plugin_name_filter[j])
153 goto next;
154 }
155
156 plugin_name = format (0, "%s/%s%c", plugin_path[i],
157 entry->d_name, 0);
Ole Troan3b3688f2016-06-15 14:29:08 +0200158
159 /* Only accept .so */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400160 char *ext = strrchr ((const char *) plugin_name, '.');
161 /* unreadable */
162 if (!ext || (strcmp (ext, ".so") != 0) ||
163 stat ((char *) plugin_name, &statb) < 0)
164 {
165 ignore:
166 vec_free (plugin_name);
167 continue;
168 }
169
170 /* a dir or other things which aren't plugins */
171 if (!S_ISREG (statb.st_mode))
172 goto ignore;
173
174 p = hash_get_mem (pm->plugin_by_name_hash, plugin_name);
175 if (p == 0)
176 {
177 vec_add2 (pm->plugin_info, pi, 1);
178 pi->name = plugin_name;
179 pi->file_info = statb;
180
181 if (load_one_plugin (pm, pi, from_early_init))
182 {
183 vec_free (plugin_name);
184 _vec_len (pm->plugin_info) = vec_len (pm->plugin_info) - 1;
185 continue;
186 }
187 memset (pi, 0, sizeof (*pi));
188 hash_set_mem (pm->plugin_by_name_hash, plugin_name,
189 pi - pm->plugin_info);
190 }
191 next:
192 ;
193 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194 closedir (dp);
195 vec_free (plugin_path[i]);
196 }
197 vec_free (plugin_path);
198 return 0;
199}
Dave Barach9b8ffd92016-07-08 08:13:45 -0400200
201char *vlib_plugin_path __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202char *vlib_plugin_path = "";
Dave Barach9b8ffd92016-07-08 08:13:45 -0400203char *vlib_plugin_name_filter __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204char *vlib_plugin_name_filter = 0;
205
Dave Barach9b8ffd92016-07-08 08:13:45 -0400206int
207vlib_plugin_early_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208{
209 plugin_main_t *pm = &vlib_plugin_main;
210
211 pm->plugin_path = format (0, "%s%c", vlib_plugin_path, 0);
212
213 clib_warning ("plugin path %s", pm->plugin_path);
214
215 if (vlib_plugin_name_filter)
216 pm->plugin_name_filter = format (0, "%s%c", vlib_plugin_name_filter, 0);
217
218 pm->plugin_by_name_hash = hash_create_string (0, sizeof (uword));
219 pm->vlib_main = vm;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400220
221 return vlib_load_new_plugins (pm, 1 /* from_early_init */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222}
Dave Barach9b8ffd92016-07-08 08:13:45 -0400223
Shwetha Bhandarif24e5d72016-07-11 23:08:54 +0100224static clib_error_t *
225vlib_plugins_show_cmd_fn (vlib_main_t * vm,
226 unformat_input_t * input,
227 vlib_cli_command_t * cmd)
228{
229 plugin_main_t *pm = &vlib_plugin_main;
230 u8 *s = 0;
231 u8 *key = 0;
232 uword *value = 0;
233 int index = 1;
234
235 s = format(s, " Plugin path is: %s\n",pm->plugin_path);
236 if (vlib_plugin_name_filter)
237 s = format(s," Plugin filter: %s\n",vlib_plugin_name_filter);
238
239 s = format(s, " Plugins loaded: \n");
240 hash_foreach_mem (key, value, pm->plugin_by_name_hash, {
241 if (key != 0)
242 s = format(s, " %d.%s\n",index, key);
243 index++;
244 });
245
246 vlib_cli_output(vm, "%v", s);
247 vec_free(s);
248 return 0;
249}
250
251VLIB_CLI_COMMAND (plugins_show_cmd, static) = {
252 .path = "show plugins",
253 .short_help = "show loaded plugins",
254 .function = vlib_plugins_show_cmd_fn,
255};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400256/*
257 * fd.io coding-style-patch-verification: ON
258 *
259 * Local Variables:
260 * eval: (c-set-style "gnu")
261 * End:
262 */