Add client-side msg_name_and_crc -> msg_index table
vppapigen now generates per-message crcs. Verified that whitespace and real changes in message A don't change the crc for message B, etc. Fixed the sample and flowperpkt plugins to participate. Others need the same treatment. They don't build due to python/java language binding build issues. To use the scheme: Client connects as usual. Then call: u32 vl_api_get_msg_index(char * name_and_crc) name_and_crc is a string like: "flowperpkt_tx_interface_add_del_753301f3", aka the message name with _%08x <expected crc> appended. Try these vpp-api-test commands to play with it: vat# dump_msg_api_table <snip> [366]: punt_reply_cca27fbe [367]: ipsec_spd_dump_5e9ae88e [368]: ipsec_spd_details_6f7821b0 [369]: sample_macswap_enable_disable_0f2813e2 [370]: sample_macswap_enable_disable_reply_476738e5 [371]: flowperpkt_tx_interface_add_del_753301f3 [372]: flowperpkt_tx_interface_add_del_reply_d47e6e0b vat# get_msg_id sample_macswap_enable_disable_reply_476738e5 'sample_macswap_enable_disable_reply_476738e5' has message index 370 vat# get_msg_id sample_macswap_enable_disable_reply_476738e3 'sample_macswap_enable_disable_reply_476738e3' not found CRCs may vary, etc. vppapigen is used to build a set of JSON representations of each API file from vpp-api/Makefile.am and that is in turn used by each language binding (Java, Python, Lua). Change-Id: I3d64582e779dac5f20cddec79c562c288d8fd9c6 Signed-off-by: Dave Barach <dave@barachs.net> Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:

committed by
Damjan Marion

