vlib: improvement to automatic core pinning
[vpp.git] / src / vpp / api / api_main.c
1 #include "vat.h"
2 #include <dlfcn.h>
3 #include <vat/plugin.h>
4
5 vat_main_t vat_main;
6
7 void __clib_no_tail_calls
8 vat_suspend (vlib_main_t *vm, f64 interval)
9 {
10   vlib_process_suspend (vm, interval);
11 }
12
13 static u8 *
14 format_api_error (u8 * s, va_list * args)
15 {
16   vat_main_t *vam = va_arg (*args, vat_main_t *);
17   i32 error = va_arg (*args, u32);
18   uword *p;
19
20   p = hash_get (vam->error_string_by_error_number, -error);
21
22   if (p)
23     s = format (s, "%s", p[0]);
24   else
25     s = format (s, "%d", error);
26   return s;
27 }
28
29
30 static void
31 init_error_string_table (vat_main_t * vam)
32 {
33
34   vam->error_string_by_error_number = hash_create (0, sizeof (uword));
35
36 #define _(n,v,s) hash_set (vam->error_string_by_error_number, -v, s);
37   foreach_vnet_api_error;
38 #undef _
39
40   hash_set (vam->error_string_by_error_number, 99, "Misc");
41 }
42
43 #if VPP_API_TEST_BUILTIN > 0
44 static void
45 load_features (void)
46 {
47   vat_registered_features_t *f;
48   vat_main_t *vam = &vat_main;
49   clib_error_t *error;
50
51   f = vam->feature_function_registrations;
52
53   while (f)
54     {
55       error = f->function (vam);
56       if (error)
57         {
58           clib_warning ("INIT FAILED");
59         }
60       f = f->next;
61     }
62 }
63
64 clib_error_t *
65 vat_builtin_main_init (vlib_main_t * vm)
66 {
67   vat_main_t *vam = &vat_main;
68   int rv;
69   int vat_plugin_init (vat_main_t * vam);
70
71   vam->vlib_main = vm;
72   vam->my_client_index = (u32) ~ 0;
73   /* Ensure that vam->inbuf is never NULL */
74   vec_validate (vam->inbuf, 0);
75   vec_validate (vam->cmd_reply, 0);
76   vec_reset_length (vam->cmd_reply);
77   init_error_string_table (vam);
78   rv = vat_plugin_init (vam);
79   if (rv)
80     clib_warning ("vat_plugin_init returned %d", rv);
81
82   load_features ();
83
84   return 0;
85 }
86 #endif
87
88 void
89 vat_plugin_hash_create (void)
90 {
91   vat_main_t *vam = &vat_main;
92
93   vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
94   vam->function_by_name = hash_create_string (0, sizeof (uword));
95   vam->help_by_name = hash_create_string (0, sizeof (uword));
96 }
97
98 static void
99 vat_register_interface_dump (vat_main_t *vam)
100 {
101   void *handle;
102   plugin_info_t *pi;
103
104   vec_foreach (pi, vat_plugin_main.plugin_info)
105     {
106       handle = dlsym (pi->handle, "api_sw_interface_dump");
107       if (handle)
108         {
109           vam->api_sw_interface_dump = handle;
110           break;
111         }
112     }
113
114   if (!vam->api_sw_interface_dump)
115     {
116       fformat (stderr,
117                "sw_interface_dump not found in interface_test plugin!\n");
118       exit (1);
119     }
120 }
121
122 static void
123 maybe_register_api_client (vat_main_t * vam)
124 {
125   vl_api_registration_t **regpp;
126   vl_api_registration_t *regp;
127   void *oldheap;
128   api_main_t *am = vlibapi_get_main ();
129
130   if (vam->my_client_index != ~0)
131     return;
132
133   pool_get (am->vl_clients, regpp);
134
135   oldheap = vl_msg_push_heap ();
136
137   *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
138
139   regp = *regpp;
140   clib_memset (regp, 0, sizeof (*regp));
141   regp->registration_type = REGISTRATION_TYPE_SHMEM;
142   regp->vl_api_registration_pool_index = regpp - am->vl_clients;
143   regp->vlib_rp = am->vlib_rp;
144   regp->shmem_hdr = am->shmem_hdr;
145
146   /* Loopback connection */
147   regp->vl_input_queue = am->shmem_hdr->vl_input_queue;
148
149   regp->name = format (0, "%s", "vpp-internal");
150   vec_add1 (regp->name, 0);
151
152   vl_msg_pop_heap (oldheap);
153
154   vam->my_client_index = vl_msg_api_handle_from_index_and_epoch
155     (regp->vl_api_registration_pool_index,
156      am->shmem_hdr->application_restarts);
157
158   vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
159   vat_register_interface_dump (vam);
160   vam->api_sw_interface_dump (vam);
161 }
162
163 static clib_error_t *
164 api_command_fn (vlib_main_t * vm,
165                 unformat_input_t * input, vlib_cli_command_t * cmd)
166 {
167   vat_main_t *vam = &vat_main;
168   unformat_input_t _input;
169   uword c;
170   u8 *cmdp, *argsp, *this_cmd;
171   uword *p;
172   u32 arg_len;
173   int rv;
174   int (*fp) (vat_main_t *);
175
176   maybe_register_api_client (vam);
177
178   /* vec_validated in the init routine */
179   vec_set_len (vam->inbuf, 0);
180
181   vam->input = &_input;
182
183   while (((c = unformat_get_input (input)) != '\n') &&
184          (c != UNFORMAT_END_OF_INPUT))
185     vec_add1 (vam->inbuf, c);
186
187   /* Null-terminate the command */
188   vec_add1 (vam->inbuf, 0);
189
190   /* In case no args given */
191   vec_add1 (vam->inbuf, 0);
192
193   /* Split input into cmd + args */
194   this_cmd = cmdp = vam->inbuf;
195
196   /* Skip leading whitespace */
197   while (cmdp < (this_cmd + vec_len (this_cmd)))
198     {
199       if (*cmdp == ' ' || *cmdp == '\t' || *cmdp == '\n')
200         {
201           cmdp++;
202         }
203       else
204         break;
205     }
206
207   argsp = cmdp;
208
209   /* Advance past the command */
210   while (argsp < (this_cmd + vec_len (this_cmd)))
211     {
212       if (*argsp != ' ' && *argsp != '\t' && *argsp != '\n' && *argsp != 0)
213         {
214           argsp++;
215         }
216       else
217         break;
218     }
219   /* NULL terminate the command */
220   *argsp++ = 0;
221
222   /* No arguments? Ensure that argsp points to a proper (empty) string */
223   if (argsp == (this_cmd + vec_len (this_cmd) - 1))
224     argsp[0] = 0;
225   else
226     while (argsp < (this_cmd + vec_len (this_cmd)))
227       {
228         if (*argsp == ' ' || *argsp == '\t' || *argsp == '\n')
229           {
230             argsp++;
231           }
232         else
233           break;
234       }
235
236   /* Blank input line? */
237   if (*cmdp == 0)
238     return 0;
239
240   p = hash_get_mem (vam->function_by_name, cmdp);
241   if (p == 0)
242     {
243       return clib_error_return (0, "'%s': function not found\n", cmdp);
244     }
245
246   arg_len = strlen ((char *) argsp);
247
248   unformat_init_string (vam->input, (char *) argsp, arg_len);
249   fp = (void *) p[0];
250
251   rv = (*fp) (vam);
252
253   if (rv < 0)
254     {
255       unformat_free (vam->input);
256       return clib_error_return (0,
257                                 "%s error: %U\n", cmdp,
258                                 format_api_error, vam, rv);
259
260     }
261   if (vam->regenerate_interface_table)
262     {
263       vam->regenerate_interface_table = 0;
264       vam->api_sw_interface_dump (vam);
265     }
266   unformat_free (vam->input);
267   return 0;
268 }
269
270 VLIB_CLI_COMMAND (api_command, static) =
271 {
272   .path = "binary-api",
273   .short_help = "binary-api [help] <name> [<args>]",
274   .function = api_command_fn,
275   .is_mp_safe = 1,
276 };
277
278 void
279 api_cli_output (void *notused, const char *fmt, ...)
280 {
281   va_list va;
282   vat_main_t *vam = &vat_main;
283   vlib_main_t *vm = vam->vlib_main;
284   vlib_process_t *cp = vlib_get_current_process (vm);
285   u8 *s;
286
287   va_start (va, fmt);
288   s = va_format (0, fmt, &va);
289   va_end (va);
290
291   /* Terminate with \n if not present. */
292   if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
293     vec_add1 (s, '\n');
294
295   if ((!cp) || (!cp->output_function))
296     fformat (stdout, "%v", s);
297   else
298     cp->output_function (cp->output_function_arg, s, vec_len (s));
299
300   vec_free (s);
301 }
302
303 u16
304 vl_client_get_first_plugin_msg_id (const char *plugin_name)
305 {
306   api_main_t *am = vlibapi_get_main ();
307   vl_api_msg_range_t *rp;
308   uword *p;
309
310   p = hash_get_mem (am->msg_range_by_name, plugin_name);
311   if (p == 0)
312     return ~0;
313
314   rp = vec_elt_at_index (am->msg_ranges, p[0]);
315
316   return (rp->first_msg_id);
317 }
318
319 uword
320 unformat_sw_if_index (unformat_input_t * input, va_list * args)
321 {
322   void *vam_unused = va_arg (*args, void *);
323   (void) (vam_unused);
324   u32 *result = va_arg (*args, u32 *);
325   vnet_main_t *vnm = vnet_get_main ();
326   u32 sw_if_index = ~0;
327
328   if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
329     {
330       *result = sw_if_index;
331       return 1;
332     }
333   return 0;
334 }
335
336 /*
337  * fd.io coding-style-patch-verification: ON
338  *
339  * Local Variables:
340  * eval: (c-set-style "gnu")
341  * End:
342  */