
Type: refactor Change-Id: I5235bf3e9aff58af6ba2c14e8c6529c4fc9ec86c Signed-off-by: Damjan Marion <damarion@cisco.com>
343 lines
7.0 KiB
C
343 lines
7.0 KiB
C
#include "vat.h"
|
|
#include <dlfcn.h>
|
|
#include <vat/plugin.h>
|
|
|
|
vat_main_t vat_main;
|
|
|
|
void __clib_no_tail_calls
|
|
vat_suspend (vlib_main_t *vm, f64 interval)
|
|
{
|
|
vlib_process_suspend (vm, interval);
|
|
}
|
|
|
|
static u8 *
|
|
format_api_error (u8 * s, va_list * args)
|
|
{
|
|
vat_main_t *vam = va_arg (*args, vat_main_t *);
|
|
i32 error = va_arg (*args, u32);
|
|
uword *p;
|
|
|
|
p = hash_get (vam->error_string_by_error_number, -error);
|
|
|
|
if (p)
|
|
s = format (s, "%s", p[0]);
|
|
else
|
|
s = format (s, "%d", error);
|
|
return s;
|
|
}
|
|
|
|
|
|
static void
|
|
init_error_string_table (vat_main_t * vam)
|
|
{
|
|
|
|
vam->error_string_by_error_number = hash_create (0, sizeof (uword));
|
|
|
|
#define _(n,v,s) hash_set (vam->error_string_by_error_number, -v, s);
|
|
foreach_vnet_api_error;
|
|
#undef _
|
|
|
|
hash_set (vam->error_string_by_error_number, 99, "Misc");
|
|
}
|
|
|
|
#if VPP_API_TEST_BUILTIN > 0
|
|
static void
|
|
load_features (void)
|
|
{
|
|
vat_registered_features_t *f;
|
|
vat_main_t *vam = &vat_main;
|
|
clib_error_t *error;
|
|
|
|
f = vam->feature_function_registrations;
|
|
|
|
while (f)
|
|
{
|
|
error = f->function (vam);
|
|
if (error)
|
|
{
|
|
clib_warning ("INIT FAILED");
|
|
}
|
|
f = f->next;
|
|
}
|
|
}
|
|
|
|
clib_error_t *
|
|
vat_builtin_main_init (vlib_main_t * vm)
|
|
{
|
|
vat_main_t *vam = &vat_main;
|
|
int rv;
|
|
int vat_plugin_init (vat_main_t * vam);
|
|
|
|
vam->vlib_main = vm;
|
|
vam->my_client_index = (u32) ~ 0;
|
|
/* Ensure that vam->inbuf is never NULL */
|
|
vec_validate (vam->inbuf, 0);
|
|
vec_validate (vam->cmd_reply, 0);
|
|
vec_reset_length (vam->cmd_reply);
|
|
init_error_string_table (vam);
|
|
rv = vat_plugin_init (vam);
|
|
if (rv)
|
|
clib_warning ("vat_plugin_init returned %d", rv);
|
|
|
|
load_features ();
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
vat_plugin_hash_create (void)
|
|
{
|
|
vat_main_t *vam = &vat_main;
|
|
|
|
vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword));
|
|
vam->function_by_name = hash_create_string (0, sizeof (uword));
|
|
vam->help_by_name = hash_create_string (0, sizeof (uword));
|
|
}
|
|
|
|
static void
|
|
vat_register_interface_dump (vat_main_t *vam)
|
|
{
|
|
void *handle;
|
|
plugin_info_t *pi;
|
|
|
|
vec_foreach (pi, vat_plugin_main.plugin_info)
|
|
{
|
|
handle = dlsym (pi->handle, "api_sw_interface_dump");
|
|
if (handle)
|
|
{
|
|
vam->api_sw_interface_dump = handle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!vam->api_sw_interface_dump)
|
|
{
|
|
fformat (stderr,
|
|
"sw_interface_dump not found in interface_test plugin!\n");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
maybe_register_api_client (vat_main_t * vam)
|
|
{
|
|
vl_api_registration_t **regpp;
|
|
vl_api_registration_t *regp;
|
|
void *oldheap;
|
|
api_main_t *am = vlibapi_get_main ();
|
|
|
|
if (vam->my_client_index != ~0)
|
|
return;
|
|
|
|
pool_get (am->vl_clients, regpp);
|
|
|
|
oldheap = vl_msg_push_heap ();
|
|
|
|
*regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
|
|
|
|
regp = *regpp;
|
|
clib_memset (regp, 0, sizeof (*regp));
|
|
regp->registration_type = REGISTRATION_TYPE_SHMEM;
|
|
regp->vl_api_registration_pool_index = regpp - am->vl_clients;
|
|
regp->vlib_rp = am->vlib_rp;
|
|
regp->shmem_hdr = am->shmem_hdr;
|
|
|
|
/* Loopback connection */
|
|
regp->vl_input_queue = am->shmem_hdr->vl_input_queue;
|
|
|
|
regp->name = format (0, "%s", "vpp-internal");
|
|
vec_add1 (regp->name, 0);
|
|
|
|
vl_msg_pop_heap (oldheap);
|
|
|
|
vam->my_client_index = vl_msg_api_handle_from_index_and_epoch
|
|
(regp->vl_api_registration_pool_index,
|
|
am->shmem_hdr->application_restarts);
|
|
|
|
vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
|
|
vat_register_interface_dump (vam);
|
|
vam->api_sw_interface_dump (vam);
|
|
}
|
|
|
|
static clib_error_t *
|
|
api_command_fn (vlib_main_t * vm,
|
|
unformat_input_t * input, vlib_cli_command_t * cmd)
|
|
{
|
|
vat_main_t *vam = &vat_main;
|
|
unformat_input_t _input;
|
|
uword c;
|
|
u8 *cmdp, *argsp, *this_cmd;
|
|
uword *p;
|
|
u32 arg_len;
|
|
int rv;
|
|
int (*fp) (vat_main_t *);
|
|
|
|
maybe_register_api_client (vam);
|
|
|
|
/* vec_validated in the init routine */
|
|
vec_set_len (vam->inbuf, 0);
|
|
|
|
vam->input = &_input;
|
|
|
|
while (((c = unformat_get_input (input)) != '\n') &&
|
|
(c != UNFORMAT_END_OF_INPUT))
|
|
vec_add1 (vam->inbuf, c);
|
|
|
|
/* Null-terminate the command */
|
|
vec_add1 (vam->inbuf, 0);
|
|
|
|
/* In case no args given */
|
|
vec_add1 (vam->inbuf, 0);
|
|
|
|
/* Split input into cmd + args */
|
|
this_cmd = cmdp = vam->inbuf;
|
|
|
|
/* Skip leading whitespace */
|
|
while (cmdp < (this_cmd + vec_len (this_cmd)))
|
|
{
|
|
if (*cmdp == ' ' || *cmdp == '\t' || *cmdp == '\n')
|
|
{
|
|
cmdp++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
argsp = cmdp;
|
|
|
|
/* Advance past the command */
|
|
while (argsp < (this_cmd + vec_len (this_cmd)))
|
|
{
|
|
if (*argsp != ' ' && *argsp != '\t' && *argsp != '\n' && *argsp != 0)
|
|
{
|
|
argsp++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
/* NULL terminate the command */
|
|
*argsp++ = 0;
|
|
|
|
/* No arguments? Ensure that argsp points to a proper (empty) string */
|
|
if (argsp == (this_cmd + vec_len (this_cmd) - 1))
|
|
argsp[0] = 0;
|
|
else
|
|
while (argsp < (this_cmd + vec_len (this_cmd)))
|
|
{
|
|
if (*argsp == ' ' || *argsp == '\t' || *argsp == '\n')
|
|
{
|
|
argsp++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* Blank input line? */
|
|
if (*cmdp == 0)
|
|
return 0;
|
|
|
|
p = hash_get_mem (vam->function_by_name, cmdp);
|
|
if (p == 0)
|
|
{
|
|
return clib_error_return (0, "'%s': function not found\n", cmdp);
|
|
}
|
|
|
|
arg_len = strlen ((char *) argsp);
|
|
|
|
unformat_init_string (vam->input, (char *) argsp, arg_len);
|
|
fp = (void *) p[0];
|
|
|
|
rv = (*fp) (vam);
|
|
|
|
if (rv < 0)
|
|
{
|
|
unformat_free (vam->input);
|
|
return clib_error_return (0,
|
|
"%s error: %U\n", cmdp,
|
|
format_api_error, vam, rv);
|
|
|
|
}
|
|
if (vam->regenerate_interface_table)
|
|
{
|
|
vam->regenerate_interface_table = 0;
|
|
vam->api_sw_interface_dump (vam);
|
|
}
|
|
unformat_free (vam->input);
|
|
return 0;
|
|
}
|
|
|
|
VLIB_CLI_COMMAND (api_command, static) =
|
|
{
|
|
.path = "binary-api",
|
|
.short_help = "binary-api [help] <name> [<args>]",
|
|
.function = api_command_fn,
|
|
.is_mp_safe = 1,
|
|
};
|
|
|
|
void
|
|
api_cli_output (void *notused, const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
vat_main_t *vam = &vat_main;
|
|
vlib_main_t *vm = vam->vlib_main;
|
|
vlib_process_t *cp = vlib_get_current_process (vm);
|
|
u8 *s;
|
|
|
|
va_start (va, fmt);
|
|
s = va_format (0, fmt, &va);
|
|
va_end (va);
|
|
|
|
/* Terminate with \n if not present. */
|
|
if (vec_len (s) > 0 && s[vec_len (s) - 1] != '\n')
|
|
vec_add1 (s, '\n');
|
|
|
|
if ((!cp) || (!cp->output_function))
|
|
fformat (stdout, "%v", s);
|
|
else
|
|
cp->output_function (cp->output_function_arg, s, vec_len (s));
|
|
|
|
vec_free (s);
|
|
}
|
|
|
|
u16
|
|
vl_client_get_first_plugin_msg_id (const char *plugin_name)
|
|
{
|
|
api_main_t *am = vlibapi_get_main ();
|
|
vl_api_msg_range_t *rp;
|
|
uword *p;
|
|
|
|
p = hash_get_mem (am->msg_range_by_name, plugin_name);
|
|
if (p == 0)
|
|
return ~0;
|
|
|
|
rp = vec_elt_at_index (am->msg_ranges, p[0]);
|
|
|
|
return (rp->first_msg_id);
|
|
}
|
|
|
|
uword
|
|
unformat_sw_if_index (unformat_input_t * input, va_list * args)
|
|
{
|
|
void *vam_unused = va_arg (*args, void *);
|
|
(void) (vam_unused);
|
|
u32 *result = va_arg (*args, u32 *);
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ~0;
|
|
|
|
if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
|
|
{
|
|
*result = sw_if_index;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|