aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2016-02-19 09:06:23 -0500
committerDave Barach <dave@barachs.net>2016-02-19 09:06:46 -0500
commitb44e9bc90b634b07d5f93a731a95028adc73bcbc (patch)
treeba6477830970b8cb663ad2c393cdca778418fb13
parentc07bf5d5032e2b3ed4a651c8e6b8ff2131bc79c6 (diff)
Serialize and upload the data plane node graph
Include node names and graph arcs. Prep work for uploading node runtime data, so the latter can be reported in a comprehensible manner. Change-Id: I215b1f8cff244200c37c7e088f1f22229dc97eb6 Signed-off-by: Dave Barach <dave@barachs.net>
-rw-r--r--vlib-api/Makefile.am3
-rw-r--r--vlib-api/vlibapi/api.h4
-rw-r--r--vlib-api/vlibapi/node_serialize.c141
-rw-r--r--vpp-api-test/vat/api_format.c193
-rw-r--r--vpp-api-test/vat/vat.h5
-rw-r--r--vpp/api/api.c32
-rw-r--r--vpp/api/vpe.api25
7 files changed, 398 insertions, 5 deletions
diff --git a/vlib-api/Makefile.am b/vlib-api/Makefile.am
index f72d23aa72e..a1fab44c687 100644
--- a/vlib-api/Makefile.am
+++ b/vlib-api/Makefile.am
@@ -20,7 +20,8 @@ lib_LTLIBRARIES = libvlibapi.la libvlibmemory.la libvlibmemoryclient.la \
libvlibapi_la_SOURCES = \
vlibapi/api.h \
- vlibapi/api_shared.c
+ vlibapi/api_shared.c \
+ vlibapi/node_serialize.c
nobase_include_HEADERS = vlibapi/api.h
diff --git a/vlib-api/vlibapi/api.h b/vlib-api/vlibapi/api.h
index f620d950d8e..1f45a05738c 100644
--- a/vlib-api/vlibapi/api.h
+++ b/vlib-api/vlibapi/api.h
@@ -215,6 +215,10 @@ 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);
+/* node_serialize.c prototypes */
+u8 * vlib_node_serialize (vlib_node_main_t *nm, u8 * vector);
+vlib_node_t ** vlib_node_unserialize (u8 * vector);
+
#define VLIB_API_INIT_FUNCTION(x) VLIB_DECLARE_INIT_FUNCTION(x,api_init)
#endif /* included_api_h */
diff --git a/vlib-api/vlibapi/node_serialize.c b/vlib-api/vlibapi/node_serialize.c
new file mode 100644
index 00000000000..d4fbd502398
--- /dev/null
+++ b/vlib-api/vlibapi/node_serialize.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <vlib/vlib.h>
+
+#include <vppinfra/serialize.h>
+
+/*
+ * Serialize a vlib_node_main_t. Appends the result to vector.
+ * Pass 0 to create a new vector, use vec_reset_length(vector)
+ * to recycle a vector / avoid memory allocation, etc.
+ * Switch heaps before/after to serialize into API client shared memory.
+ */
+
+u8 * vlib_node_serialize (vlib_node_main_t *nm, u8 * vector)
+{
+ serialize_main_t _sm, *sm=&_sm;
+ vlib_node_t * node;
+ int i, j;
+ u8 * cstemp = 0;
+
+ serialize_open_vector (sm, vector);
+
+ serialize_likely_small_unsigned_integer (sm, vec_len(nm->nodes));
+ for (i = 0; i < vec_len (nm->nodes); i++)
+ {
+ node = nm->nodes[i];
+ vec_reset_length (cstemp);
+ cstemp = vec_dup(node->name);
+ vec_add1(cstemp, 0);
+ serialize_cstring (sm, (char *)cstemp);
+ serialize_likely_small_unsigned_integer (sm, vec_len(node->next_nodes));
+ for (j = 0; j < vec_len (node->next_nodes); j++)
+ serialize_likely_small_unsigned_integer (sm, node->next_nodes[j]);
+ }
+ vec_free(cstemp);
+
+ return (serialize_close_vector (sm));
+}
+
+vlib_node_t ** vlib_node_unserialize (u8 * vector)
+{
+ serialize_main_t _sm, *sm=&_sm;
+ u32 nnodes, nnexts;
+ vlib_node_t * node;
+ vlib_node_t ** nodes = 0;
+ int i, j;
+
+ serialize_open_vector (sm, vector);
+
+ nnodes = unserialize_likely_small_unsigned_integer (sm);
+
+ vec_validate (nodes, nnodes-1);
+
+ for (i = 0; i < nnodes; i++)
+ {
+ node = 0;
+ vec_validate (node,0);
+ nodes[i] = node;
+ unserialize_cstring (sm, (char **)&node->name);
+
+ nnexts = unserialize_likely_small_unsigned_integer (sm);
+ if (nnexts > 0)
+ vec_validate (node->next_nodes, nnexts-1);
+ for (j = 0; j < vec_len (node->next_nodes); j++)
+ node->next_nodes[j] =
+ unserialize_likely_small_unsigned_integer (sm);
+ }
+ return nodes;
+}
+
+
+#if CLIB_DEBUG > 0
+
+static clib_error_t *
+test_node_serialize_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vlib_node_main_t * nm = &vm->node_main;
+ u8 * vector = 0;
+ vlib_node_t ** nodes;
+ vlib_node_t * node;
+ vlib_node_t * next_node;
+ int i, j;
+
+ /*
+ * Keep the number of memcpy ops to a minimum (e.g. 1).
+ * The current size of the serialized vector is
+ * slightly under 4K.
+ */
+ vec_validate (vector, 4095);
+ vec_reset_length (vector);
+
+ vector = vlib_node_serialize (nm, vector);
+
+ nodes = vlib_node_unserialize (vector);
+
+ vec_free (vector);
+
+ for (i = 0; i < vec_len(nodes); i++)
+ {
+ node = nodes[i];
+
+ vlib_cli_output (vm, "[%d] %s", i, node->name);
+ for (j = 0; j < vec_len (node->next_nodes); j++)
+ {
+ if (node->next_nodes[j] != ~0)
+ next_node = nodes[node->next_nodes[j]];
+ vlib_cli_output (vm, " [%d] %s", j, next_node->name);
+ }
+ }
+
+ for (i = 0; i < vec_len(nodes); i++)
+ {
+ vec_free (nodes[i]->name);
+ vec_free (nodes[i]->next_nodes);
+ vec_free (nodes[i]);
+ }
+ vec_free(nodes);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (test_node_serialize_node, static) = {
+ .path = "test node serialize",
+ .short_help = "test node serialize",
+ .function = test_node_serialize_command_fn,
+};
+#endif
diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c
index 4283586e307..13b2c0d64b9 100644
--- a/vpp-api-test/vat/api_format.c
+++ b/vpp-api-test/vat/api_format.c
@@ -635,10 +635,23 @@ static void vl_api_cli_reply_t_handler_json
{
vat_main_t * vam = &vat_main;
vat_json_node_t node;
+ api_main_t * am = &api_main;
+ void * oldheap;
+ u8 * reply;
vat_json_init_object(&node);
vat_json_object_add_int(&node, "retval", ntohl(mp->retval));
- vat_json_object_add_uint(&node, "reply_in_shmem", ntohl(mp->reply_in_shmem));
+ vat_json_object_add_uint(&node, "reply_in_shmem",
+ ntohl(mp->reply_in_shmem));
+ /* Toss the shared-memory original... */
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ reply = (u8 *)(mp->reply_in_shmem);
+ vec_free (reply);
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
vat_json_print(vam->ofp, &node);
vat_json_free(&node);
@@ -1723,6 +1736,94 @@ static void vl_api_get_first_msg_id_reply_t_handler_json
vam->result_ready = 1;
}
+static void vl_api_get_node_graph_reply_t_handler
+(vl_api_get_node_graph_reply_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ api_main_t * am = &api_main;
+ i32 retval = ntohl(mp->retval);
+ u8 * pvt_copy, * reply;
+ void * oldheap;
+ vlib_node_t * node;
+ int i;
+
+ if (vam->async_mode) {
+ vam->async_errors += (retval < 0);
+ } else {
+ vam->retval = retval;
+ vam->result_ready = 1;
+ }
+
+ /* "Should never happen..." */
+ if (retval != 0)
+ return;
+
+ reply = (u8 *)(mp->reply_in_shmem);
+ pvt_copy = vec_dup (reply);
+
+ /* Toss the shared-memory original... */
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ vec_free (reply);
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
+
+ if (vam->graph_nodes) {
+ hash_free (vam->graph_node_index_by_name);
+
+ for (i = 0; i < vec_len (vam->graph_nodes); i++) {
+ node = vam->graph_nodes[i];
+ vec_free (node->name);
+ vec_free (node->next_nodes);
+ vec_free (node);
+ }
+ vec_free(vam->graph_nodes);
+ }
+
+ vam->graph_node_index_by_name = hash_create_string (0, sizeof(uword));
+ vam->graph_nodes = vlib_node_unserialize (pvt_copy);
+ vec_free (pvt_copy);
+
+ for (i = 0; i < vec_len (vam->graph_nodes); i++) {
+ node = vam->graph_nodes[i];
+ hash_set_mem (vam->graph_node_index_by_name, node->name, i);
+ }
+}
+
+static void vl_api_get_node_graph_reply_t_handler_json
+(vl_api_get_node_graph_reply_t * mp)
+{
+ vat_main_t * vam = &vat_main;
+ api_main_t * am = &api_main;
+ void * oldheap;
+ vat_json_node_t node;
+ u8 * reply;
+
+ /* $$$$ make this real? */
+ vat_json_init_object(&node);
+ vat_json_object_add_int(&node, "retval", ntohl(mp->retval));
+ vat_json_object_add_uint(&node, "reply_in_shmem", mp->reply_in_shmem);
+
+ reply = (u8 *)(mp->reply_in_shmem);
+
+ /* Toss the shared-memory original... */
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ vec_free (reply);
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
+
+ vat_json_print(vam->ofp, &node);
+ vat_json_free(&node);
+
+ vam->retval = ntohl(mp->retval);
+ vam->result_ready = 1;
+}
+
#define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler
#define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler
#define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler
@@ -1946,7 +2047,8 @@ _(WANT_INTERFACE_EVENTS_REPLY, want_interface_events_reply) \
_(WANT_STATS_REPLY, want_stats_reply) \
_(GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply) \
_(COP_INTERFACE_ENABLE_DISABLE_REPLY, cop_interface_enable_disable_reply) \
-_(COP_WHITELIST_ENABLE_DISABLE_REPLY, cop_whitelist_enable_disable_reply)
+_(COP_WHITELIST_ENABLE_DISABLE_REPLY, cop_whitelist_enable_disable_reply) \
+_(GET_NODE_GRAPH_REPLY, get_node_graph_reply)
/* M: construct, but don't yet send a message */
@@ -8488,6 +8590,19 @@ static int api_cop_whitelist_enable_disable (vat_main_t * vam)
W;
}
+static int api_get_node_graph (vat_main_t * vam)
+{
+ vl_api_get_node_graph_t * mp;
+ f64 timeout;
+
+ M(GET_NODE_GRAPH, get_node_graph);
+
+ /* send it... */
+ S;
+ /* Wait for the reply */
+ W;
+}
+
static int q_or_quit (vat_main_t * vam)
{
longjmp (vam->jump_buf, 1);
@@ -8623,6 +8738,75 @@ static int dump_macro_table (vat_main_t * vam)
return 0;
}
+static int dump_node_table (vat_main_t * vam)
+{
+ int i, j;
+ vlib_node_t * node, * next_node;
+
+ if (vec_len (vam->graph_nodes) == 0) {
+ fformat (vam->ofp, "Node table empty, issue get_node_graph...\n");
+ return 0;
+ }
+
+ for (i = 0; i < vec_len (vam->graph_nodes); i++) {
+ node = vam->graph_nodes[i];
+ fformat (vam->ofp, "[%d] %s\n", i, node->name);
+ for (j = 0; j < vec_len (node->next_nodes); j++) {
+ if (node->next_nodes[j] != ~0) {
+ next_node = vam->graph_nodes[node->next_nodes[j]];
+ fformat (vam->ofp, " [%d] %s\n", j, next_node->name);
+ }
+ }
+ }
+ return 0;
+}
+
+static int search_node_table (vat_main_t * vam)
+{
+ unformat_input_t * line_input = vam->input;
+ u8 * node_to_find;
+ int j;
+ vlib_node_t * node, * next_node;
+ uword * p;
+
+ if (vam->graph_node_index_by_name == 0) {
+ fformat (vam->ofp, "Node table empty, issue get_node_graph...\n");
+ return 0;
+ }
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (line_input, "%s", &node_to_find)) {
+ vec_add1 (node_to_find, 0);
+ p = hash_get_mem (vam->graph_node_index_by_name, node_to_find);
+ if (p == 0) {
+ fformat (vam->ofp, "%s not found...\n", node_to_find);
+ goto out;
+ }
+ node = vam->graph_nodes[p[0]];
+ fformat (vam->ofp, "[%d] %s\n", p[0], node->name);
+ for (j = 0; j < vec_len (node->next_nodes); j++) {
+ if (node->next_nodes[j] != ~0) {
+ next_node = vam->graph_nodes[node->next_nodes[j]];
+ fformat (vam->ofp, " [%d] %s\n", j, next_node->name);
+ }
+ }
+ }
+
+ else {
+ clib_warning ("parse error '%U'", format_unformat_error,
+ line_input);
+ return -99;
+ }
+
+ out:
+ vec_free(node_to_find);
+
+ }
+
+ return 0;
+}
+
+
static int script (vat_main_t * vam)
{
u8 * s = 0;
@@ -8870,7 +9054,8 @@ _(want_stats,"enable|disable") \
_(get_first_msg_id, "client <name>") \
_(cop_interface_enable_disable, "<intfc> | sw_if_index <nn> [disable]") \
_(cop_whitelist_enable_disable, "<intfc> | sw_if_index <nn>\n" \
- "fib-id <nn> [ip4][ip6][default]")
+ "fib-id <nn> [ip4][ip6][default]") \
+_(get_node_graph, " ")
/* List of command functions, CLI names map directly to functions */
#define foreach_cli_function \
@@ -8881,11 +9066,13 @@ _(dump_ipv4_table, "usage: dump_ipv4_table") \
_(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") \
_(echo, "usage: echo <message>") \
_(exec, "usage: exec <vpe-debug-CLI-command>") \
_(help, "usage: help") \
_(q, "usage: quit") \
_(quit, "usage: quit") \
+_(search_node_table, "usage: search_node_table <name>...") \
_(set, "usage: set <variable-name> <value>") \
_(script, "usage: script <file-name>") \
_(unset, "usage: unset <variable-name>")
diff --git a/vpp-api-test/vat/vat.h b/vpp-api-test/vat/vat.h
index 0d012cf2d32..b32d9ffc754 100644
--- a/vpp-api-test/vat/vat.h
+++ b/vpp-api-test/vat/vat.h
@@ -94,6 +94,10 @@ typedef struct {
/* subinterface table */
sw_interface_subif_t * sw_if_subif_table;
+ /* Graph node table */
+ uword * graph_node_index_by_name;
+ vlib_node_t ** graph_nodes;
+
/* ip tables */
ip_details_t * ip_details_by_sw_if_index[2];
@@ -115,6 +119,7 @@ typedef struct {
/* Errors by number */
uword * error_string_by_error_number;
+
/* Main thread can spin (w/ timeout) here if needed */
u32 async_mode;
u32 async_errors;
diff --git a/vpp/api/api.c b/vpp/api/api.c
index 1390291bb85..e14eef6375c 100644
--- a/vpp/api/api.c
+++ b/vpp/api/api.c
@@ -310,7 +310,8 @@ _(MAP_DOMAIN_DUMP, map_domain_dump) \
_(MAP_RULE_DUMP, map_rule_dump) \
_(MAP_SUMMARY_STATS, map_summary_stats) \
_(COP_INTERFACE_ENABLE_DISABLE, cop_interface_enable_disable) \
-_(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable)
+_(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable) \
+_(GET_NODE_GRAPH, get_node_graph)
#define QUOTE_(x) #x
#define QUOTE(x) QUOTE_(x)
@@ -4905,6 +4906,35 @@ static void vl_api_cop_whitelist_enable_disable_t_handler
REPLY_MACRO(VL_API_COP_WHITELIST_ENABLE_DISABLE_REPLY);
}
+static void vl_api_get_node_graph_t_handler
+(vl_api_get_node_graph_t * mp)
+{
+ int rv = 0;
+ u8 * vector = 0;
+ api_main_t * am = &api_main;
+ vlib_main_t * vm = vlib_get_main();
+ void * oldheap;
+ vl_api_get_node_graph_reply_t * rmp;
+
+ pthread_mutex_lock (&am->vlib_rp->mutex);
+ oldheap = svm_push_data_heap (am->vlib_rp);
+
+ /*
+ * Keep the number of memcpy ops to a minimum (e.g. 1).
+ * The current size of the serialized vector is
+ * slightly under 4K.
+ */
+ vec_validate (vector, 4095);
+ vec_reset_length (vector);
+
+ vector = vlib_node_serialize (&vm->node_main, vector);
+
+ svm_pop_heap (oldheap);
+ pthread_mutex_unlock (&am->vlib_rp->mutex);
+
+ REPLY_MACRO2(VL_API_GET_NODE_GRAPH_REPLY,
+ rmp->reply_in_shmem = (uword) vector);
+}
#define BOUNCE_HANDLER(nn) \
static void vl_api_##nn##_t_handler ( \
diff --git a/vpp/api/vpe.api b/vpp/api/vpe.api
index bc3e107f0c0..d76a5c8eb88 100644
--- a/vpp/api/vpe.api
+++ b/vpp/api/vpe.api
@@ -2809,3 +2809,28 @@ define cop_whitelist_enable_disable_reply {
i32 retval;
};
+/** \brief get_node_graph - get a copy of the vpp node graph
+ including the current set of graph arcs.
+
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+*/
+
+define get_node_graph {
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief get_node_graph_reply
+ @param context - returned sender context, to match reply w/ request
+ @param retval - return code
+ @param reply_in_shmem - result from vlib_node_serialize, in shared
+ memory. Process with vlib_node_unserialize, remember to switch
+ heaps and free the result.
+*/
+
+define get_node_graph_reply {
+ u32 context;
+ i32 retval;
+ u64 reply_in_shmem;
+};