dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / src / vlib / unix / plugin.c
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 <dlfcn.h>
20 #include <dirent.h>
21
22 plugin_main_t vlib_plugin_main;
23
24 void
25 vlib_set_get_handoff_structure_cb (void *cb)
26 {
27   plugin_main_t *pm = &vlib_plugin_main;
28   pm->handoff_structure_get_cb = cb;
29 }
30
31 static void *
32 vnet_get_handoff_structure (void)
33 {
34   void *(*fp) (void);
35
36   fp = vlib_plugin_main.handoff_structure_get_cb;
37   if (fp == 0)
38     return 0;
39   else
40     return (*fp) ();
41 }
42
43 static int
44 load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init)
45 {
46   void *handle, *register_handle;
47   clib_error_t *(*fp) (vlib_main_t *, void *, int);
48   clib_error_t *error;
49   void *handoff_structure;
50
51   handle = dlopen ((char *) pi->name, RTLD_LAZY);
52
53   /*
54    * 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     {
60       clib_warning ("%s", dlerror ());
61       return -1;
62     }
63
64   pi->handle = handle;
65
66
67   register_handle = dlsym (pi->handle, "vlib_plugin_register");
68   if (register_handle == 0)
69     {
70       dlclose (handle);
71       clib_warning ("Plugin missing vlib_plugin_register: %s\n",
72                     (char *) pi->name);
73       return 1;
74     }
75
76   fp = register_handle;
77
78   handoff_structure = vnet_get_handoff_structure ();
79
80   if (handoff_structure == 0)
81     error = clib_error_return (0, "handoff structure callback returned 0");
82   else
83     error = (*fp) (pm->vlib_main, handoff_structure, from_early_init);
84
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
97 static u8 **
98 split_plugin_path (plugin_main_t * pm)
99 {
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] != ':')
108         {
109           vec_add1 (this, path[i]);
110           continue;
111         }
112       vec_add1 (this, 0);
113       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
124 int
125 vlib_load_new_plugins (plugin_main_t * pm, int from_early_init)
126 {
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);
136
137   for (i = 0; i < vec_len (plugin_path); i++)
138     {
139       dp = opendir ((char *) plugin_path[i]);
140
141       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);
158
159           /* Only accept .so */
160           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         }
194       closedir (dp);
195       vec_free (plugin_path[i]);
196     }
197   vec_free (plugin_path);
198   return 0;
199 }
200
201 char *vlib_plugin_path __attribute__ ((weak));
202 char *vlib_plugin_path = "";
203 char *vlib_plugin_name_filter __attribute__ ((weak));
204 char *vlib_plugin_name_filter = 0;
205
206 int
207 vlib_plugin_early_init (vlib_main_t * vm)
208 {
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;
220
221   return vlib_load_new_plugins (pm, 1 /* from_early_init */ );
222 }
223
224 static clib_error_t *
225 vlib_plugins_show_cmd_fn (vlib_main_t * vm,
226                           unformat_input_t * input, vlib_cli_command_t * cmd)
227 {
228   plugin_main_t *pm = &vlib_plugin_main;
229   u8 *s = 0;
230   u8 *key = 0;
231   uword *value = 0;
232   int index = 1;
233
234   s = format (s, " Plugin path is: %s\n", pm->plugin_path);
235   if (vlib_plugin_name_filter)
236     s = format (s, " Plugin filter: %s\n", vlib_plugin_name_filter);
237
238   s = format (s, " Plugins loaded: \n");
239   hash_foreach_mem (key, value, pm->plugin_by_name_hash,
240                     {
241                     if (key != 0)
242                     s = format (s, "  %d.%s\n", index, key); index++;}
243   );
244
245   vlib_cli_output (vm, "%v", s);
246   vec_free (s);
247   return 0;
248 }
249
250 VLIB_CLI_COMMAND (plugins_show_cmd, static) =
251 {
252 .path = "show plugins",.short_help = "show loaded plugins",.function =
253     vlib_plugins_show_cmd_fn,};
254 /*
255  * fd.io coding-style-patch-verification: ON
256  *
257  * Local Variables:
258  * eval: (c-set-style "gnu")
259  * End:
260  */