Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : * plugin.c: plugin handling
17 : */
18 :
19 : #include <vat/vat.h>
20 : #include <vat/plugin.h>
21 : #include <dlfcn.h>
22 : #include <dirent.h>
23 :
24 : plugin_main_t vat_plugin_main;
25 :
26 : static vlib_log_class_t vat_builtin_logger;
27 :
28 : #define PLUGIN_LOG_DBG(...) \
29 : do {vlib_log_debug (vat_builtin_logger, __VA_ARGS__);} while(0)
30 : #define PLUGIN_LOG_ERR(...) \
31 : do {vlib_log_err (vat_builtin_logger, __VA_ARGS__);} while(0)
32 : #define PLUGIN_LOG_NOTICE(...) \
33 : do {vlib_log_notice (vat_builtin_logger, __VA_ARGS__);} while(0)
34 :
35 : static int
36 27025 : load_one_vat_plugin (plugin_main_t * pm, plugin_info_t * pi)
37 : {
38 : void *handle, *register_handle;
39 : clib_error_t *(*fp) (vat_main_t *);
40 : clib_error_t *error;
41 :
42 27025 : handle = dlopen ((char *) pi->filename, RTLD_LAZY);
43 :
44 : /*
45 : * Note: this can happen if the plugin has an undefined symbol reference,
46 : * so print a warning. Otherwise, the poor slob won't know what happened.
47 : * Ask me how I know that...
48 : */
49 27025 : if (handle == 0)
50 : {
51 0 : PLUGIN_LOG_ERR ("%s", dlerror ());
52 0 : return 0;
53 : }
54 :
55 27025 : pi->handle = handle;
56 :
57 27025 : register_handle = dlsym (pi->handle, "vat_plugin_register");
58 27025 : if (register_handle == 0)
59 : {
60 0 : PLUGIN_LOG_ERR ("%s: symbol vat_plugin_register not found", pi->name);
61 0 : dlclose (handle);
62 0 : return 0;
63 : }
64 :
65 27025 : fp = register_handle;
66 :
67 27025 : error = (*fp) (pm->vat_main);
68 :
69 27025 : if (error)
70 : {
71 1725 : u8 *err = format (0, "%U%c", format_clib_error, error, 0);
72 1725 : PLUGIN_LOG_ERR ((char *) err);
73 1725 : clib_error_free (error);
74 1725 : dlclose (handle);
75 1725 : pi->handle = 0;
76 1725 : return 1;
77 : }
78 :
79 25300 : PLUGIN_LOG_NOTICE ("Loaded plugin: %s", pi->name);
80 :
81 25300 : return 0;
82 : }
83 :
84 : static u8 **
85 575 : split_plugin_path (plugin_main_t * pm)
86 : {
87 : int i;
88 575 : u8 **rv = 0;
89 575 : u8 *path = pm->plugin_path;
90 575 : u8 *this = 0;
91 :
92 77625 : for (i = 0; i < vec_len (pm->plugin_path); i++)
93 : {
94 77050 : if (path[i] != ':')
95 : {
96 77050 : vec_add1 (this, path[i]);
97 77050 : continue;
98 : }
99 0 : vec_add1 (this, 0);
100 0 : vec_add1 (rv, this);
101 0 : this = 0;
102 : }
103 575 : if (this)
104 : {
105 575 : vec_add1 (this, 0);
106 575 : vec_add1 (rv, this);
107 : }
108 575 : return rv;
109 : }
110 :
111 : int
112 575 : vat_load_new_plugins (plugin_main_t * pm)
113 : {
114 : DIR *dp;
115 : struct dirent *entry;
116 : struct stat statb;
117 : uword *p;
118 : plugin_info_t *pi;
119 : u8 **plugin_path;
120 : int i;
121 :
122 575 : plugin_path = split_plugin_path (pm);
123 :
124 1150 : for (i = 0; i < vec_len (plugin_path); i++)
125 : {
126 575 : dp = opendir ((char *) plugin_path[i]);
127 :
128 575 : if (dp == 0)
129 0 : continue;
130 :
131 28750 : while ((entry = readdir (dp)))
132 : {
133 : u8 *plugin_name;
134 : u8 *file_name;
135 :
136 28175 : if (pm->plugin_name_filter)
137 : {
138 : int j;
139 0 : for (j = 0; j < vec_len (pm->plugin_name_filter); j++)
140 0 : if (entry->d_name[j] != pm->plugin_name_filter[j])
141 0 : goto next;
142 : }
143 :
144 28175 : file_name = format (0, "%s/%s%c", plugin_path[i], entry->d_name, 0);
145 28175 : plugin_name = format (0, "%s%c", entry->d_name, 0);
146 :
147 : /* unreadable */
148 28175 : if (stat ((char *) file_name, &statb) < 0)
149 : {
150 0 : ignore:
151 1150 : vec_free (file_name);
152 1150 : vec_free (plugin_name);
153 2875 : continue;
154 : }
155 :
156 : /* a dir or other things which aren't plugins */
157 28175 : if (!S_ISREG (statb.st_mode))
158 1150 : goto ignore;
159 :
160 54050 : p = hash_get_mem (pm->plugin_by_name_hash, plugin_name);
161 27025 : if (p == 0)
162 : {
163 27025 : vec_add2 (pm->plugin_info, pi, 1);
164 27025 : clib_memset (pi, 0, sizeof (*pi));
165 27025 : pi->name = plugin_name;
166 27025 : pi->filename = file_name;
167 27025 : pi->file_info = statb;
168 :
169 27025 : if (load_one_vat_plugin (pm, pi))
170 : {
171 1725 : vec_free (file_name);
172 1725 : vec_free (plugin_name);
173 1725 : vec_set_len (pm->plugin_info, vec_len (pm->plugin_info) - 1);
174 1725 : continue;
175 : }
176 50600 : hash_set_mem (pm->plugin_by_name_hash, plugin_name,
177 : pi - pm->plugin_info);
178 : }
179 25300 : next:
180 : ;
181 : }
182 575 : closedir (dp);
183 575 : vec_free (plugin_path[i]);
184 : }
185 575 : vec_free (plugin_path);
186 575 : return 0;
187 : }
188 :
189 : #define QUOTE_(x) #x
190 : #define QUOTE(x) QUOTE_(x)
191 :
192 : extern char *vat_plugin_path;
193 :
194 : char *vat_plugin_name_filter = 0;
195 :
196 : int
197 575 : vat_plugin_init (vat_main_t * vam)
198 : {
199 575 : plugin_main_t *pm = &vat_plugin_main;
200 : u8 *vlib_get_vat_plugin_path (void);
201 : u8 *vlib_get_vat_plugin_name_filter (void);
202 : u8 *plugin_path;
203 : u8 *plugin_name_filter;
204 :
205 575 : vat_builtin_logger =
206 575 : vlib_log_register_class_rate_limit ("vat-plug", "load",
207 : 0x7FFFFFFF /* aka no rate limit */ );
208 :
209 575 : plugin_path = vlib_get_vat_plugin_path ();
210 575 : plugin_name_filter = vlib_get_vat_plugin_name_filter ();
211 :
212 575 : if (plugin_path)
213 0 : vat_plugin_path = (char *) plugin_path;
214 :
215 575 : if (plugin_name_filter)
216 0 : vat_plugin_name_filter = (char *) plugin_name_filter;
217 :
218 575 : pm->plugin_path = format (0, "%s%c", vat_plugin_path, 0);
219 :
220 575 : if (vat_plugin_name_filter)
221 0 : pm->plugin_name_filter = format (0, "%s%c", vat_plugin_name_filter, 0);
222 :
223 575 : pm->plugin_by_name_hash = hash_create_string (0, sizeof (uword));
224 575 : pm->vat_main = vam;
225 :
226 575 : return vat_load_new_plugins (pm);
227 : }
228 :
229 : /*
230 : * fd.io coding-style-patch-verification: ON
231 : *
232 : * Local Variables:
233 : * eval: (c-set-style "gnu")
234 : * End:
235 : */
|