parent
fca670b0ec
commit
557d128b68
@ -23,7 +23,7 @@ nil
|
||||
'(setq PLUGIN-NAME (upcase plugin-name))
|
||||
"
|
||||
/*
|
||||
* " plugin-name ".c - skeleton vpp engine plug-in
|
||||
* " plugin-name ".c - skeleton vpp engine plug-in
|
||||
*
|
||||
* Copyright (c) <current-year> <your-organization>
|
||||
* Licensed under the Apache License, Version 2.0 (the \"License\");
|
||||
@ -52,18 +52,18 @@ nil
|
||||
|
||||
/* define message structures */
|
||||
#define vl_typedefs
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#undef vl_typedefs
|
||||
|
||||
/* define generated endian-swappers */
|
||||
#define vl_endianfun
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#undef vl_endianfun
|
||||
|
||||
/* instantiate all the print functions we know about */
|
||||
#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
|
||||
#define vl_printfun
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#undef vl_printfun
|
||||
|
||||
/* Get the API version number */
|
||||
@ -71,7 +71,7 @@ nil
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#undef vl_api_version
|
||||
|
||||
/*
|
||||
/*
|
||||
* A handy macro to set up a message reply.
|
||||
* Assumes that the following variables are available:
|
||||
* mp - pointer to request message
|
||||
@ -100,14 +100,14 @@ do { \\
|
||||
#define foreach_" plugin-name "_plugin_api_msg \\
|
||||
_(" PLUGIN-NAME "_ENABLE_DISABLE, " plugin-name "_enable_disable)
|
||||
|
||||
/*
|
||||
/*
|
||||
* This routine exists to convince the vlib plugin framework that
|
||||
* we haven't accidentally copied a random .dll into the plugin directory.
|
||||
*
|
||||
* Also collects global variable pointers passed from the vpp engine
|
||||
*/
|
||||
|
||||
clib_error_t *
|
||||
clib_error_t *
|
||||
vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
|
||||
int from_early_init)
|
||||
{
|
||||
@ -130,7 +130,7 @@ int " plugin-name "_enable_disable (" plugin-name "_main_t * sm, u32 sw_if_index
|
||||
int rv = 0;
|
||||
|
||||
/* Utterly wrong? */
|
||||
if (pool_is_free_index (sm->vnet_main->interface_main.sw_interfaces,
|
||||
if (pool_is_free_index (sm->vnet_main->interface_main.sw_interfaces,
|
||||
sw_if_index))
|
||||
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||
|
||||
@ -138,7 +138,7 @@ int " plugin-name "_enable_disable (" plugin-name "_main_t * sm, u32 sw_if_index
|
||||
sw = vnet_get_sw_interface (sm->vnet_main, sw_if_index);
|
||||
if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
|
||||
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
||||
|
||||
|
||||
vnet_feature_enable_disable (\"device-input\", \"" plugin-name "\",
|
||||
sw_if_index, enable_disable, 0, 0);
|
||||
|
||||
@ -153,7 +153,7 @@ static clib_error_t *
|
||||
" plugin-name "_main_t * sm = &" plugin-name "_main;
|
||||
u32 sw_if_index = ~0;
|
||||
int enable_disable = 1;
|
||||
|
||||
|
||||
int rv;
|
||||
|
||||
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
|
||||
@ -168,7 +168,7 @@ static clib_error_t *
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
return clib_error_return (0, \"Please specify an interface...\");
|
||||
|
||||
|
||||
rv = " plugin-name "_enable_disable (sm, sw_if_index, enable_disable);
|
||||
|
||||
switch(rv) {
|
||||
@ -176,7 +176,7 @@ static clib_error_t *
|
||||
break;
|
||||
|
||||
case VNET_API_ERROR_INVALID_SW_IF_INDEX:
|
||||
return clib_error_return
|
||||
return clib_error_return
|
||||
(0, \"Invalid interface, only works on physical ports\");
|
||||
break;
|
||||
|
||||
@ -193,7 +193,7 @@ static clib_error_t *
|
||||
|
||||
VLIB_CLI_COMMAND (" plugin-name "_enable_disable_command, static) = {
|
||||
.path = \"" plugin-name " enable-disable\",
|
||||
.short_help =
|
||||
.short_help =
|
||||
\"" plugin-name " enable-disable <interface-name> [disable]\",
|
||||
.function = " plugin-name "_enable_disable_command_fn,
|
||||
};
|
||||
@ -206,9 +206,9 @@ static void vl_api_" plugin-name "_enable_disable_t_handler
|
||||
" plugin-name "_main_t * sm = &" plugin-name "_main;
|
||||
int rv;
|
||||
|
||||
rv = " plugin-name "_enable_disable (sm, ntohl(mp->sw_if_index),
|
||||
rv = " plugin-name "_enable_disable (sm, ntohl(mp->sw_if_index),
|
||||
(int) (mp->enable_disable));
|
||||
|
||||
|
||||
REPLY_MACRO(VL_API_" PLUGIN-NAME "_ENABLE_DISABLE_REPLY);
|
||||
}
|
||||
|
||||
@ -224,13 +224,26 @@ static clib_error_t *
|
||||
vl_noop_handler, \\
|
||||
vl_api_##n##_t_endian, \\
|
||||
vl_api_##n##_t_print, \\
|
||||
sizeof(vl_api_##n##_t), 1);
|
||||
sizeof(vl_api_##n##_t), 1);
|
||||
foreach_" plugin-name "_plugin_api_msg;
|
||||
#undef _
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <" plugin-name "/" plugin-name "_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (" plugin-name "_main_t * sm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_" plugin-name" ;
|
||||
#undef _
|
||||
}
|
||||
|
||||
static clib_error_t * " plugin-name "_init (vlib_main_t * vm)
|
||||
{
|
||||
" plugin-name "_main_t * sm = &" plugin-name "_main;
|
||||
@ -240,7 +253,7 @@ static clib_error_t * " plugin-name "_init (vlib_main_t * vm)
|
||||
name = format (0, \"" plugin-name "_%08x%c\", api_version, 0);
|
||||
|
||||
/* Ask for a correctly-sized block of API message decode slots */
|
||||
sm->msg_id_base = vl_msg_api_get_msg_ids
|
||||
sm->msg_id_base = vl_msg_api_get_msg_ids
|
||||
((char *) name, VL_MSG_FIRST_AVAILABLE);
|
||||
|
||||
error = " plugin-name "_plugin_api_hookup (vm);
|
||||
@ -252,7 +265,7 @@ static clib_error_t * " plugin-name "_init (vlib_main_t * vm)
|
||||
|
||||
VLIB_INIT_FUNCTION (" plugin-name "_init);
|
||||
|
||||
VNET_FEATURE_INIT (" plugin-name ", static) =
|
||||
VNET_FEATURE_INIT (" plugin-name ", static) =
|
||||
{
|
||||
.arc_name = \"device-input\",
|
||||
.node_name = \"" plugin-name "\",
|
||||
|
@ -438,6 +438,19 @@ flowperpkt_plugin_api_hookup (vlib_main_t * vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <flowperpkt/flowperpkt_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (flowperpkt_main_t * fm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_flowperpkt;
|
||||
#undef _
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set up the API message handling tables
|
||||
* @param vm vlib_main_t * vlib main data structure pointer
|
||||
@ -462,6 +475,9 @@ flowperpkt_init (vlib_main_t * vm)
|
||||
/* Hook up message handlers */
|
||||
error = flowperpkt_plugin_api_hookup (vm);
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (fm, &api_main);
|
||||
|
||||
vec_free (name);
|
||||
|
||||
/* Decide how many worker threads we have */
|
||||
|
@ -176,6 +176,19 @@ ioam_export_plugin_api_hookup (vlib_main_t * vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <ioam/export/ioam_export_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (ioam_export_main_t * sm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_ioam_export;
|
||||
#undef _
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
set_ioam_export_ipfix_command_fn (vlib_main_t * vm,
|
||||
unformat_input_t * input,
|
||||
@ -247,6 +260,9 @@ ioam_export_init (vlib_main_t * vm)
|
||||
|
||||
error = ioam_export_plugin_api_hookup (vm);
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (em, &api_main);
|
||||
|
||||
/* Hook this export node to ip6-hop-by-hop */
|
||||
ip6_hbyh_node = vlib_get_node_by_name (vm, (u8 *) "ip6-hop-by-hop");
|
||||
em->my_hbh_slot = vlib_node_add_next (vm, ip6_hbyh_node->index, node_index);
|
||||
|
@ -206,6 +206,19 @@ pot_plugin_api_hookup (vlib_main_t *vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <ioam/lib-pot/pot_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (pot_main_t * sm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_pot;
|
||||
#undef _
|
||||
}
|
||||
|
||||
static clib_error_t * pot_init (vlib_main_t * vm)
|
||||
{
|
||||
pot_main_t * sm = &pot_main;
|
||||
@ -222,6 +235,9 @@ static clib_error_t * pot_init (vlib_main_t * vm)
|
||||
|
||||
error = pot_plugin_api_hookup (vm);
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (sm, &api_main);
|
||||
|
||||
vec_free(name);
|
||||
|
||||
return error;
|
||||
|
@ -178,6 +178,19 @@ trace_plugin_api_hookup (vlib_main_t * vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <ioam/lib-trace/trace_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (trace_main_t * sm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_trace;
|
||||
#undef _
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
trace_init (vlib_main_t * vm)
|
||||
{
|
||||
@ -195,6 +208,9 @@ trace_init (vlib_main_t * vm)
|
||||
|
||||
error = trace_plugin_api_hookup (vm);
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (sm, &api_main);
|
||||
|
||||
vec_free (name);
|
||||
|
||||
return error;
|
||||
|
@ -47,6 +47,19 @@ typedef enum {
|
||||
#include <lb/lb.api.h>
|
||||
#undef vl_api_version
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <lb/lb.api.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (lb_main_t * lbm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + lbm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_lb;
|
||||
#undef _
|
||||
}
|
||||
|
||||
/* Macro to finish up custom dump fns */
|
||||
#define FINISH \
|
||||
vec_add1 (s, 0); \
|
||||
@ -206,6 +219,9 @@ static clib_error_t * lb_api_init (vlib_main_t * vm)
|
||||
foreach_lb_plugin_api_msg;
|
||||
#undef _
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (lbm, &api_main);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -210,6 +210,19 @@ sample_plugin_api_hookup (vlib_main_t *vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <sample/sample_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (sample_main_t * sm, api_main_t *am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_sample;
|
||||
#undef _
|
||||
}
|
||||
|
||||
static clib_error_t * sample_init (vlib_main_t * vm)
|
||||
{
|
||||
sample_main_t * sm = &sample_main;
|
||||
@ -224,6 +237,9 @@ static clib_error_t * sample_init (vlib_main_t * vm)
|
||||
|
||||
error = sample_plugin_api_hookup (vm);
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (sm, &api_main);
|
||||
|
||||
vec_free(name);
|
||||
|
||||
return error;
|
||||
|
@ -39,8 +39,8 @@ SUFFIXES = .api.h .api
|
||||
|
||||
%.py: %.api
|
||||
$(info Creating Python binding for $@)
|
||||
$(CC) $(CPPFLAGS) -E -P -C -x c $< \
|
||||
| vppapigen --input - --python - \
|
||||
$(CC) $(CPPFLAGS) -E -P -C -x c $< \
|
||||
| vppapigen --input - --python - \
|
||||
| pyvppapigen.py --input - > $@
|
||||
|
||||
pyapidir = ${prefix}/vpp_papi_plugins
|
||||
@ -59,7 +59,8 @@ install-data-hook:
|
||||
@(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES))
|
||||
@(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES))
|
||||
|
||||
|
||||
apidir = $(prefix)/snat
|
||||
api_DATA = snat/snat.api
|
||||
|
||||
#
|
||||
# Java code generation
|
||||
|
@ -955,6 +955,19 @@ snat_plugin_api_hookup (vlib_main_t *vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <snat/snat_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (snat_main_t * sm, api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) \
|
||||
vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
|
||||
foreach_vl_msg_name_crc_snat;
|
||||
#undef _
|
||||
}
|
||||
|
||||
static void plugin_custom_dump_configure (snat_main_t * sm)
|
||||
{
|
||||
#define _(n,f) sm->api_main->msg_print_handlers \
|
||||
@ -985,6 +998,10 @@ static clib_error_t * snat_init (vlib_main_t * vm)
|
||||
sm->api_main = &api_main;
|
||||
|
||||
error = snat_plugin_api_hookup (vm);
|
||||
|
||||
/* Add our API messages to the global name_crc hash table */
|
||||
setup_message_id_table (sm, &api_main);
|
||||
|
||||
plugin_custom_dump_configure (sm);
|
||||
vec_free(name);
|
||||
|
||||
|
@ -87,11 +87,14 @@ typedef struct
|
||||
u8 **traces;
|
||||
} vl_api_trace_t;
|
||||
|
||||
typedef CLIB_PACKED (struct
|
||||
{
|
||||
u8 endian; u8 wrapped;
|
||||
u32 nitems;
|
||||
}) vl_api_trace_file_header_t;
|
||||
/* *INDENT-OFF* */
|
||||
typedef CLIB_PACKED
|
||||
(struct
|
||||
{
|
||||
u8 endian; u8 wrapped;
|
||||
u32 nitems;
|
||||
}) vl_api_trace_file_header_t;
|
||||
/* *INDENT-ON* */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -132,6 +135,8 @@ typedef struct
|
||||
struct vl_shmem_hdr_ *shmem_hdr;
|
||||
vl_api_registration_t **vl_clients;
|
||||
|
||||
u8 *serialized_message_table_in_shmem;
|
||||
|
||||
/* For plugin msg allocator */
|
||||
u16 first_available_msg_id;
|
||||
|
||||
@ -178,6 +183,9 @@ typedef struct
|
||||
|
||||
i32 vlib_signal;
|
||||
|
||||
/* client side message index hash table */
|
||||
uword *msg_index_by_name_and_crc;
|
||||
|
||||
char *region_name;
|
||||
char *root_path;
|
||||
} api_main_t;
|
||||
@ -188,6 +196,7 @@ typedef struct
|
||||
{
|
||||
int id;
|
||||
char *name;
|
||||
u32 crc;
|
||||
void *handler;
|
||||
void *cleanup;
|
||||
void *endian;
|
||||
@ -242,6 +251,8 @@ int vl_msg_api_pd_handler (void *mp, int rv);
|
||||
|
||||
void vl_msg_api_set_first_available_msg_id (u16 first_avail);
|
||||
u16 vl_msg_api_get_msg_ids (char *name, int n);
|
||||
void vl_msg_api_add_msg_name_crc (api_main_t * am, char *string, u32 id);
|
||||
u32 vl_api_get_msg_index (u8 * name_and_crc);
|
||||
|
||||
/* node_serialize.c prototypes */
|
||||
u8 *vlib_node_serialize (vlib_node_main_t * nm, u8 * vector,
|
||||
|
@ -1312,6 +1312,25 @@ vl_msg_api_get_msg_ids (char *name, int n)
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
vl_msg_api_add_msg_name_crc (api_main_t * am, char *string, u32 id)
|
||||
{
|
||||
uword *p;
|
||||
|
||||
if (am->msg_index_by_name_and_crc == 0)
|
||||
am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
|
||||
|
||||
p = hash_get_mem (am->msg_index_by_name_and_crc, string);
|
||||
if (p)
|
||||
{
|
||||
clib_warning ("attempt to redefine '%s' ignored...", string);
|
||||
return;
|
||||
}
|
||||
|
||||
hash_set_mem (am->msg_index_by_name_and_crc, string, id);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
|
@ -28,9 +28,10 @@ define memclnt_create {
|
||||
|
||||
define memclnt_create_reply {
|
||||
i32 response; /* Non-negative = success */
|
||||
u64 handle; /* handle by which vlib knows this client */
|
||||
u64 handle; /* handle by which vlib knows this client */
|
||||
u32 index; /* index, used e.g. by API trace replay */
|
||||
u32 context; /* opaque value from the create request */
|
||||
u64 message_table; /* serialized message table in shmem */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -541,28 +541,62 @@ vl_msg_api_send_shmem_nolock (unix_shared_memory_queue_t * q, u8 * elem)
|
||||
static void
|
||||
vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp)
|
||||
{
|
||||
serialize_main_t _sm, *sm = &_sm;
|
||||
api_main_t *am = &api_main;
|
||||
int rv;
|
||||
u8 *tblv;
|
||||
u32 nmsgs;
|
||||
int i;
|
||||
u8 *name_and_crc;
|
||||
u32 msg_index;
|
||||
|
||||
am->my_client_index = mp->index;
|
||||
am->my_registration = (vl_api_registration_t *) (uword) mp->handle;
|
||||
|
||||
rv = ntohl (mp->response);
|
||||
/* Clean out any previous hash table (unlikely) */
|
||||
if (am->msg_index_by_name_and_crc)
|
||||
{
|
||||
int i;
|
||||
u8 **keys = 0;
|
||||
hash_pair_t *hp;
|
||||
/* *INDENT-OFF* */
|
||||
hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
|
||||
({
|
||||
vec_add1 (keys, (u8 *) hp->key);
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
for (i = 0; i < vec_len (keys); i++)
|
||||
vec_free (keys[i]);
|
||||
vec_free (keys);
|
||||
}
|
||||
|
||||
if (rv < 0)
|
||||
clib_warning ("WARNING: API mismatch detected");
|
||||
am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
|
||||
|
||||
/* Recreate the vnet-side API message handler table */
|
||||
tblv = (u8 *) mp->message_table;
|
||||
serialize_open_vector (sm, tblv);
|
||||
unserialize_integer (sm, &nmsgs, sizeof (u32));
|
||||
|
||||
for (i = 0; i < nmsgs; i++)
|
||||
{
|
||||
msg_index = unserialize_likely_small_unsigned_integer (sm);
|
||||
unserialize_cstring (sm, (char **) &name_and_crc);
|
||||
hash_set_mem (am->msg_index_by_name_and_crc, name_and_crc, msg_index);
|
||||
}
|
||||
}
|
||||
|
||||
void vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
|
||||
__attribute__ ((weak));
|
||||
|
||||
void
|
||||
vl_client_add_api_signatures (vl_api_memclnt_create_t * mp)
|
||||
u32
|
||||
vl_api_get_msg_index (u8 * name_and_crc)
|
||||
{
|
||||
int i;
|
||||
api_main_t *am = &api_main;
|
||||
uword *p;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN (mp->api_versions); i++)
|
||||
mp->api_versions[i] = 0;
|
||||
if (am->msg_index_by_name_and_crc)
|
||||
{
|
||||
p = hash_get_mem (am->msg_index_by_name_and_crc, name_and_crc);
|
||||
if (p)
|
||||
return p[0];
|
||||
}
|
||||
return ~0;
|
||||
}
|
||||
|
||||
int
|
||||
@ -617,8 +651,6 @@ vl_client_connect (char *name, int ctx_quota, int input_queue_size)
|
||||
mp->input_queue = (uword) vl_input_queue;
|
||||
strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
|
||||
|
||||
vl_client_add_api_signatures (mp);
|
||||
|
||||
vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & mp);
|
||||
|
||||
while (1)
|
||||
|
@ -100,13 +100,28 @@ vl_msg_api_send (vl_api_registration_t * rp, u8 * elem)
|
||||
}
|
||||
}
|
||||
|
||||
int vl_msg_api_version_check (vl_api_memclnt_create_t * mp)
|
||||
__attribute__ ((weak));
|
||||
|
||||
int
|
||||
vl_msg_api_version_check (vl_api_memclnt_create_t * mp)
|
||||
u8 *
|
||||
vl_api_serialize_message_table (api_main_t * am, u8 * vector)
|
||||
{
|
||||
return 0;
|
||||
serialize_main_t _sm, *sm = &_sm;
|
||||
hash_pair_t *hp;
|
||||
u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
|
||||
|
||||
serialize_open_vector (sm, vector);
|
||||
|
||||
/* serialize the count */
|
||||
serialize_integer (sm, nmsg, sizeof (u32));
|
||||
|
||||
hash_foreach_pair (hp, am->msg_index_by_name_and_crc, (
|
||||
{
|
||||
serialize_likely_small_unsigned_integer
|
||||
(sm, hp->value[0]);
|
||||
serialize_cstring
|
||||
(sm,
|
||||
(char *) hp->key);
|
||||
}));
|
||||
|
||||
return serialize_close_vector (sm);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -120,12 +135,10 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
|
||||
vl_api_memclnt_create_reply_t *rp;
|
||||
svm_region_t *svm;
|
||||
unix_shared_memory_queue_t *q;
|
||||
int rv;
|
||||
int rv = 0;
|
||||
void *oldheap;
|
||||
api_main_t *am = &api_main;
|
||||
|
||||
/* Indicate API version mismatch if appropriate */
|
||||
rv = vl_msg_api_version_check (mp);
|
||||
u8 *serialized_message_table = 0;
|
||||
|
||||
/*
|
||||
* This is tortured. Maintain a vlib-address-space private
|
||||
@ -157,6 +170,9 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
|
||||
|
||||
svm = am->vlib_rp;
|
||||
|
||||
if (am->serialized_message_table_in_shmem == 0)
|
||||
serialized_message_table = vl_api_serialize_message_table (am, 0);
|
||||
|
||||
pthread_mutex_lock (&svm->mutex);
|
||||
oldheap = svm_push_data_heap (svm);
|
||||
*regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
|
||||
@ -171,10 +187,15 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
|
||||
|
||||
regp->name = format (0, "%s", mp->name);
|
||||
vec_add1 (regp->name, 0);
|
||||
if (serialized_message_table)
|
||||
am->serialized_message_table_in_shmem =
|
||||
vec_dup (serialized_message_table);
|
||||
|
||||
pthread_mutex_unlock (&svm->mutex);
|
||||
svm_pop_heap (oldheap);
|
||||
|
||||
vec_free (serialized_message_table);
|
||||
|
||||
rp = vl_msg_api_alloc (sizeof (*rp));
|
||||
rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_REPLY);
|
||||
rp->handle = (uword) regp;
|
||||
@ -183,6 +204,7 @@ vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
|
||||
am->shmem_hdr->application_restarts);
|
||||
rp->context = mp->context;
|
||||
rp->response = ntohl (rv);
|
||||
rp->message_table = (u64) am->serialized_message_table_in_shmem;
|
||||
|
||||
vl_msg_api_send_shmem (q, (u8 *) & rp);
|
||||
}
|
||||
|
@ -16534,6 +16534,67 @@ dump_node_table (vat_main_t * vam)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
value_sort_cmp (void *a1, void *a2)
|
||||
{
|
||||
name_sort_t *n1 = a1;
|
||||
name_sort_t *n2 = a2;
|
||||
|
||||
if (n1->value < n2->value)
|
||||
return -1;
|
||||
if (n1->value > n2->value)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_msg_api_table (vat_main_t * vam)
|
||||
{
|
||||
api_main_t *am = &api_main;
|
||||
name_sort_t *nses = 0, *ns;
|
||||
hash_pair_t *hp;
|
||||
int i;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
|
||||
({
|
||||
vec_add2 (nses, ns, 1);
|
||||
ns->name = (u8 *)(hp->key);
|
||||
ns->value = (u32) hp->value[0];
|
||||
}));
|
||||
/* *INDENT-ON* */
|
||||
|
||||
vec_sort_with_function (nses, value_sort_cmp);
|
||||
|
||||
for (i = 0; i < vec_len (nses); i++)
|
||||
fformat (vam->ofp, " [%d]: %s\n", nses[i].value, nses[i].name);
|
||||
vec_free (nses);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_msg_id (vat_main_t * vam)
|
||||
{
|
||||
u8 *name_and_crc;
|
||||
u32 message_index;
|
||||
|
||||
if (unformat (vam->input, "%s", &name_and_crc))
|
||||
{
|
||||
message_index = vl_api_get_msg_index (name_and_crc);
|
||||
if (message_index == ~0)
|
||||
{
|
||||
fformat (vam->ofp, " '%s' not found\n", name_and_crc);
|
||||
return 0;
|
||||
}
|
||||
fformat (vam->ofp, " '%s' has message index %d\n",
|
||||
name_and_crc, message_index);
|
||||
return 0;
|
||||
}
|
||||
errmsg ("name_and_crc required...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
search_node_table (vat_main_t * vam)
|
||||
{
|
||||
@ -16971,6 +17032,8 @@ _(dump_ipv6_table, "usage: dump_ipv6_table") \
|
||||
_(dump_stats_table, "usage: dump_stats_table") \
|
||||
_(dump_macro_table, "usage: dump_macro_table ") \
|
||||
_(dump_node_table, "usage: dump_node_table") \
|
||||
_(dump_msg_api_table, "usage: dump_msg_api_table") \
|
||||
_(get_msg_id, "usage: get_msg_id name_and_crc") \
|
||||
_(echo, "usage: echo <message>") \
|
||||
_(exec, "usage: exec <vpe-debug-CLI-command>") \
|
||||
_(exec_inband, "usage: exec_inband <vpe-debug-CLI-command>") \
|
||||
|
@ -1,2 +1,17 @@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
SUBDIRS = python java
|
||||
|
||||
api_json_dir = $(abs_builddir)/vpp-api
|
||||
api_srcs:=$(shell find $(prefix)/../ -name '*.api')
|
||||
api_json:=$(patsubst %.api,$(api_json_dir)/%.api.json,$(notdir $(api_srcs)))
|
||||
|
||||
define define_compile_rules
|
||||
$(api_json_dir)/%.api.json: $(1)%.api
|
||||
@echo " + Generating '$$<'"
|
||||
@mkdir -p $$(@D)
|
||||
$(CC) $$(CPPFLAGS) -E -P -C -x c $$< | vppapigen --input - --json $$@
|
||||
endef
|
||||
|
||||
$(foreach directory,$(dir $(api_srcs)),$(eval $(call define_compile_rules,$(directory))))
|
||||
|
||||
BUILT_SOURCES = $(api_json)
|
||||
|
@ -1,4 +1,4 @@
|
||||
AC_INIT(vpp-api, 1.0.0)
|
||||
AC_INIT(vpp-api, 1.1.0)
|
||||
LT_INIT
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SUBDIRS([java])
|
||||
|
@ -52,7 +52,8 @@ install-exec-local: $(srcdir)/vpp_papi/vpe.py $(srcdir)/vpp_papi/memclnt.py
|
||||
cd $(srcdir); \
|
||||
mkdir -p $(prefix)/lib/python2.7/site-packages; \
|
||||
PYTHONUSERBASE=$(prefix) \
|
||||
python setup.py build_ext -L $(prefix)/lib64 install --user
|
||||
python setup.py build_ext -L $(prefix)/lib64 \
|
||||
-I $(prefix)/../vppinfra/include/ install --user
|
||||
|
||||
#
|
||||
# Test client
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -52,7 +52,7 @@ typedef struct {
|
||||
|
||||
pneum_main_t pneum_main;
|
||||
|
||||
extern int wrap_pneum_callback(char *data, int len);
|
||||
pneum_callback_t pneum_callback;
|
||||
|
||||
/*
|
||||
* Satisfy external references when -lvlib is not available.
|
||||
@ -62,24 +62,16 @@ void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...)
|
||||
clib_warning ("vlib_cli_output called...");
|
||||
}
|
||||
|
||||
#define vl_api_version(n,v) static u32 vpe_api_version = v;
|
||||
#include <vpp-api/vpe.api.h>
|
||||
#undef vl_api_version
|
||||
void
|
||||
vl_client_add_api_signatures (vl_api_memclnt_create_t *mp)
|
||||
pneum_free (void * msg)
|
||||
{
|
||||
/*
|
||||
* Send the main API signature in slot 0. This bit of code must
|
||||
* match the checks in ../vpe/api/api.c: vl_msg_api_version_check().
|
||||
*/
|
||||
mp->api_versions[0] = clib_host_to_net_u32 (vpe_api_version);
|
||||
vl_msg_api_free (msg);
|
||||
}
|
||||
|
||||
static void
|
||||
pneum_api_handler (void *msg)
|
||||
{
|
||||
u16 id = ntohs(*((u16 *)msg));
|
||||
|
||||
if (id == VL_API_RX_THREAD_EXIT) {
|
||||
pneum_main_t *pm = &pneum_main;
|
||||
vl_msg_api_free(msg);
|
||||
@ -91,8 +83,9 @@ pneum_api_handler (void *msg)
|
||||
clib_warning("Message ID %d has wrong length: %d\n", id, l);
|
||||
|
||||
/* Call Python callback */
|
||||
(void)wrap_pneum_callback(msg, l);
|
||||
vl_msg_api_free(msg);
|
||||
ASSERT(pneum_callback);
|
||||
(pneum_callback)(msg, l);
|
||||
pneum_free(msg);
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -115,8 +108,22 @@ pneum_rx_thread_fn (void *arg)
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
uword *
|
||||
pneum_msg_table_get_hash (void)
|
||||
{
|
||||
api_main_t *am = &api_main;
|
||||
return (am->msg_index_by_name_and_crc);
|
||||
}
|
||||
|
||||
int
|
||||
pneum_connect (char * name, char * chroot_prefix)
|
||||
pneum_msg_table_size(void)
|
||||
{
|
||||
api_main_t *am = &api_main;
|
||||
return hash_elts(am->msg_index_by_name_and_crc);
|
||||
}
|
||||
|
||||
int
|
||||
pneum_connect (char * name, char * chroot_prefix, pneum_callback_t cb)
|
||||
{
|
||||
int rv = 0;
|
||||
pneum_main_t *pm = &pneum_main;
|
||||
@ -134,12 +141,15 @@ pneum_connect (char * name, char * chroot_prefix)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Start the rx queue thread */
|
||||
rv = pthread_create(&pm->rx_thread_handle, NULL, pneum_rx_thread_fn, 0);
|
||||
if (rv) {
|
||||
clib_warning("pthread_create returned %d", rv);
|
||||
vl_client_api_unmap();
|
||||
return (-1);
|
||||
if (cb) {
|
||||
/* Start the rx queue thread */
|
||||
rv = pthread_create(&pm->rx_thread_handle, NULL, pneum_rx_thread_fn, 0);
|
||||
if (rv) {
|
||||
clib_warning("pthread_create returned %d", rv);
|
||||
vl_client_api_unmap();
|
||||
return (-1);
|
||||
}
|
||||
pneum_callback = cb;
|
||||
}
|
||||
|
||||
pm->connected_to_vlib = 1;
|
||||
@ -164,6 +174,7 @@ pneum_disconnect (void)
|
||||
if (pm->connected_to_vlib) {
|
||||
vl_client_disconnect();
|
||||
vl_client_api_unmap();
|
||||
pneum_callback = 0;
|
||||
}
|
||||
memset (pm, 0, sizeof (*pm));
|
||||
|
||||
@ -175,8 +186,11 @@ pneum_read (char **p, int *l)
|
||||
{
|
||||
unix_shared_memory_queue_t *q;
|
||||
api_main_t *am = &api_main;
|
||||
pneum_main_t *pm = &pneum_main;
|
||||
uword msg;
|
||||
|
||||
if (!pm->connected_to_vlib) return -1;
|
||||
|
||||
*l = 0;
|
||||
|
||||
if (am->our_pid == 0) return (-1);
|
||||
@ -219,7 +233,9 @@ pneum_write (char *p, int l)
|
||||
api_main_t *am = &api_main;
|
||||
vl_api_header_t *mp = vl_msg_api_alloc(l);
|
||||
unix_shared_memory_queue_t *q;
|
||||
pneum_main_t *pm = &pneum_main;
|
||||
|
||||
if (!pm->connected_to_vlib) return -1;
|
||||
if (!mp) return (-1);
|
||||
memcpy(mp, p, l);
|
||||
mp->client_index = pneum_client_index();
|
||||
@ -228,7 +244,7 @@ pneum_write (char *p, int l)
|
||||
if (rv != 0) {
|
||||
printf("vpe_api_write fails: %d\n", rv);
|
||||
/* Clear message */
|
||||
vl_msg_api_free(mp);
|
||||
pneum_free(mp);
|
||||
}
|
||||
return (rv);
|
||||
}
|
||||
|
@ -15,9 +15,15 @@
|
||||
#ifndef included_pneum_h
|
||||
#define included_pneum_h
|
||||
|
||||
int pneum_connect(char * name, char * chroot_prefix);
|
||||
#include <vppinfra/types.h>
|
||||
|
||||
typedef void (*pneum_callback_t)(unsigned char * data, int len);
|
||||
int pneum_connect(char * name, char * chroot_prefix, pneum_callback_t cb);
|
||||
int pneum_disconnect(void);
|
||||
int pneum_read(char **data, int *l);
|
||||
int pneum_write(char *data, int len);
|
||||
void pneum_free(void * msg);
|
||||
uword * pneum_msg_table_get_hash (void);
|
||||
int pneum_msg_table_size(void);
|
||||
|
||||
#endif
|
||||
|
@ -76,7 +76,7 @@ int main (int argc, char ** argv)
|
||||
vl_api_show_version_t message;
|
||||
vl_api_show_version_t *mp;
|
||||
int async = 1;
|
||||
int rv = pneum_connect("pneum_client", NULL);
|
||||
int rv = pneum_connect("pneum_client", NULL, NULL);
|
||||
|
||||
if (rv != 0) {
|
||||
printf("Connect failed: %d\n", rv);
|
||||
|
@ -15,11 +15,12 @@
|
||||
|
||||
#include <Python.h>
|
||||
#include "../pneum/pneum.h"
|
||||
#include <vppinfra/hash.h>
|
||||
|
||||
static PyObject *pneum_callback = NULL;
|
||||
|
||||
int
|
||||
wrap_pneum_callback (char *data, int len)
|
||||
static void
|
||||
wrap_pneum_callback (unsigned char * data, int len)
|
||||
{
|
||||
PyGILState_STATE gstate;
|
||||
PyObject *result;//, *arglist;
|
||||
@ -38,7 +39,6 @@ wrap_pneum_callback (char *data, int len)
|
||||
PyErr_Print();
|
||||
|
||||
PyGILState_Release(gstate);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -46,22 +46,28 @@ wrap_connect (PyObject *self, PyObject *args)
|
||||
{
|
||||
char * name, * chroot_prefix = NULL;
|
||||
int rv;
|
||||
PyObject * temp;
|
||||
PyObject * temp = NULL;
|
||||
pneum_callback_t cb = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sO|s:wrap_connect", &name, &temp, &chroot_prefix))
|
||||
if (!PyArg_ParseTuple(args, "s|Os:wrap_connect",
|
||||
&name, &temp, &chroot_prefix))
|
||||
return (NULL);
|
||||
|
||||
if (!PyCallable_Check(temp)) {
|
||||
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_XINCREF(temp); /* Add a reference to new callback */
|
||||
Py_XDECREF(pneum_callback); /* Dispose of previous callback */
|
||||
pneum_callback = temp; /* Remember new callback */
|
||||
if (temp)
|
||||
{
|
||||
if (!PyCallable_Check(temp))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_XINCREF(temp); /* Add a reference to new callback */
|
||||
Py_XDECREF(pneum_callback); /* Dispose of previous callback */
|
||||
pneum_callback = temp; /* Remember new callback */
|
||||
cb = wrap_pneum_callback;
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
rv = pneum_connect(name, chroot_prefix);
|
||||
rv = pneum_connect(name, chroot_prefix, cb);
|
||||
Py_END_ALLOW_THREADS
|
||||
return PyLong_FromLong(rv);
|
||||
}
|
||||
@ -90,8 +96,6 @@ wrap_write (PyObject *self, PyObject *args)
|
||||
return PyLong_FromLong(rv);
|
||||
}
|
||||
|
||||
void vl_msg_api_free(void *);
|
||||
|
||||
static PyObject *
|
||||
wrap_read (PyObject *self, PyObject *args)
|
||||
{
|
||||
@ -110,15 +114,44 @@ wrap_read (PyObject *self, PyObject *args)
|
||||
#endif
|
||||
if (!ret) { Py_RETURN_NONE; }
|
||||
|
||||
vl_msg_api_free(data);
|
||||
pneum_free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
wrap_msg_table (PyObject *self, PyObject *args)
|
||||
{
|
||||
int i = 0, rv = 0;
|
||||
hash_pair_t *hp;
|
||||
uword *h = pneum_msg_table_get_hash();
|
||||
PyObject *ret = PyList_New(pneum_msg_table_size());
|
||||
if (!ret) goto error;
|
||||
hash_foreach_pair (hp, h,
|
||||
({
|
||||
PyObject *item = PyTuple_New(2);
|
||||
if (!item) goto error;
|
||||
rv = PyTuple_SetItem(item, 0, PyLong_FromLong((u32)hp->value[0]));
|
||||
if (rv) goto error;
|
||||
rv = PyTuple_SetItem(item, 1, PyString_FromString((char *)hp->key));
|
||||
if (rv) goto error;
|
||||
PyList_SetItem(ret, i, item);
|
||||
i++;
|
||||
}));
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
/* TODO: Raise exception */
|
||||
printf("msg_table failed");
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef vpp_api_Methods[] = {
|
||||
{"connect", wrap_connect, METH_VARARGS, "Connect to the VPP API."},
|
||||
{"disconnect", wrap_disconnect, METH_VARARGS, "Disconnect from the VPP API."},
|
||||
{"write", wrap_write, METH_VARARGS, "Write data to the VPP API."},
|
||||
{"read", wrap_read, METH_VARARGS, "Read data from the VPP API."},
|
||||
{"msg_table", wrap_msg_table, METH_VARARGS, "Get API dictionary."},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
@ -9245,6 +9245,8 @@ static void vl_api_##nn##_t_handler ( \
|
||||
vl_msg_api_free (mp); \
|
||||
}
|
||||
|
||||
static void setup_message_id_table (api_main_t * am);
|
||||
|
||||
/*
|
||||
* vpe_api_hookup
|
||||
* Add vpe's API message handlers to the table.
|
||||
@ -9252,7 +9254,6 @@ static void vl_api_##nn##_t_handler ( \
|
||||
* added the client registration handlers.
|
||||
* See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
|
||||
*/
|
||||
|
||||
static clib_error_t *
|
||||
vpe_api_hookup (vlib_main_t * vm)
|
||||
{
|
||||
@ -9306,6 +9307,11 @@ vpe_api_hookup (vlib_main_t * vm)
|
||||
am->is_mp_safe[VL_API_IP_ADD_DEL_ROUTE] = 1;
|
||||
am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;
|
||||
|
||||
/*
|
||||
* Set up the (msg_name, crc, message-id) table
|
||||
*/
|
||||
setup_message_id_table (am);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -9459,24 +9465,6 @@ get_unformat_vnet_sw_interface (void)
|
||||
return (void *) &unformat_vnet_sw_interface;
|
||||
}
|
||||
|
||||
#undef vl_api_version
|
||||
#define vl_api_version(n,v) static u32 vpe_api_version = v;
|
||||
#include <vpp-api/vpe.api.h>
|
||||
#undef vl_api_version
|
||||
|
||||
int
|
||||
vl_msg_api_version_check (vl_api_memclnt_create_t * mp)
|
||||
{
|
||||
if (clib_host_to_net_u32 (mp->api_versions[0]) != vpe_api_version)
|
||||
{
|
||||
clib_warning ("vpe API mismatch: 0x%08x instead of 0x%08x",
|
||||
clib_host_to_net_u32 (mp->api_versions[0]),
|
||||
vpe_api_version);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 *
|
||||
format_arp_event (u8 * s, va_list * args)
|
||||
{
|
||||
@ -9540,6 +9528,20 @@ VLIB_CLI_COMMAND (show_ip_arp_nd_events, static) = {
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#define vl_msg_name_crc_list
|
||||
#include <vpp-api/vpe_all_api_h.h>
|
||||
#undef vl_msg_name_crc_list
|
||||
|
||||
static void
|
||||
setup_message_id_table (api_main_t * am)
|
||||
{
|
||||
#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
|
||||
foreach_vl_msg_name_crc_memclnt;
|
||||
foreach_vl_msg_name_crc_vpe;
|
||||
#undef _
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
|
105
vppapigen/lex.c
105
vppapigen/lex.c
@ -28,7 +28,7 @@
|
||||
#include "node.h"
|
||||
#include "gram.h"
|
||||
|
||||
FILE *ifp, *ofp, *pythonfp;
|
||||
FILE *ifp, *ofp, *pythonfp, *jsonfp;
|
||||
char *vlib_app_name = "vpp";
|
||||
int dump_tree;
|
||||
time_t starttime;
|
||||
@ -36,6 +36,7 @@ char *input_filename;
|
||||
char *current_filename;
|
||||
int current_filename_allocated;
|
||||
unsigned long input_crc;
|
||||
unsigned long message_crc;
|
||||
int yydebug;
|
||||
|
||||
/*
|
||||
@ -258,6 +259,7 @@ int main (int argc, char **argv)
|
||||
int curarg = 1;
|
||||
char *ofile=0;
|
||||
char *pythonfile=0;
|
||||
char *jsonfile=0;
|
||||
char *show_name=0;
|
||||
|
||||
while (curarg < argc) {
|
||||
@ -349,6 +351,27 @@ int main (int argc, char **argv)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strncmp (argv [curarg], "--json", 6)) {
|
||||
curarg++;
|
||||
if (curarg < argc) {
|
||||
if (!strcmp(argv[curarg], "-")) {
|
||||
jsonfp = stdout;
|
||||
} else {
|
||||
jsonfp = fopen(argv[curarg], "w");
|
||||
jsonfile = argv[curarg];
|
||||
}
|
||||
if (jsonfp == NULL) {
|
||||
fprintf (stderr, "Couldn't open JSON output file %s\n",
|
||||
argv[curarg]);
|
||||
exit (1);
|
||||
}
|
||||
curarg++;
|
||||
} else {
|
||||
fprintf(stderr, "Missing filename after --json\n");
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strncmp (argv [curarg], "--app", 4)) {
|
||||
curarg++;
|
||||
if (curarg < argc) {
|
||||
@ -370,6 +393,9 @@ int main (int argc, char **argv)
|
||||
if (pythonfp == NULL) {
|
||||
pythonfile = 0;
|
||||
}
|
||||
if (jsonfp == NULL) {
|
||||
jsonfile = 0;
|
||||
}
|
||||
if (ifp == NULL) {
|
||||
fprintf(stderr, "No input file specified...\n");
|
||||
exit(1);
|
||||
@ -391,6 +417,10 @@ int main (int argc, char **argv)
|
||||
printf ("Python bindings written to %s\n", pythonfile);
|
||||
fclose (pythonfp);
|
||||
}
|
||||
if (jsonfile) {
|
||||
printf ("JSON bindings written to %s\n", jsonfile);
|
||||
fclose (jsonfp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fclose (ifp);
|
||||
@ -404,6 +434,10 @@ int main (int argc, char **argv)
|
||||
printf ("Removing %s\n", pythonfile);
|
||||
unlink (pythonfile);
|
||||
}
|
||||
if (jsonfile) {
|
||||
printf ("Removing %s\n", jsonfile);
|
||||
unlink (jsonfile);
|
||||
}
|
||||
exit (1);
|
||||
}
|
||||
exit (0);
|
||||
@ -415,7 +449,8 @@ int main (int argc, char **argv)
|
||||
static void usage (char *progname)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"usage: %s --input <filename> [--output <filename>] [--python <filename>]\n%s",
|
||||
"usage: %s --input <filename> [--output <filename>] "
|
||||
"[--json <filename>] [--python <filename>]\n%s",
|
||||
progname,
|
||||
" [--yydebug] [--dump-tree]\n");
|
||||
exit (1);
|
||||
@ -818,18 +853,18 @@ int yylex (void)
|
||||
*/
|
||||
unsigned long crc = input_crc;
|
||||
int node_type = yylex_1 ();
|
||||
unsigned long crc2 = message_crc;
|
||||
int use_helper_string = 0;
|
||||
unsigned short code;
|
||||
|
||||
switch (node_type) {
|
||||
case PRIMTYPE:
|
||||
case NAME:
|
||||
case NUMBER:
|
||||
case STRING:
|
||||
case HELPER_STRING: {
|
||||
/* We know these types accumulated token text into namebuf */
|
||||
/* HELPER_STRING may still contain C comments. Argh. */
|
||||
crc = crc_eliding_c_comments (namebuf, crc);
|
||||
case HELPER_STRING:
|
||||
use_helper_string = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Other node types have no "substate" */
|
||||
/* This code is written in this curious fashion because we
|
||||
@ -837,30 +872,25 @@ int yylex (void)
|
||||
* values a particular version of lex/bison assigned to various states.
|
||||
*/
|
||||
|
||||
/* case NAME: crc = CRC16 (crc, 257); break; */
|
||||
case RPAR: crc = CRC16 (crc, 258); break;
|
||||
case LPAR: crc = CRC16 (crc, 259); break;
|
||||
case SEMI: crc = CRC16 (crc, 260); break;
|
||||
case LBRACK: crc = CRC16 (crc, 261); break;
|
||||
case RBRACK: crc = CRC16 (crc, 262); break;
|
||||
/* case NUMBER: crc = CRC16 (crc, 263); break; */
|
||||
/* case PRIMTYPE: crc = CRC16 (crc, 264); break; */
|
||||
case BARF: crc = CRC16 (crc, 265); break;
|
||||
case TPACKED: crc = CRC16 (crc, 266); break;
|
||||
case DEFINE: crc = CRC16 (crc, 267); break;
|
||||
case LCURLY: crc = CRC16 (crc, 268); break;
|
||||
case RCURLY: crc = CRC16 (crc, 269); break;
|
||||
/* case STRING: crc = CRC16 (crc, 270); break; */
|
||||
case UNION: crc = CRC16 (crc, 271); break;
|
||||
/* case HELPER_STRING: crc = CRC16 (crc, 272); break; */
|
||||
case COMMA: crc = CRC16 (crc, 273); break;
|
||||
case NOVERSION: crc = CRC16 (crc, 274); break;
|
||||
case MANUAL_PRINT: crc = CRC16 (crc, 275); break;
|
||||
case MANUAL_ENDIAN: crc = CRC16 (crc, 276); break;
|
||||
case TYPEONLY: crc = CRC16 (crc, 278); break;
|
||||
case DONT_TRACE: crc = CRC16 (crc, 279); break;
|
||||
case RPAR: code = 258; break;
|
||||
case LPAR: code = 259; break;
|
||||
case SEMI: code = 260; break;
|
||||
case LBRACK: code = 261; break;
|
||||
case RBRACK: code = 262; break;
|
||||
case BARF: code = 265; break;
|
||||
case TPACKED: code = 266; break;
|
||||
case DEFINE: code = 267; break;
|
||||
case LCURLY: code = 268; break;
|
||||
case RCURLY: code = 269; break;
|
||||
case UNION: code = 271; break;
|
||||
case COMMA: code = 273; break;
|
||||
case NOVERSION: code = 274; break;
|
||||
case MANUAL_PRINT: code = 275; break;
|
||||
case MANUAL_ENDIAN: code = 276; break;
|
||||
case TYPEONLY: code = 278; break;
|
||||
case DONT_TRACE: code = 279; break;
|
||||
|
||||
case EOF: crc = CRC16 (crc, ~0); break; /* hysterical compatibility */
|
||||
case EOF: code = ~0; break; /* hysterical compatibility */
|
||||
|
||||
default:
|
||||
fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n",
|
||||
@ -868,11 +898,23 @@ int yylex (void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (use_helper_string)
|
||||
{
|
||||
/* We know these types accumulated token text into namebuf */
|
||||
/* HELPER_STRING may still contain C comments. Argh. */
|
||||
crc = crc_eliding_c_comments (namebuf, crc);
|
||||
crc2 = crc_eliding_c_comments (namebuf, crc2);
|
||||
} else
|
||||
{
|
||||
crc = CRC16 (crc, code);
|
||||
crc2 = CRC16 (crc2, code);
|
||||
}
|
||||
|
||||
input_crc = crc;
|
||||
message_crc = crc2;
|
||||
return (node_type);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* name_check -- see if the name we just ate
|
||||
* matches a known keyword. If so, set yylval
|
||||
@ -943,6 +985,7 @@ static int name_check (const char *s, YYSTYPE *token_value)
|
||||
return (TPACKED);
|
||||
|
||||
case NODE_DEFINE:
|
||||
message_crc = 0;
|
||||
*token_value = make_node(subclass_id);
|
||||
return(DEFINE);
|
||||
|
||||
|
@ -45,5 +45,6 @@ enum lex_state {
|
||||
#define MAXNAME 64000
|
||||
|
||||
extern unsigned long input_crc;
|
||||
extern unsigned long message_crc;
|
||||
|
||||
#endif /* _LEX_H_ */
|
||||
|
146
vppapigen/node.c
146
vppapigen/node.c
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
@ -33,6 +34,7 @@
|
||||
|
||||
FILE *ofp;
|
||||
FILE *pythonfp;
|
||||
FILE *jsonfp;
|
||||
time_t starttime;
|
||||
char *vlib_app_name;
|
||||
char *input_filename;
|
||||
@ -130,6 +132,12 @@ void primtype_recursive_generate(node_t *this, enum passid which, FILE *ofp,
|
||||
fputs("', ", pythonfp);
|
||||
break;
|
||||
|
||||
case JSON_PASS:
|
||||
fputs("[\"", jsonfp);
|
||||
fputs((char *)type_name, jsonfp);
|
||||
fputs("\", ", jsonfp);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which);
|
||||
break;
|
||||
@ -377,6 +385,24 @@ void node_define_generate (node_t *this, enum passid which, FILE *fp)
|
||||
fprintf(fp, "),\n\n");
|
||||
break;
|
||||
|
||||
case JSON_PASS:
|
||||
fprintf(fp, "[\"%s\",\n", CDATA0);
|
||||
child = this->deeper;
|
||||
indent += 4;
|
||||
while (child) {
|
||||
node_vft_t *vftp = the_vft[child->type];
|
||||
indent_me(fp);
|
||||
vftp->generate(child, which, fp);
|
||||
child = child->peer;
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
indent_me(fp);
|
||||
fprintf (fp, "{\"crc\" : \"0x%08x\"}\n", (u32)(u64)CDATA3);
|
||||
indent -= 4;
|
||||
indent_me(fp);
|
||||
fprintf(fp, "]");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "node_define_generate: unimp pass %d\n", which);
|
||||
break;
|
||||
@ -537,6 +563,10 @@ void node_scalar_generate (node_t *this, enum passid which, FILE *fp)
|
||||
fprintf(fp, "'%s'),\n", CDATA0);
|
||||
break;
|
||||
|
||||
case JSON_PASS:
|
||||
fprintf(fp, "\"%s\"]", CDATA0);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which);
|
||||
}
|
||||
@ -658,6 +688,14 @@ void node_vector_generate (node_t *this, enum passid which, FILE *fp)
|
||||
}
|
||||
break;
|
||||
|
||||
case JSON_PASS:
|
||||
if (CDATA2 != 0) { /* variable length vector */
|
||||
fprintf(fp, "\"%s\", %d, \"%s\"]", CDATA0, IDATA1, CDATA2);
|
||||
} else {
|
||||
fprintf(fp, "\"%s\", %d]", CDATA0, IDATA1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "node_vector_generate: unimp pass %d\n", which);
|
||||
}
|
||||
@ -746,6 +784,15 @@ void node_complex_generate (node_t *this, enum passid which, FILE *fp)
|
||||
}
|
||||
break;
|
||||
|
||||
case JSON_PASS:
|
||||
fprintf(fp, "[\"%s\", ", CDATA0);
|
||||
deeper = this->deeper;
|
||||
if (deeper) {
|
||||
vftp = the_vft[deeper->type];
|
||||
vftp->generate(deeper, which, fp);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "node_complex_generate unimp pass %d...\n", which);
|
||||
break;
|
||||
@ -879,6 +926,7 @@ YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2)
|
||||
|
||||
np = make_node(NODE_DEFINE);
|
||||
np->data[0] = a1;
|
||||
np->data[3] = (void *) message_crc;
|
||||
deeper((YYSTYPE)np, a2);
|
||||
return ((YYSTYPE) np);
|
||||
}
|
||||
@ -1065,15 +1113,11 @@ void generate_top_boilerplate(FILE *fp)
|
||||
fprintf (fp, " * Input file: %s\n", input_filename);
|
||||
fprintf (fp, " * Automatically generated: please edit the input file ");
|
||||
fprintf (fp, "NOT this file!\n");
|
||||
|
||||
/* Moron Acme trigger workaround */
|
||||
fprintf (fp, " * %syright (c) %s by Cisco Systems, Inc.\n", "Cop",
|
||||
&datestring[20]);
|
||||
fprintf (fp, " */\n\n");
|
||||
fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||");
|
||||
fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||");
|
||||
fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n");
|
||||
fprintf (fp, " ||defined(vl_msg_name)\n");
|
||||
fprintf (fp, " ||defined(vl_msg_name)||defined(vl_msg_name_crc_list)\n");
|
||||
fprintf (fp, "/* ok, something was selected */\n");
|
||||
fprintf (fp, "#else\n");
|
||||
fprintf (fp, "#warning no content included from %s\n", input_filename);
|
||||
@ -1141,6 +1185,37 @@ void generate_msg_names(YYSTYPE a1, FILE *fp)
|
||||
fprintf (fp, "#endif\n\n");
|
||||
}
|
||||
|
||||
void generate_msg_name_crc_list (YYSTYPE a1, FILE *fp)
|
||||
{
|
||||
node_t *np = (node_t *)a1;
|
||||
char *unique_suffix, *cp;
|
||||
|
||||
unique_suffix = sxerox(fixed_name);
|
||||
|
||||
cp = unique_suffix;
|
||||
while (*cp && (*cp != '.'))
|
||||
cp++;
|
||||
if (*cp == '.')
|
||||
*cp = 0;
|
||||
|
||||
fprintf (fp, "\n/****** Message name, crc list ******/\n\n");
|
||||
|
||||
fprintf (fp, "#ifdef vl_msg_name_crc_list\n");
|
||||
fprintf (fp, "#define foreach_vl_msg_name_crc_%s ", unique_suffix);
|
||||
|
||||
while (np) {
|
||||
if (np->type == NODE_DEFINE) {
|
||||
if (!(np->flags & NODE_FLAG_TYPEONLY)) {
|
||||
fprintf (fp, "\\\n_(VL_API_%s, %s, %08x) ",
|
||||
uppercase (np->data[0]), (i8 *) np->data[0],
|
||||
(u32)(u64)np->data[3]);
|
||||
}
|
||||
}
|
||||
np = np->peer;
|
||||
}
|
||||
fprintf (fp, "\n#endif\n\n");
|
||||
}
|
||||
|
||||
void generate_typedefs(YYSTYPE a1, FILE *fp)
|
||||
{
|
||||
node_t *np = (node_t *)a1;
|
||||
@ -1341,6 +1416,47 @@ void generate_python_msg_definitions(YYSTYPE a1, FILE *fp)
|
||||
fprintf (fp, "\n]\n");
|
||||
}
|
||||
|
||||
static bool
|
||||
is_typeonly_check(node_t *np, bool typeonly)
|
||||
{
|
||||
bool is_typeonly = (np->flags & NODE_FLAG_TYPEONLY);
|
||||
return (is_typeonly == typeonly);
|
||||
}
|
||||
|
||||
static void
|
||||
generate_json_definitions(YYSTYPE a1, FILE *fp, bool typeonly)
|
||||
{
|
||||
node_t *np = (node_t *)a1;
|
||||
node_vft_t *vftp;
|
||||
indent_me(fp);
|
||||
if (typeonly)
|
||||
fprintf (fp, "\"types\" : [\n");
|
||||
else
|
||||
fprintf (fp, "\"messages\" : [\n");
|
||||
|
||||
/* Walk the top-level node-list */
|
||||
bool comma = false;
|
||||
indent += 4;
|
||||
while (np) {
|
||||
if (np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) {
|
||||
/* Yeah, this is pedantic */
|
||||
vftp = the_vft[np->type];
|
||||
indent_me(fp);
|
||||
vftp->generate(np, JSON_PASS, fp);
|
||||
comma = true;
|
||||
}
|
||||
np = np->peer;
|
||||
if (comma && np &&
|
||||
np->type == NODE_DEFINE && is_typeonly_check(np, typeonly))
|
||||
fprintf (fp, ",\n");
|
||||
|
||||
}
|
||||
indent -= 4;
|
||||
fprintf (fp, "\n");
|
||||
indent_me(fp);
|
||||
fprintf(fp, "]");
|
||||
}
|
||||
|
||||
void generate_python_typeonly_definitions(YYSTYPE a1, FILE *fp)
|
||||
{
|
||||
node_t *np = (node_t *)a1;
|
||||
@ -1368,6 +1484,22 @@ void generate_python(YYSTYPE a1, FILE *fp)
|
||||
fprintf (fp, "vl_api_version = 0x%08x\n\n", (unsigned int)input_crc);
|
||||
}
|
||||
|
||||
void generate_json(YYSTYPE a1, FILE *fp)
|
||||
{
|
||||
fprintf (fp, "{\n");
|
||||
indent += 4;
|
||||
generate_json_definitions(a1, fp, true);
|
||||
fprintf (fp, ",\n");
|
||||
generate_json_definitions(a1, fp, false);
|
||||
|
||||
/*
|
||||
* API CRC signature
|
||||
*/
|
||||
fprintf (fp, ",\n\"vl_api_version\" :\"0x%08x\"\n",
|
||||
(unsigned int)input_crc);
|
||||
fprintf (fp, "}\n");
|
||||
}
|
||||
|
||||
void generate(YYSTYPE a1)
|
||||
{
|
||||
if (dump_tree) {
|
||||
@ -1381,6 +1513,7 @@ void generate(YYSTYPE a1)
|
||||
|
||||
generate_msg_ids(a1, ofp);
|
||||
generate_msg_names(a1, ofp);
|
||||
generate_msg_name_crc_list(a1, ofp);
|
||||
generate_typedefs(a1, ofp);
|
||||
generate_uniondefs(a1, ofp);
|
||||
generate_printfun(a1, ofp);
|
||||
@ -1391,4 +1524,7 @@ void generate(YYSTYPE a1)
|
||||
if (pythonfp) {
|
||||
generate_python(a1, pythonfp);
|
||||
}
|
||||
if (jsonfp) {
|
||||
generate_json(a1, jsonfp);
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ enum passid {
|
||||
ENDIANFUN_PASS,
|
||||
PRINTFUN_PASS,
|
||||
PYTHON_PASS,
|
||||
JSON_PASS,
|
||||
};
|
||||
|
||||
extern void *make_node (enum node_subclass type);
|
||||
@ -70,13 +71,14 @@ typedef struct node_ {
|
||||
struct node_ *peer;
|
||||
struct node_ *deeper;
|
||||
int flags;
|
||||
void *data[3];
|
||||
void *data[4];
|
||||
} node_t;
|
||||
|
||||
/* To shut up gcc-4.2.x warnings */
|
||||
#define CDATA0 ((char *)(this->data[0]))
|
||||
#define IDATA1 ((int)(uword)(this->data[1]))
|
||||
#define CDATA2 ((char *)(this->data[2]))
|
||||
#define CDATA3 ((char *)(this->data[3]))
|
||||
|
||||
#define NODE_FLAG_MANUAL_PRINT (1<<0)
|
||||
#define NODE_FLAG_MANUAL_ENDIAN (1<<1)
|
||||
|
Reference in New Issue
Block a user