diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmake/library.cmake | 30 | ||||
-rw-r--r-- | src/tools/vppapigen/vppapigen_c.py | 6 | ||||
-rw-r--r-- | src/vat/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vat/api_format.c | 559 | ||||
-rw-r--r-- | src/vlibapi/api_helper_macros.h | 10 | ||||
-rw-r--r-- | src/vlibmemory/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/vlibmemory/memclnt_api.c | 719 | ||||
-rw-r--r-- | src/vlibmemory/vlib.api | 250 | ||||
-rw-r--r-- | src/vlibmemory/vlib_api.c | 828 | ||||
-rw-r--r-- | src/vlibmemory/vlibapi_test.c | 470 | ||||
-rw-r--r-- | src/vnet/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/vnet/arp/arp_test.c | 2 | ||||
-rw-r--r-- | src/vnet/ip/ip_test.c | 2 | ||||
-rw-r--r-- | src/vnet/ip6-nd/ip6_nd_test.c | 6 | ||||
-rw-r--r-- | src/vpp/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/vpp/api/api.c | 367 | ||||
-rw-r--r-- | src/vpp/api/vpe.api | 243 |
17 files changed, 1744 insertions, 1765 deletions
diff --git a/src/cmake/library.cmake b/src/cmake/library.cmake index d19eb3c80cc..c80d7f226d6 100644 --- a/src/cmake/library.cmake +++ b/src/cmake/library.cmake @@ -108,6 +108,36 @@ function (add_vpp_headers path) endforeach() endfunction() +macro(add_vat_test_library lib) + cmake_parse_arguments(TEST + "" + "" + ${ARGN} + ) + + foreach(file ${ARGN}) + get_filename_component(name ${file} NAME_WE) + set(test_lib ${lib}_${name}_plugin) + add_library(${test_lib} SHARED ${file}) + target_compile_options(${test_lib} PUBLIC ${VPP_DEFAULT_MARCH_FLAGS}) + if(NOT VPP_EXTERNAL_PROJECT) + add_dependencies(${test_lib} api_headers) + endif() + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set_target_properties(${test_lib} PROPERTIES NO_SONAME 1) + set_target_properties(${test_lib} PROPERTIES + PREFIX "" + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/vpp_api_test_plugins) + + # install .so + install( + TARGETS ${test_lib} + DESTINATION ${VPP_LIBRARY_DIR}/vpp_api_test_plugins + COMPONENT ${ARG_COMPONENT} + ) + endforeach() +endmacro() + macro(add_vpp_test_library lib) cmake_parse_arguments(TEST "" diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py index 4227cae1ece..2d526c151b7 100644 --- a/src/tools/vppapigen/vppapigen_c.py +++ b/src/tools/vppapigen/vppapigen_c.py @@ -1478,11 +1478,7 @@ def generate_c_test_boilerplate(services, defines, file_crc, module, plugin, .format(n=e, ID=e.upper())) write('}\n') - if plugin: - write('clib_error_t * vat_plugin_register (vat_main_t *vam)\n') - else: - write('clib_error_t * vat_{}_plugin_register (vat_main_t *vam)\n' - .format(module)) + write('clib_error_t * vat_plugin_register (vat_main_t *vam)\n') write('{\n') write(' {n}_test_main_t * mainp = &{n}_test_main;\n'.format(n=module)) write(' mainp->vat_main = vam;\n') diff --git a/src/vat/CMakeLists.txt b/src/vat/CMakeLists.txt index 66ea69b8da4..e4f89458e12 100644 --- a/src/vat/CMakeLists.txt +++ b/src/vat/CMakeLists.txt @@ -32,7 +32,6 @@ add_vpp_executable(vpp_api_test ENABLE_EXPORTS ip_types_api.c ip_types.c protocols.def - ../vnet/arp/arp_test.c DEPENDS api_headers diff --git a/src/vat/api_format.c b/src/vat/api_format.c index bb168f8459e..8f23d773d99 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -579,185 +579,6 @@ ip_set (ip46_address_t * dst, void *src, u8 is_ip4) } -static void -vl_api_cli_reply_t_handler (vl_api_cli_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - - vam->retval = retval; - vam->shmem_result = uword_to_pointer (mp->reply_in_shmem, u8 *); - vam->result_ready = 1; -} - -static void -vl_api_cli_reply_t_handler_json (vl_api_cli_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - 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)); - /* Toss the shared-memory original... */ - oldheap = vl_msg_push_heap (); - - reply = uword_to_pointer (mp->reply_in_shmem, u8 *); - vec_free (reply); - - vl_msg_pop_heap (oldheap); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - -static void -vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - - vec_reset_length (vam->cmd_reply); - - vam->retval = retval; - if (retval == 0) - vam->cmd_reply = vl_api_from_api_to_new_vec (mp, &mp->reply); - vam->result_ready = 1; -} - -static void -vl_api_cli_inband_reply_t_handler_json (vl_api_cli_inband_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - u8 *reply = 0; /* reply vector */ - - reply = vl_api_from_api_to_new_vec (mp, &mp->reply); - vec_reset_length (vam->cmd_reply); - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); - vat_json_object_add_string_copy (&node, "reply", reply); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - vec_free (reply); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - -static void vl_api_get_node_index_reply_t_handler - (vl_api_get_node_index_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - if (vam->async_mode) - { - vam->async_errors += (retval < 0); - } - else - { - vam->retval = retval; - if (retval == 0) - errmsg ("node index %d", ntohl (mp->node_index)); - vam->result_ready = 1; - } -} - -static void vl_api_get_node_index_reply_t_handler_json - (vl_api_get_node_index_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); - vat_json_object_add_uint (&node, "node_index", ntohl (mp->node_index)); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - -static void vl_api_get_next_index_reply_t_handler - (vl_api_get_next_index_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - if (vam->async_mode) - { - vam->async_errors += (retval < 0); - } - else - { - vam->retval = retval; - if (retval == 0) - errmsg ("next node index %d", ntohl (mp->next_index)); - vam->result_ready = 1; - } -} - -static void vl_api_get_next_index_reply_t_handler_json - (vl_api_get_next_index_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); - vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index)); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - -static void vl_api_add_node_next_reply_t_handler - (vl_api_add_node_next_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - if (vam->async_mode) - { - vam->async_errors += (retval < 0); - } - else - { - vam->retval = retval; - if (retval == 0) - errmsg ("next index %d", ntohl (mp->next_index)); - vam->result_ready = 1; - } -} - -static void vl_api_add_node_next_reply_t_handler_json - (vl_api_add_node_next_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); - vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index)); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - static void vl_api_show_version_reply_t_handler (vl_api_show_version_reply_t * mp) { @@ -796,80 +617,6 @@ static void vl_api_show_version_reply_t_handler_json vam->result_ready = 1; } -static void vl_api_show_threads_reply_t_handler - (vl_api_show_threads_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - i32 retval = ntohl (mp->retval); - int i, count = 0; - - if (retval >= 0) - count = ntohl (mp->count); - - for (i = 0; i < count; i++) - print (vam->ofp, - "\n%-2d %-11s %-11s %-5d %-6d %-4d %-6d", - ntohl (mp->thread_data[i].id), mp->thread_data[i].name, - mp->thread_data[i].type, ntohl (mp->thread_data[i].pid), - ntohl (mp->thread_data[i].cpu_id), ntohl (mp->thread_data[i].core), - ntohl (mp->thread_data[i].cpu_socket)); - - vam->retval = retval; - vam->result_ready = 1; -} - -static void vl_api_show_threads_reply_t_handler_json - (vl_api_show_threads_reply_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t node; - vl_api_thread_data_t *td; - i32 retval = ntohl (mp->retval); - int i, count = 0; - - if (retval >= 0) - count = ntohl (mp->count); - - vat_json_init_object (&node); - vat_json_object_add_int (&node, "retval", retval); - vat_json_object_add_uint (&node, "count", count); - - for (i = 0; i < count; i++) - { - td = &mp->thread_data[i]; - vat_json_object_add_uint (&node, "id", ntohl (td->id)); - vat_json_object_add_string_copy (&node, "name", td->name); - vat_json_object_add_string_copy (&node, "type", td->type); - vat_json_object_add_uint (&node, "pid", ntohl (td->pid)); - vat_json_object_add_int (&node, "cpu_id", ntohl (td->cpu_id)); - vat_json_object_add_int (&node, "core", ntohl (td->id)); - vat_json_object_add_int (&node, "cpu_socket", ntohl (td->cpu_socket)); - } - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = retval; - vam->result_ready = 1; -} - -static int -api_show_threads (vat_main_t * vam) -{ - vl_api_show_threads_t *mp; - int ret; - - print (vam->ofp, - "\n%-2s %-11s %-11s %-5s %-6s %-4s %-6s", - "ID", "Name", "Type", "LWP", "cpu_id", "Core", "Socket"); - - M (SHOW_THREADS, mp); - - S (mp); - W (ret); - return ret; -} - #define vl_api_bridge_domain_details_t_endian vl_noop_handler #define vl_api_bridge_domain_details_t_print vl_noop_handler @@ -955,95 +702,6 @@ 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; - 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 = uword_to_pointer (mp->reply_in_shmem, u8 *); - pvt_copy = vec_dup (reply); - - /* Toss the shared-memory original... */ - oldheap = vl_msg_push_heap (); - - vec_free (reply); - - vl_msg_pop_heap (oldheap); - - if (vam->graph_nodes) - { - hash_free (vam->graph_node_index_by_name); - - for (i = 0; i < vec_len (vam->graph_nodes[0]); i++) - { - node = vam->graph_nodes[0][i]; - vec_free (node->name); - vec_free (node->next_nodes); - vec_free (node); - } - vec_free (vam->graph_nodes[0]); - 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[0]); i++) - { - node = vam->graph_nodes[0][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; - 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 = uword_to_pointer (mp->reply_in_shmem, u8 *); - - /* Toss the shared-memory original... */ - oldheap = vl_msg_push_heap (); - - vec_free (reply); - - vl_msg_pop_heap (oldheap); - - vat_json_print (vam->ofp, &node); - vat_json_free (&node); - - vam->retval = ntohl (mp->retval); - vam->result_ready = 1; -} - /* Format hex dump. */ u8 * format_hex_bytes (u8 * s, va_list * va) @@ -1120,15 +778,8 @@ foreach_standard_reply_retval_handler; #define foreach_vpe_api_reply_msg \ _ (GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply) \ - _ (GET_NODE_GRAPH_REPLY, get_node_graph_reply) \ _ (CONTROL_PING_REPLY, control_ping_reply) \ - _ (CLI_REPLY, cli_reply) \ - _ (CLI_INBAND_REPLY, cli_inband_reply) \ - _ (GET_NODE_INDEX_REPLY, get_node_index_reply) \ - _ (GET_NEXT_INDEX_REPLY, get_next_index_reply) \ - _ (ADD_NODE_NEXT_REPLY, add_node_next_reply) \ _ (SHOW_VERSION_REPLY, show_version_reply) \ - _ (SHOW_THREADS_REPLY, show_threads_reply) \ #define foreach_standalone_reply_msg \ @@ -1142,53 +793,6 @@ typedef struct case L2_VTR_ ## op: \ return "" # op; -/* - * Pass CLI buffers directly in the CLI_INBAND API message, - * instead of an additional shared memory area. - */ -static int -exec_inband (vat_main_t * vam) -{ - vl_api_cli_inband_t *mp; - unformat_input_t *i = vam->input; - int ret; - - if (vec_len (i->buffer) == 0) - return -1; - - if (vam->exec_mode == 0 && unformat (i, "mode")) - { - vam->exec_mode = 1; - return 0; - } - if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit"))) - { - vam->exec_mode = 0; - return 0; - } - - /* - * In order for the CLI command to work, it - * must be a vector ending in \n, not a C-string ending - * in \n\0. - */ - M2 (CLI_INBAND, mp, vec_len (vam->input->buffer)); - vl_api_vec_to_api_string (vam->input->buffer, &mp->cmd); - - S (mp); - W (ret); - /* json responses may or may not include a useful reply... */ - if (vec_len (vam->cmd_reply)) - print (vam->ofp, "%v", (char *) (vam->cmd_reply)); - return ret; -} - -int -exec (vat_main_t *vam) -{ - return exec_inband (vam); -} - int api_sw_interface_dump (vat_main_t *vam) { @@ -2442,140 +2046,6 @@ api_unformat_classify_match (unformat_input_t * input, va_list * args) return 0; } -static int -api_get_node_index (vat_main_t *vam) -{ - unformat_input_t *i = vam->input; - vl_api_get_node_index_t *mp; - u8 *name = 0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "node %s", &name)) - ; - else - break; - } - if (name == 0) - { - errmsg ("node name required"); - return -99; - } - if (vec_len (name) >= ARRAY_LEN (mp->node_name)) - { - errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); - return -99; - } - - M (GET_NODE_INDEX, mp); - clib_memcpy (mp->node_name, name, vec_len (name)); - vec_free (name); - - S (mp); - W (ret); - return ret; -} - -static int -api_get_next_index (vat_main_t *vam) -{ - unformat_input_t *i = vam->input; - vl_api_get_next_index_t *mp; - u8 *node_name = 0, *next_node_name = 0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "node-name %s", &node_name)) - ; - else if (unformat (i, "next-node-name %s", &next_node_name)) - break; - } - - if (node_name == 0) - { - errmsg ("node name required"); - return -99; - } - if (vec_len (node_name) >= ARRAY_LEN (mp->node_name)) - { - errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); - return -99; - } - - if (next_node_name == 0) - { - errmsg ("next node name required"); - return -99; - } - if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name)) - { - errmsg ("next node name too long, max %d", ARRAY_LEN (mp->next_name)); - return -99; - } - - M (GET_NEXT_INDEX, mp); - clib_memcpy (mp->node_name, node_name, vec_len (node_name)); - clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name)); - vec_free (node_name); - vec_free (next_node_name); - - S (mp); - W (ret); - return ret; -} - -static int -api_add_node_next (vat_main_t *vam) -{ - unformat_input_t *i = vam->input; - vl_api_add_node_next_t *mp; - u8 *name = 0; - u8 *next = 0; - int ret; - - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "node %s", &name)) - ; - else if (unformat (i, "next %s", &next)) - ; - else - break; - } - if (name == 0) - { - errmsg ("node name required"); - return -99; - } - if (vec_len (name) >= ARRAY_LEN (mp->node_name)) - { - errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); - return -99; - } - if (next == 0) - { - errmsg ("next node required"); - return -99; - } - if (vec_len (next) >= ARRAY_LEN (mp->next_name)) - { - errmsg ("next name too long, max %d", ARRAY_LEN (mp->next_name)); - return -99; - } - - M (ADD_NODE_NEXT, mp); - clib_memcpy (mp->node_name, name, vec_len (name)); - clib_memcpy (mp->next_name, next, vec_len (next)); - vec_free (name); - vec_free (next); - - S (mp); - W (ret); - return ret; -} - #define foreach_vtr_op \ _ ("disable", L2_VTR_DISABLED) \ _ ("push-1", L2_VTR_PUSH_1) \ @@ -2637,21 +2107,6 @@ api_get_first_msg_id (vat_main_t *vam) return ret; } -static int -api_get_node_graph (vat_main_t *vam) -{ - vl_api_get_node_graph_t *mp; - int ret; - - M (GET_NODE_GRAPH, mp); - - /* send it... */ - S (mp); - /* Wait for the reply */ - W (ret); - return ret; -} - #define foreach_pbb_vtr_op \ _("disable", L2_VTR_DISABLED) \ _("pop", L2_VTR_POP_2) \ @@ -3218,15 +2673,17 @@ echo (vat_main_t * vam) return 0; } +int exec (vat_main_t *vam) __attribute__ ((weak)); +int +exec (vat_main_t *vam) +{ + return -1; +} + /* List of API message constructors, CLI names map to api_xxx */ #define foreach_vpe_api_msg \ -_(get_node_index, "node <node-name") \ -_(add_node_next, "node <node-name> next <next-node-name>") \ _(show_version, "") \ -_(show_threads, "") \ _(get_first_msg_id, "client <name>") \ -_(get_node_graph, " ") \ -_(get_next_index, "node-name <node-name> next-node-name <node-name>") \ _(sock_init_shm, "size <nnn>") \ /* List of command functions, CLI names map directly to functions */ #define foreach_cli_function \ @@ -3239,8 +2696,6 @@ _(elog_enable, "usage: elog_enable") \ _(elog_save, "usage: elog_save <filename>") \ _(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>") \ _(help, "usage: help") \ _(q, "usage: quit") \ _(quit, "usage: quit") \ diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h index d49282e9e65..2e0a62229f3 100644 --- a/src/vlibapi/api_helper_macros.h +++ b/src/vlibapi/api_helper_macros.h @@ -271,12 +271,8 @@ do { \ /* "trust, but verify" */ - -static inline uword -vnet_sw_if_index_is_api_valid (u32 sw_if_index) -{ - return vnet_sw_interface_is_api_valid (vnet_get_main (), sw_if_index); -} +#define vnet_sw_if_index_is_api_valid(sw_if_index) \ + vnet_sw_interface_is_api_valid (vnet_get_main (), sw_if_index) #define VALIDATE_SW_IF_INDEX(mp) \ do { u32 __sw_if_index = ntohl((mp)->sw_if_index); \ @@ -423,7 +419,7 @@ typedef struct /* convenience */ vlib_main_t *vlib_main; - vnet_main_t *vnet_main; + struct vnet_main_t *vnet_main; } vpe_api_main_t; extern vpe_api_main_t vpe_api_main; diff --git a/src/vlibmemory/CMakeLists.txt b/src/vlibmemory/CMakeLists.txt index b48ff7b5766..456cba9baeb 100644 --- a/src/vlibmemory/CMakeLists.txt +++ b/src/vlibmemory/CMakeLists.txt @@ -18,8 +18,9 @@ add_vpp_library (vlibmemory memory_client.c socket_client.c socket_api.c - vlib_api.c + memclnt_api.c vlib_api_cli.c + vlib_api.c ../vlibapi/api_shared.c ../vlibapi/node_serialize.c @@ -35,6 +36,7 @@ add_vpp_library (vlibmemory API_FILES memclnt.api + vlib.api LINK_LIBRARIES vppinfra svm vlib ) @@ -51,3 +53,7 @@ add_vpp_library (vlibmemoryclient LINK_LIBRARIES vppinfra svm ) add_dependencies(vlibmemoryclient vlibmemory_api_headers) + +add_vat_test_library(vlib + vlibapi_test.c +) diff --git a/src/vlibmemory/memclnt_api.c b/src/vlibmemory/memclnt_api.c new file mode 100644 index 00000000000..5ebc31f71dc --- /dev/null +++ b/src/vlibmemory/memclnt_api.c @@ -0,0 +1,719 @@ +/* + *------------------------------------------------------------------ + * memclnt_api.c VLIB API implementation + * + * Copyright (c) 2009 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 <fcntl.h> +#include <pthread.h> +#include <vppinfra/vec.h> +#include <vppinfra/hash.h> +#include <vppinfra/pool.h> +#include <vppinfra/format.h> +#include <vppinfra/byte_order.h> +#include <vppinfra/elog.h> +#include <vlib/vlib.h> +#include <vlib/unix/unix.h> +#include <vlibapi/api.h> +#include <vlibmemory/api.h> + +/** + * @file + * @brief Binary API messaging via shared memory + * Low-level, primary provisioning interface + */ +/*? %%clicmd:group_label Binary API CLI %% ?*/ +/*? %%syscfg:group_label Binary API configuration %% ?*/ + +#define TRACE_VLIB_MEMORY_QUEUE 0 + +#include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */ + +#define vl_typedefs /* define message structures */ +#include <vlibmemory/vl_memory_api_h.h> +#undef vl_typedefs + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include <vlibmemory/vl_memory_api_h.h> +#undef vl_printfun + +static inline void * +vl_api_trace_plugin_msg_ids_t_print (vl_api_trace_plugin_msg_ids_t *a, + void *handle) +{ + vl_print (handle, "vl_api_trace_plugin_msg_ids: %s first %u last %u\n", + a->plugin_name, clib_host_to_net_u16 (a->first_msg_id), + clib_host_to_net_u16 (a->last_msg_id)); + return handle; +} + +/* instantiate all the endian swap functions we know about */ +#define vl_endianfun +#include <vlibmemory/vl_memory_api_h.h> +#undef vl_endianfun + +static void +vl_api_get_first_msg_id_t_handler (vl_api_get_first_msg_id_t *mp) +{ + vl_api_get_first_msg_id_reply_t *rmp; + vl_api_registration_t *regp; + uword *p; + api_main_t *am = vlibapi_get_main (); + vl_api_msg_range_t *rp; + u8 name[64]; + u16 first_msg_id = ~0; + int rv = -7; /* VNET_API_ERROR_INVALID_VALUE */ + + regp = vl_api_client_index_to_registration (mp->client_index); + if (!regp) + return; + + if (am->msg_range_by_name == 0) + goto out; + strncpy ((char *) name, (char *) mp->name, ARRAY_LEN (name)); + name[ARRAY_LEN (name) - 1] = '\0'; + p = hash_get_mem (am->msg_range_by_name, name); + if (p == 0) + goto out; + + rp = vec_elt_at_index (am->msg_ranges, p[0]); + first_msg_id = rp->first_msg_id; + rv = 0; + +out: + rmp = vl_msg_api_alloc (sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID_REPLY); + rmp->context = mp->context; + rmp->retval = ntohl (rv); + rmp->first_msg_id = ntohs (first_msg_id); + vl_api_send_msg (regp, (u8 *) rmp); +} + +void +vl_api_api_versions_t_handler (vl_api_api_versions_t *mp) +{ + api_main_t *am = vlibapi_get_main (); + vl_api_api_versions_reply_t *rmp; + vl_api_registration_t *reg; + u32 nmsg = vec_len (am->api_version_list); + int msg_size = sizeof (*rmp) + sizeof (rmp->api_versions[0]) * nmsg; + int i; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + rmp = vl_msg_api_alloc (msg_size); + clib_memset (rmp, 0, msg_size); + rmp->_vl_msg_id = ntohs (VL_API_API_VERSIONS_REPLY); + + /* fill in the message */ + rmp->context = mp->context; + rmp->count = htonl (nmsg); + + for (i = 0; i < nmsg; ++i) + { + api_version_t *vl = &am->api_version_list[i]; + rmp->api_versions[i].major = htonl (vl->major); + rmp->api_versions[i].minor = htonl (vl->minor); + rmp->api_versions[i].patch = htonl (vl->patch); + strncpy ((char *) rmp->api_versions[i].name, vl->name, + ARRAY_LEN (rmp->api_versions[i].name)); + rmp->api_versions[i].name[ARRAY_LEN (rmp->api_versions[i].name) - 1] = + '\0'; + } + + vl_api_send_msg (reg, (u8 *) rmp); +} + +#define foreach_vlib_api_msg \ + _ (GET_FIRST_MSG_ID, get_first_msg_id) \ + _ (API_VERSIONS, api_versions) + +/* + * vl_api_init + */ +static int +vlib_api_init (void) +{ + vl_msg_api_msg_config_t cfg; + vl_msg_api_msg_config_t *c = &cfg; + + clib_memset (c, 0, sizeof (*c)); + +#define _(N, n) \ + do \ + { \ + c->id = VL_API_##N; \ + c->name = #n; \ + c->handler = vl_api_##n##_t_handler; \ + c->cleanup = vl_noop_handler; \ + c->endian = vl_api_##n##_t_endian; \ + c->print = vl_api_##n##_t_print; \ + c->size = sizeof (vl_api_##n##_t); \ + c->traced = 1; /* trace, so these msgs print */ \ + c->replay = 0; /* don't replay client create/delete msgs */ \ + c->message_bounce = 0; /* don't bounce this message */ \ + vl_msg_api_config (c); \ + } \ + while (0); + + foreach_vlib_api_msg; +#undef _ + + return 0; +} + +u64 vector_rate_histogram[SLEEP_N_BUCKETS]; + +/* + * Callback to send ourselves a plugin numbering-space trace msg + */ +static void +send_one_plugin_msg_ids_msg (u8 *name, u16 first_msg_id, u16 last_msg_id) +{ + vl_api_trace_plugin_msg_ids_t *mp; + api_main_t *am = vlibapi_get_main (); + vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr; + svm_queue_t *q; + + mp = vl_msg_api_alloc_as_if_client (sizeof (*mp)); + clib_memset (mp, 0, sizeof (*mp)); + + mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_TRACE_PLUGIN_MSG_IDS); + strncpy ((char *) mp->plugin_name, (char *) name, + sizeof (mp->plugin_name) - 1); + mp->first_msg_id = clib_host_to_net_u16 (first_msg_id); + mp->last_msg_id = clib_host_to_net_u16 (last_msg_id); + + q = shmem_hdr->vl_input_queue; + + vl_msg_api_send_shmem (q, (u8 *) &mp); +} + +void +vl_api_save_msg_table (void) +{ + u8 *serialized_message_table; + api_main_t *am = vlibapi_get_main (); + u8 *chroot_file; + int fd, rv; + + /* + * Snapshoot the api message table. + */ + if (strstr ((char *) am->save_msg_table_filename, "..") || + index ((char *) am->save_msg_table_filename, '/')) + { + clib_warning ("illegal save-message-table filename '%s'", + am->save_msg_table_filename); + return; + } + + chroot_file = format (0, "/tmp/%s%c", am->save_msg_table_filename, 0); + + fd = creat ((char *) chroot_file, 0644); + + if (fd < 0) + { + clib_unix_warning ("creat"); + return; + } + + serialized_message_table = vl_api_serialize_message_table (am, 0); + + rv = + write (fd, serialized_message_table, vec_len (serialized_message_table)); + + if (rv != vec_len (serialized_message_table)) + clib_unix_warning ("write"); + + rv = close (fd); + if (rv < 0) + clib_unix_warning ("close"); + + vec_free (chroot_file); + vec_free (serialized_message_table); +} + +clib_error_t *vat_builtin_main_init (vlib_main_t *vm) __attribute__ ((weak)); +clib_error_t * +vat_builtin_main_init (vlib_main_t *vm) +{ + return 0; +} + +static uword +vl_api_clnt_process (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *f) +{ + vlib_global_main_t *vgm = vlib_get_global_main (); + int private_segment_rotor = 0, i, rv; + vl_socket_args_for_process_t *a; + vl_shmem_hdr_t *shm; + svm_queue_t *q; + clib_error_t *e; + api_main_t *am = vlibapi_get_main (); + f64 dead_client_scan_time; + f64 sleep_time, start_time; + f64 vector_rate; + clib_error_t *error; + uword event_type; + uword *event_data = 0; + f64 now; + + if ((error = vl_sock_api_init (vm))) + { + clib_error_report (error); + clib_warning ("socksvr_api_init failed, quitting..."); + return 0; + } + + if ((rv = vlib_api_init ()) < 0) + { + clib_warning ("vlib_api_init returned %d, quitting...", rv); + return 0; + } + + shm = am->shmem_hdr; + q = shm->vl_input_queue; + + e = vlib_call_init_exit_functions (vm, &vgm->api_init_function_registrations, + 1 /* call_once */, 1 /* is_global */); + if (e) + clib_error_report (e); + + e = vat_builtin_main_init (vm); + if (e) + clib_error_report (e); + + sleep_time = 10.0; + dead_client_scan_time = vlib_time_now (vm) + 10.0; + + /* + * Send plugin message range messages for each plugin we loaded + */ + for (i = 0; i < vec_len (am->msg_ranges); i++) + { + vl_api_msg_range_t *rp = am->msg_ranges + i; + send_one_plugin_msg_ids_msg (rp->name, rp->first_msg_id, + rp->last_msg_id); + } + + /* + * Save the api message table snapshot, if configured + */ + if (am->save_msg_table_filename) + vl_api_save_msg_table (); + + /* $$$ pay attention to frame size, control CPU usage */ + while (1) + { + /* + * There's a reason for checking the queue before + * sleeping. If the vlib application crashes, it's entirely + * possible for a client to enqueue a connect request + * during the process restart interval. + * + * Unless some force of physics causes the new incarnation + * of the application to process the request, the client will + * sit and wait for Godot... + */ + vector_rate = (f64) vlib_last_vectors_per_main_loop (vm); + start_time = vlib_time_now (vm); + while (1) + { + if (vl_mem_api_handle_rpc (vm, node) || + vl_mem_api_handle_msg_main (vm, node)) + { + vm->api_queue_nonempty = 0; + VL_MEM_API_LOG_Q_LEN ("q-underflow: len %d", 0); + sleep_time = 20.0; + break; + } + + /* Allow no more than 10us without a pause */ + if (vlib_time_now (vm) > start_time + 10e-6) + { + int index = SLEEP_400_US; + if (vector_rate > 40.0) + sleep_time = 400e-6; + else if (vector_rate > 20.0) + { + index = SLEEP_200_US; + sleep_time = 200e-6; + } + else if (vector_rate >= 1.0) + { + index = SLEEP_100_US; + sleep_time = 100e-6; + } + else + { + index = SLEEP_10_US; + sleep_time = 10e-6; + } + vector_rate_histogram[index] += 1; + break; + } + } + + /* + * see if we have any private api shared-memory segments + * If so, push required context variables, and process + * a message. + */ + if (PREDICT_FALSE (vec_len (am->vlib_private_rps))) + { + if (private_segment_rotor >= vec_len (am->vlib_private_rps)) + private_segment_rotor = 0; + vl_mem_api_handle_msg_private (vm, node, private_segment_rotor++); + } + + vlib_process_wait_for_event_or_clock (vm, sleep_time); + vec_reset_length (event_data); + event_type = vlib_process_get_events (vm, &event_data); + now = vlib_time_now (vm); + + switch (event_type) + { + case QUEUE_SIGNAL_EVENT: + vm->queue_signal_pending = 0; + VL_MEM_API_LOG_Q_LEN ("q-awake: len %d", q->cursize); + + break; + case SOCKET_READ_EVENT: + for (i = 0; i < vec_len (event_data); i++) + { + vl_api_registration_t *regp; + + a = pool_elt_at_index (socket_main.process_args, event_data[i]); + regp = vl_socket_get_registration (a->reg_index); + if (regp) + { + vl_socket_process_api_msg (regp, (i8 *) a->data); + a = pool_elt_at_index (socket_main.process_args, + event_data[i]); + } + vec_free (a->data); + pool_put (socket_main.process_args, a); + } + break; + + /* Timeout... */ + case -1: + break; + + default: + clib_warning ("unknown event type %d", event_type); + break; + } + + if (now > dead_client_scan_time) + { + vl_mem_api_dead_client_scan (am, shm, now); + dead_client_scan_time = vlib_time_now (vm) + 10.0; + } + } + + return 0; +} + +VLIB_REGISTER_NODE (vl_api_clnt_node) = { + .function = vl_api_clnt_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "api-rx-from-ring", + .state = VLIB_NODE_STATE_DISABLED, + .process_log2_n_stack_bytes = 18, +}; + +void +vl_mem_api_enable_disable (vlib_main_t *vm, int enable) +{ + vlib_node_set_state ( + vm, vl_api_clnt_node.index, + (enable ? VLIB_NODE_STATE_POLLING : VLIB_NODE_STATE_DISABLED)); +} + +static uword +api_rx_from_node (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + uword n_packets = frame->n_vectors; + uword n_left_from; + u32 *from; + static u8 *long_msg; + + vec_validate (long_msg, 4095); + n_left_from = frame->n_vectors; + from = vlib_frame_vector_args (frame); + + while (n_left_from > 0) + { + u32 bi0; + vlib_buffer_t *b0; + void *msg; + uword msg_len; + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + from += 1; + n_left_from -= 1; + + msg = b0->data + b0->current_data; + msg_len = b0->current_length; + if (b0->flags & VLIB_BUFFER_NEXT_PRESENT) + { + ASSERT (long_msg != 0); + _vec_len (long_msg) = 0; + vec_add (long_msg, msg, msg_len); + while (b0->flags & VLIB_BUFFER_NEXT_PRESENT) + { + b0 = vlib_get_buffer (vm, b0->next_buffer); + msg = b0->data + b0->current_data; + msg_len = b0->current_length; + vec_add (long_msg, msg, msg_len); + } + msg = long_msg; + } + vl_msg_api_handler_no_trace_no_free (msg); + } + + /* Free what we've been given. */ + vlib_buffer_free (vm, vlib_frame_vector_args (frame), n_packets); + + return n_packets; +} + +VLIB_REGISTER_NODE (api_rx_from_node_node, static) = { + .function = api_rx_from_node, + .type = VLIB_NODE_TYPE_INTERNAL, + .vector_size = 4, + .name = "api-rx-from-node", +}; + +static void +vl_api_rpc_call_t_handler (vl_api_rpc_call_t *mp) +{ + vl_api_rpc_call_reply_t *rmp; + int (*fp) (void *); + i32 rv = 0; + vlib_main_t *vm = vlib_get_main (); + + if (mp->function == 0) + { + rv = -1; + clib_warning ("rpc NULL function pointer"); + } + + else + { + if (mp->need_barrier_sync) + vlib_worker_thread_barrier_sync (vm); + + fp = uword_to_pointer (mp->function, int (*) (void *)); + rv = fp (mp->data); + + if (mp->need_barrier_sync) + vlib_worker_thread_barrier_release (vm); + } + + if (mp->send_reply) + { + svm_queue_t *q = vl_api_client_index_to_input_queue (mp->client_index); + if (q) + { + rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp)); + rmp->_vl_msg_id = ntohs (VL_API_RPC_CALL_REPLY); + rmp->context = mp->context; + rmp->retval = rv; + vl_msg_api_send_shmem (q, (u8 *) &rmp); + } + } + if (mp->multicast) + { + clib_warning ("multicast not yet implemented..."); + } +} + +static void +vl_api_rpc_call_reply_t_handler (vl_api_rpc_call_reply_t *mp) +{ + clib_warning ("unimplemented"); +} + +void +vl_api_send_pending_rpc_requests (vlib_main_t *vm) +{ + vlib_main_t *vm_global = vlib_get_first_main (); + + ASSERT (vm != vm_global); + + clib_spinlock_lock_if_init (&vm_global->pending_rpc_lock); + vec_append (vm_global->pending_rpc_requests, vm->pending_rpc_requests); + vec_reset_length (vm->pending_rpc_requests); + clib_spinlock_unlock_if_init (&vm_global->pending_rpc_lock); +} + +always_inline void +vl_api_rpc_call_main_thread_inline (void *fp, u8 *data, u32 data_length, + u8 force_rpc) +{ + vl_api_rpc_call_t *mp; + vlib_main_t *vm_global = vlib_get_first_main (); + vlib_main_t *vm = vlib_get_main (); + + /* Main thread and not a forced RPC: call the function directly */ + if ((force_rpc == 0) && (vlib_get_thread_index () == 0)) + { + void (*call_fp) (void *); + + vlib_worker_thread_barrier_sync (vm); + + call_fp = fp; + call_fp (data); + + vlib_worker_thread_barrier_release (vm); + return; + } + + /* Otherwise, actually do an RPC */ + mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + data_length); + + clib_memset (mp, 0, sizeof (*mp)); + clib_memcpy_fast (mp->data, data, data_length); + mp->_vl_msg_id = ntohs (VL_API_RPC_CALL); + mp->function = pointer_to_uword (fp); + mp->need_barrier_sync = 1; + + /* Add to the pending vector. Thread 0 requires locking. */ + if (vm == vm_global) + clib_spinlock_lock_if_init (&vm_global->pending_rpc_lock); + vec_add1 (vm->pending_rpc_requests, (uword) mp); + if (vm == vm_global) + clib_spinlock_unlock_if_init (&vm_global->pending_rpc_lock); +} + +/* + * Check if called from worker threads. + * If so, make rpc call of fp through shmem. + * Otherwise, call fp directly + */ +void +vl_api_rpc_call_main_thread (void *fp, u8 *data, u32 data_length) +{ + vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */ + 0); +} + +/* + * Always make rpc call of fp through shmem, useful for calling from threads + * not setup as worker threads, such as DPDK callback thread + */ +void +vl_api_force_rpc_call_main_thread (void *fp, u8 *data, u32 data_length) +{ + vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */ + 1); +} + +static void +vl_api_trace_plugin_msg_ids_t_handler (vl_api_trace_plugin_msg_ids_t *mp) +{ + api_main_t *am = vlibapi_get_main (); + vl_api_msg_range_t *rp; + uword *p; + + /* Noop (except for tracing) during normal operation */ + if (am->replay_in_progress == 0) + return; + + p = hash_get_mem (am->msg_range_by_name, mp->plugin_name); + if (p == 0) + { + clib_warning ("WARNING: traced plugin '%s' not in current image", + mp->plugin_name); + return; + } + + rp = vec_elt_at_index (am->msg_ranges, p[0]); + if (rp->first_msg_id != clib_net_to_host_u16 (mp->first_msg_id)) + { + clib_warning ("WARNING: traced plugin '%s' first message id %d not %d", + mp->plugin_name, clib_net_to_host_u16 (mp->first_msg_id), + rp->first_msg_id); + } + + if (rp->last_msg_id != clib_net_to_host_u16 (mp->last_msg_id)) + { + clib_warning ("WARNING: traced plugin '%s' last message id %d not %d", + mp->plugin_name, clib_net_to_host_u16 (mp->last_msg_id), + rp->last_msg_id); + } +} + +#define foreach_rpc_api_msg \ + _ (RPC_CALL, rpc_call) \ + _ (RPC_CALL_REPLY, rpc_call_reply) + +#define foreach_plugin_trace_msg _ (TRACE_PLUGIN_MSG_IDS, trace_plugin_msg_ids) + +/* + * Set the rpc callback at our earliest possible convenience. + * This avoids ordering issues between thread_init() -> start_workers and + * an init function which we could define here. If we ever intend to use + * vlib all by itself, we can't create a link-time dependency on + * an init function here and a typical "call foo_init first" + * guitar lick. + */ + +extern void *rpc_call_main_thread_cb_fn; + +static clib_error_t * +rpc_api_hookup (vlib_main_t *vm) +{ + api_main_t *am = vlibapi_get_main (); +#define _(N, n) \ + vl_msg_api_set_handlers ( \ + VL_API_##N, #n, vl_api_##n##_t_handler, vl_noop_handler, vl_noop_handler, \ + vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0 /* do not trace */); + foreach_rpc_api_msg; +#undef _ + +#define _(N, n) \ + vl_msg_api_set_handlers ( \ + VL_API_##N, #n, vl_api_##n##_t_handler, vl_noop_handler, vl_noop_handler, \ + vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 1 /* do trace */); + foreach_plugin_trace_msg; +#undef _ + + /* No reason to halt the parade to create a trace record... */ + am->is_mp_safe[VL_API_TRACE_PLUGIN_MSG_IDS] = 1; + rpc_call_main_thread_cb_fn = vl_api_rpc_call_main_thread; + return 0; +} + +VLIB_API_INIT_FUNCTION (rpc_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vlibmemory/vlib.api b/src/vlibmemory/vlib.api new file mode 100644 index 00000000000..5e8ba47ba7d --- /dev/null +++ b/src/vlibmemory/vlib.api @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2021 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. + */ + +option version = "1.0.0"; + +/** \brief Process a vpe parser cli string request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param cmd_in_shmem - pointer to cli command string +*/ +define cli +{ + u32 client_index; + u32 context; + u64 cmd_in_shmem; +}; +define cli_inband +{ + u32 client_index; + u32 context; + string cmd[]; +}; + +/** \brief vpe parser cli string response + @param context - sender context, to match reply w/ request + @param retval - return code for request + @param reply_in_shmem - Reply string from cli processing if any +*/ +define cli_reply +{ + u32 context; + i32 retval; + u64 reply_in_shmem; +}; +define cli_inband_reply +{ + u32 context; + i32 retval; + string reply[]; +}; + +/** \brief Get node index using name request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param node_name[] - name of the node +*/ +define get_node_index +{ + u32 client_index; + u32 context; + string node_name[64]; +}; + +/** \brief Get node index using name request + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param node_index - index of the desired node if found, else ~0 +*/ +define get_node_index_reply +{ + u32 context; + i32 retval; + u32 node_index; +}; + +/** \brief Set the next node for a given node request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param node_name[] - node to add the next node to + @param next_name[] - node to add as the next node +*/ +define add_node_next +{ + u32 client_index; + u32 context; + string node_name[64]; + string next_name[64]; +}; + +/** \brief IP Set the next node for a given node response + @param context - sender context, to match reply w/ request + @param retval - return code for the add next node request + @param next_index - the index of the next node if success, else ~0 +*/ +define add_node_next_reply +{ + u32 context; + i32 retval; + u32 next_index; +}; + +/** \brief show_threads display the information about vpp + threads running on system along with their process id, + cpu id, physical core and cpu socket. +*/ +define show_threads +{ + u32 client_index; + u32 context; +}; + +/** \brief thread data + @param id - thread index + @param name - thread name i.e. vpp_main or vpp_wk_0 + @param type - thread type i.e. workers or stats + @param pid - thread Process Id + @param cpu_id - thread pinned to cpu. + "CPUs or Logical cores are the number of physical cores times + the number of threads that can run on each core through + the use of hyperthreading." (from unix.stackexchange.com) + @param core - thread pinned to actual physical core. + @param cpu_socket - thread is running on which cpu socket. +*/ +typedef thread_data +{ + u32 id; + string name[64]; + string type[64]; + u32 pid; + u32 cpu_id; + u32 core; + u32 cpu_socket; +}; + +/** \brief show_threads_reply + @param context - returned sender context, to match reply w/ request + @param retval - return code + @param count - number of threads in thread_data array + @param thread_data - array of thread data +*/ +define show_threads_reply +{ + u32 context; + i32 retval; + u32 count; + vl_api_thread_data_t thread_data[count]; +}; + +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; +}; + +/** \brief Query relative index via node names + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param node_name - name of node to find relative index from + @param next_name - next node from node_name to find relative index of +*/ +define get_next_index +{ + u32 client_index; + u32 context; + string node_name[64]; + string next_name[64]; +}; + +/** \brief Reply for get next node index + @param context - sender context which was passed in the request + @param retval - return value + @param next_index - index of the next_node +*/ +define get_next_index_reply +{ + u32 context; + i32 retval; + u32 next_index; +}; + +/** \brief f64 types are not standardized across the wire. Sense wire format in each direction by sending the f64 value 1.0. + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param f64_one - The constant of 1.0. If you send a different value, expect an rv=VNET_API_ERROR_API_ENDIAN_FAILED. +*/ +define get_f64_endian_value +{ + u32 client_index; + u32 context; + f64 f64_one [default=1.0]; +}; + +/** \brief get_f64_endian_value reply message + @param context - sender context which was passed in the request + @param retval - return value - VNET_API_ERROR_API_ENDIAN_FAILED if f64_one != 1.0 + @param f64_one_result - The value of 'f64 1.0' +*/ +define get_f64_endian_value_reply +{ + u32 context; + u32 retval; + f64 f64_one_result; +}; + +/** \brief Verify f64 wire format by sending a value and receiving the value + 1.0 + @param client_index - opaque cookie to identify the sender. + @param context - sender context, to match reply w/ request. + @param f64_value - The value you want to test. Default: 1.0. +*/ +define get_f64_increment_by_one +{ + u32 client_index; + u32 context; + f64 f64_value [default=1.0]; +}; + +/** \brief get_f64_increment_by_one reply + @param client_index - opaque cookie to identify the sender. + @param context - sender context, to match reply w/ request. + @param f64_value - The input f64_value incremented by 1.0. +*/ +define get_f64_increment_by_one_reply +{ + u32 context; + u32 retval; + f64 f64_value; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */
\ No newline at end of file diff --git a/src/vlibmemory/vlib_api.c b/src/vlibmemory/vlib_api.c index f9ed891f90a..e5d77eb5bf6 100644 --- a/src/vlibmemory/vlib_api.c +++ b/src/vlibmemory/vlib_api.c @@ -1,8 +1,7 @@ /* - *------------------------------------------------------------------ * vlib_api.c VLIB API implementation * - * Copyright (c) 2009 Cisco and/or its affiliates. + * Copyright (c) 2021 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: @@ -14,710 +13,339 @@ * 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 <fcntl.h> -#include <pthread.h> -#include <vppinfra/vec.h> -#include <vppinfra/hash.h> -#include <vppinfra/pool.h> -#include <vppinfra/format.h> -#include <vppinfra/byte_order.h> -#include <vppinfra/elog.h> -#include <vlib/vlib.h> -#include <vlib/unix/unix.h> #include <vlibapi/api.h> #include <vlibmemory/api.h> +#include <vnet/api_errno.h> -/** - * @file - * @brief Binary API messaging via shared memory - * Low-level, primary provisioning interface - */ -/*? %%clicmd:group_label Binary API CLI %% ?*/ -/*? %%syscfg:group_label Binary API configuration %% ?*/ - -#define TRACE_VLIB_MEMORY_QUEUE 0 - -#include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */ +#include <vlibmemory/vlib.api_enum.h> +#include <vlibmemory/vlib.api_types.h> -#define vl_typedefs /* define message structures */ -#include <vlibmemory/vl_memory_api_h.h> -#undef vl_typedefs +u16 msg_id_base; +#define REPLY_MSG_ID_BASE msg_id_base +#include <vlibapi/api_helper_macros.h> -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <vlibmemory/vl_memory_api_h.h> -#undef vl_printfun - -static inline void * -vl_api_trace_plugin_msg_ids_t_print (vl_api_trace_plugin_msg_ids_t * a, - void *handle) +static void +shmem_cli_output (uword arg, u8 *buffer, uword buffer_bytes) { - vl_print (handle, "vl_api_trace_plugin_msg_ids: %s first %u last %u\n", - a->plugin_name, - clib_host_to_net_u16 (a->first_msg_id), - clib_host_to_net_u16 (a->last_msg_id)); - return handle; -} + u8 **shmem_vecp = (u8 **) arg; + u8 *shmem_vec; + void *oldheap; + u32 offset; -/* instantiate all the endian swap functions we know about */ -#define vl_endianfun -#include <vlibmemory/vl_memory_api_h.h> -#undef vl_endianfun + shmem_vec = *shmem_vecp; -static void -vl_api_get_first_msg_id_t_handler (vl_api_get_first_msg_id_t * mp) -{ - vl_api_get_first_msg_id_reply_t *rmp; - vl_api_registration_t *regp; - uword *p; - api_main_t *am = vlibapi_get_main (); - vl_api_msg_range_t *rp; - u8 name[64]; - u16 first_msg_id = ~0; - int rv = -7; /* VNET_API_ERROR_INVALID_VALUE */ + offset = vec_len (shmem_vec); - regp = vl_api_client_index_to_registration (mp->client_index); - if (!regp) - return; + oldheap = vl_msg_push_heap (); - if (am->msg_range_by_name == 0) - goto out; - strncpy ((char *) name, (char *) mp->name, ARRAY_LEN (name)); - name[ARRAY_LEN (name) - 1] = '\0'; - p = hash_get_mem (am->msg_range_by_name, name); - if (p == 0) - goto out; + vec_validate (shmem_vec, offset + buffer_bytes - 1); - rp = vec_elt_at_index (am->msg_ranges, p[0]); - first_msg_id = rp->first_msg_id; - rv = 0; + clib_memcpy (shmem_vec + offset, buffer, buffer_bytes); -out: - rmp = vl_msg_api_alloc (sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID_REPLY); - rmp->context = mp->context; - rmp->retval = ntohl (rv); - rmp->first_msg_id = ntohs (first_msg_id); - vl_api_send_msg (regp, (u8 *) rmp); + vl_msg_pop_heap (oldheap); + + *shmem_vecp = shmem_vec; } -void -vl_api_api_versions_t_handler (vl_api_api_versions_t * mp) +static void +vl_api_cli_t_handler (vl_api_cli_t *mp) { - api_main_t *am = vlibapi_get_main (); - vl_api_api_versions_reply_t *rmp; + vl_api_cli_reply_t *rp; vl_api_registration_t *reg; - u32 nmsg = vec_len (am->api_version_list); - int msg_size = sizeof (*rmp) + sizeof (rmp->api_versions[0]) * nmsg; - int i; + vlib_main_t *vm = vlib_get_main (); + unformat_input_t input; + u8 *shmem_vec = 0; + void *oldheap; reg = vl_api_client_index_to_registration (mp->client_index); if (!reg) return; + ; - rmp = vl_msg_api_alloc (msg_size); - clib_memset (rmp, 0, msg_size); - rmp->_vl_msg_id = ntohs (VL_API_API_VERSIONS_REPLY); - - /* fill in the message */ - rmp->context = mp->context; - rmp->count = htonl (nmsg); + rp = vl_msg_api_alloc (sizeof (*rp)); + rp->_vl_msg_id = ntohs (VL_API_CLI_REPLY + REPLY_MSG_ID_BASE); + rp->context = mp->context; - for (i = 0; i < nmsg; ++i) - { - api_version_t *vl = &am->api_version_list[i]; - rmp->api_versions[i].major = htonl (vl->major); - rmp->api_versions[i].minor = htonl (vl->minor); - rmp->api_versions[i].patch = htonl (vl->patch); - strncpy ((char *) rmp->api_versions[i].name, vl->name, - ARRAY_LEN (rmp->api_versions[i].name)); - rmp->api_versions[i].name[ARRAY_LEN (rmp->api_versions[i].name) - 1] = - '\0'; - } + unformat_init_vector (&input, (u8 *) (uword) mp->cmd_in_shmem); - vl_api_send_msg (reg, (u8 *) rmp); -} + vlib_cli_input (vm, &input, shmem_cli_output, (uword) &shmem_vec); -#define foreach_vlib_api_msg \ -_(GET_FIRST_MSG_ID, get_first_msg_id) \ -_(API_VERSIONS, api_versions) + oldheap = vl_msg_push_heap (); + vec_add1 (shmem_vec, 0); + vl_msg_pop_heap (oldheap); -/* - * vl_api_init - */ -static int -vlib_api_init (void) -{ - vl_msg_api_msg_config_t cfg; - vl_msg_api_msg_config_t *c = &cfg; - - clib_memset (c, 0, sizeof (*c)); - -#define _(N,n) do { \ - c->id = VL_API_##N; \ - c->name = #n; \ - c->handler = vl_api_##n##_t_handler; \ - c->cleanup = vl_noop_handler; \ - c->endian = vl_api_##n##_t_endian; \ - c->print = vl_api_##n##_t_print; \ - c->size = sizeof(vl_api_##n##_t); \ - c->traced = 1; /* trace, so these msgs print */ \ - c->replay = 0; /* don't replay client create/delete msgs */ \ - c->message_bounce = 0; /* don't bounce this message */ \ - vl_msg_api_config(c);} while (0); - - foreach_vlib_api_msg; -#undef _ + rp->reply_in_shmem = (uword) shmem_vec; - return 0; + vl_api_send_msg (reg, (u8 *) rp); } -u64 vector_rate_histogram[SLEEP_N_BUCKETS]; - -/* - * Callback to send ourselves a plugin numbering-space trace msg - */ static void -send_one_plugin_msg_ids_msg (u8 * name, u16 first_msg_id, u16 last_msg_id) +inband_cli_output (uword arg, u8 *buffer, uword buffer_bytes) { - vl_api_trace_plugin_msg_ids_t *mp; - api_main_t *am = vlibapi_get_main (); - vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr; - svm_queue_t *q; + u8 **mem_vecp = (u8 **) arg; + u8 *mem_vec = *mem_vecp; + u32 offset = vec_len (mem_vec); - mp = vl_msg_api_alloc_as_if_client (sizeof (*mp)); - clib_memset (mp, 0, sizeof (*mp)); - - mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_TRACE_PLUGIN_MSG_IDS); - strncpy ((char *) mp->plugin_name, (char *) name, - sizeof (mp->plugin_name) - 1); - mp->first_msg_id = clib_host_to_net_u16 (first_msg_id); - mp->last_msg_id = clib_host_to_net_u16 (last_msg_id); - - q = shmem_hdr->vl_input_queue; - - vl_msg_api_send_shmem (q, (u8 *) & mp); + vec_validate (mem_vec, offset + buffer_bytes - 1); + clib_memcpy (mem_vec + offset, buffer, buffer_bytes); + *mem_vecp = mem_vec; } -void -vl_api_save_msg_table (void) +static void +vl_api_cli_inband_t_handler (vl_api_cli_inband_t *mp) { - u8 *serialized_message_table; - api_main_t *am = vlibapi_get_main (); - u8 *chroot_file; - int fd, rv; - - /* - * Snapshoot the api message table. - */ - if (strstr ((char *) am->save_msg_table_filename, "..") - || index ((char *) am->save_msg_table_filename, '/')) - { - clib_warning ("illegal save-message-table filename '%s'", - am->save_msg_table_filename); - return; - } - - chroot_file = format (0, "/tmp/%s%c", am->save_msg_table_filename, 0); - - fd = creat ((char *) chroot_file, 0644); + vl_api_cli_inband_reply_t *rmp; + int rv = 0; + vlib_main_t *vm = vlib_get_main (); + unformat_input_t input; + u8 *out_vec = 0; + u8 *cmd_vec = 0; - if (fd < 0) + if (vl_msg_api_get_msg_length (mp) < + vl_api_string_len (&mp->cmd) + sizeof (*mp)) { - clib_unix_warning ("creat"); - return; + rv = -1; + goto error; } - serialized_message_table = vl_api_serialize_message_table (am, 0); + cmd_vec = vl_api_from_api_to_new_vec (mp, &mp->cmd); - rv = write (fd, serialized_message_table, - vec_len (serialized_message_table)); + unformat_init_string (&input, (char *) cmd_vec, + vl_api_string_len (&mp->cmd)); + rv = vlib_cli_input (vm, &input, inband_cli_output, (uword) &out_vec); + unformat_free (&input); - if (rv != vec_len (serialized_message_table)) - clib_unix_warning ("write"); - - rv = close (fd); - if (rv < 0) - clib_unix_warning ("close"); - - vec_free (chroot_file); - vec_free (serialized_message_table); +error: + REPLY_MACRO3 (VL_API_CLI_INBAND_REPLY, vec_len (out_vec), + ({ vl_api_vec_to_api_string (out_vec, &rmp->reply); })); + vec_free (out_vec); + vec_free (cmd_vec); } -clib_error_t *vat_builtin_main_init (vlib_main_t * vm) __attribute__ ((weak)); -clib_error_t * -vat_builtin_main_init (vlib_main_t * vm) -{ - return 0; -} - -static uword -vl_api_clnt_process (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * f) +static void +vl_api_get_node_index_t_handler (vl_api_get_node_index_t *mp) { - vlib_global_main_t *vgm = vlib_get_global_main (); - int private_segment_rotor = 0, i, rv; - vl_socket_args_for_process_t *a; - vl_shmem_hdr_t *shm; - svm_queue_t *q; - clib_error_t *e; - api_main_t *am = vlibapi_get_main (); - f64 dead_client_scan_time; - f64 sleep_time, start_time; - f64 vector_rate; - clib_error_t *error; - uword event_type; - uword *event_data = 0; - f64 now; - - if ((error = vl_sock_api_init (vm))) - { - clib_error_report (error); - clib_warning ("socksvr_api_init failed, quitting..."); - return 0; - } + vlib_main_t *vm = vlib_get_main (); + vl_api_get_node_index_reply_t *rmp; + vlib_node_t *n; + int rv = 0; + u32 node_index = ~0; - if ((rv = vlib_api_init ()) < 0) - { - clib_warning ("vlib_api_init returned %d, quitting...", rv); - return 0; - } + n = vlib_get_node_by_name (vm, mp->node_name); - shm = am->shmem_hdr; - q = shm->vl_input_queue; + if (n == 0) + rv = VNET_API_ERROR_NO_SUCH_NODE; + else + node_index = n->index; - e = vlib_call_init_exit_functions (vm, &vgm->api_init_function_registrations, - 1 /* call_once */, 1 /* is_global */); - if (e) - clib_error_report (e); + REPLY_MACRO2 (VL_API_GET_NODE_INDEX_REPLY, + ({ rmp->node_index = htonl (node_index); })); +} - e = vat_builtin_main_init (vm); - if (e) - clib_error_report (e); +static void +vl_api_add_node_next_t_handler (vl_api_add_node_next_t *mp) +{ + vlib_main_t *vm = vlib_get_main (); + vl_api_add_node_next_reply_t *rmp; + vlib_node_t *n, *next; + int rv = 0; + u32 next_index = ~0; - sleep_time = 10.0; - dead_client_scan_time = vlib_time_now (vm) + 10.0; + n = vlib_get_node_by_name (vm, mp->node_name); - /* - * Send plugin message range messages for each plugin we loaded - */ - for (i = 0; i < vec_len (am->msg_ranges); i++) + if (n == 0) { - vl_api_msg_range_t *rp = am->msg_ranges + i; - send_one_plugin_msg_ids_msg (rp->name, rp->first_msg_id, - rp->last_msg_id); + rv = VNET_API_ERROR_NO_SUCH_NODE; + goto out; } - /* - * Save the api message table snapshot, if configured - */ - if (am->save_msg_table_filename) - vl_api_save_msg_table (); + next = vlib_get_node_by_name (vm, mp->next_name); - /* $$$ pay attention to frame size, control CPU usage */ - while (1) - { - /* - * There's a reason for checking the queue before - * sleeping. If the vlib application crashes, it's entirely - * possible for a client to enqueue a connect request - * during the process restart interval. - * - * Unless some force of physics causes the new incarnation - * of the application to process the request, the client will - * sit and wait for Godot... - */ - vector_rate = (f64) vlib_last_vectors_per_main_loop (vm); - start_time = vlib_time_now (vm); - while (1) - { - if (vl_mem_api_handle_rpc (vm, node) - || vl_mem_api_handle_msg_main (vm, node)) - { - vm->api_queue_nonempty = 0; - VL_MEM_API_LOG_Q_LEN ("q-underflow: len %d", 0); - sleep_time = 20.0; - break; - } - - /* Allow no more than 10us without a pause */ - if (vlib_time_now (vm) > start_time + 10e-6) - { - int index = SLEEP_400_US; - if (vector_rate > 40.0) - sleep_time = 400e-6; - else if (vector_rate > 20.0) - { - index = SLEEP_200_US; - sleep_time = 200e-6; - } - else if (vector_rate >= 1.0) - { - index = SLEEP_100_US; - sleep_time = 100e-6; - } - else - { - index = SLEEP_10_US; - sleep_time = 10e-6; - } - vector_rate_histogram[index] += 1; - break; - } - } - - /* - * see if we have any private api shared-memory segments - * If so, push required context variables, and process - * a message. - */ - if (PREDICT_FALSE (vec_len (am->vlib_private_rps))) - { - if (private_segment_rotor >= vec_len (am->vlib_private_rps)) - private_segment_rotor = 0; - vl_mem_api_handle_msg_private (vm, node, private_segment_rotor++); - } - - vlib_process_wait_for_event_or_clock (vm, sleep_time); - vec_reset_length (event_data); - event_type = vlib_process_get_events (vm, &event_data); - now = vlib_time_now (vm); - - switch (event_type) - { - case QUEUE_SIGNAL_EVENT: - vm->queue_signal_pending = 0; - VL_MEM_API_LOG_Q_LEN ("q-awake: len %d", q->cursize); - - break; - case SOCKET_READ_EVENT: - for (i = 0; i < vec_len (event_data); i++) - { - vl_api_registration_t *regp; - - a = pool_elt_at_index (socket_main.process_args, event_data[i]); - regp = vl_socket_get_registration (a->reg_index); - if (regp) - { - vl_socket_process_api_msg (regp, (i8 *) a->data); - a = pool_elt_at_index (socket_main.process_args, - event_data[i]); - } - vec_free (a->data); - pool_put (socket_main.process_args, a); - } - break; - - /* Timeout... */ - case -1: - break; - - default: - clib_warning ("unknown event type %d", event_type); - break; - } - - if (now > dead_client_scan_time) - { - vl_mem_api_dead_client_scan (am, shm, now); - dead_client_scan_time = vlib_time_now (vm) + 10.0; - } - } + if (next == 0) + rv = VNET_API_ERROR_NO_SUCH_NODE2; + else + next_index = vlib_node_add_next (vm, n->index, next->index); - return 0; -} -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (vl_api_clnt_node) = -{ - .function = vl_api_clnt_process, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "api-rx-from-ring", - .state = VLIB_NODE_STATE_DISABLED, - .process_log2_n_stack_bytes = 18, -}; -/* *INDENT-ON* */ - -void -vl_mem_api_enable_disable (vlib_main_t * vm, int enable) -{ - vlib_node_set_state (vm, vl_api_clnt_node.index, - (enable - ? VLIB_NODE_STATE_POLLING - : VLIB_NODE_STATE_DISABLED)); +out: + REPLY_MACRO2 (VL_API_ADD_NODE_NEXT_REPLY, + ({ rmp->next_index = htonl (next_index); })); } -static uword -api_rx_from_node (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +static void +get_thread_data (vl_api_thread_data_t *td, int index) { - uword n_packets = frame->n_vectors; - uword n_left_from; - u32 *from; - static u8 *long_msg; - - vec_validate (long_msg, 4095); - n_left_from = frame->n_vectors; - from = vlib_frame_vector_args (frame); - - while (n_left_from > 0) - { - u32 bi0; - vlib_buffer_t *b0; - void *msg; - uword msg_len; - - bi0 = from[0]; - b0 = vlib_get_buffer (vm, bi0); - from += 1; - n_left_from -= 1; - - msg = b0->data + b0->current_data; - msg_len = b0->current_length; - if (b0->flags & VLIB_BUFFER_NEXT_PRESENT) - { - ASSERT (long_msg != 0); - _vec_len (long_msg) = 0; - vec_add (long_msg, msg, msg_len); - while (b0->flags & VLIB_BUFFER_NEXT_PRESENT) - { - b0 = vlib_get_buffer (vm, b0->next_buffer); - msg = b0->data + b0->current_data; - msg_len = b0->current_length; - vec_add (long_msg, msg, msg_len); - } - msg = long_msg; - } - vl_msg_api_handler_no_trace_no_free (msg); - } - - /* Free what we've been given. */ - vlib_buffer_free (vm, vlib_frame_vector_args (frame), n_packets); - - return n_packets; + vlib_worker_thread_t *w = vlib_worker_threads + index; + td->id = htonl (index); + if (w->name) + strncpy ((char *) td->name, (char *) w->name, ARRAY_LEN (td->name) - 1); + if (w->registration) + strncpy ((char *) td->type, (char *) w->registration->name, + ARRAY_LEN (td->type) - 1); + td->pid = htonl (w->lwp); + td->cpu_id = htonl (w->cpu_id); + td->core = htonl (w->core_id); + td->cpu_socket = htonl (w->numa_id); } -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (api_rx_from_node_node,static) = { - .function = api_rx_from_node, - .type = VLIB_NODE_TYPE_INTERNAL, - .vector_size = 4, - .name = "api-rx-from-node", -}; -/* *INDENT-ON* */ - static void -vl_api_rpc_call_t_handler (vl_api_rpc_call_t * mp) +vl_api_show_threads_t_handler (vl_api_show_threads_t *mp) { - vl_api_rpc_call_reply_t *rmp; - int (*fp) (void *); - i32 rv = 0; - vlib_main_t *vm = vlib_get_main (); - - if (mp->function == 0) - { - rv = -1; - clib_warning ("rpc NULL function pointer"); - } + int count = 0; - else - { - if (mp->need_barrier_sync) - vlib_worker_thread_barrier_sync (vm); +#if !defined(__powerpc64__) + vl_api_registration_t *reg; + vl_api_show_threads_reply_t *rmp; + vl_api_thread_data_t *td; + int i, msg_size = 0; + count = vec_len (vlib_worker_threads); + if (!count) + return; - fp = uword_to_pointer (mp->function, int (*)(void *)); - rv = fp (mp->data); + msg_size = sizeof (*rmp) + sizeof (rmp->thread_data[0]) * count; + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; - if (mp->need_barrier_sync) - vlib_worker_thread_barrier_release (vm); - } + rmp = vl_msg_api_alloc (msg_size); + clib_memset (rmp, 0, msg_size); + rmp->_vl_msg_id = htons (VL_API_SHOW_THREADS_REPLY + REPLY_MSG_ID_BASE); + rmp->context = mp->context; + rmp->count = htonl (count); + td = rmp->thread_data; - if (mp->send_reply) + for (i = 0; i < count; i++) { - svm_queue_t *q = vl_api_client_index_to_input_queue (mp->client_index); - if (q) - { - rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_RPC_CALL_REPLY); - rmp->context = mp->context; - rmp->retval = rv; - vl_msg_api_send_shmem (q, (u8 *) & rmp); - } + get_thread_data (&td[i], i); } - if (mp->multicast) - { - clib_warning ("multicast not yet implemented..."); - } -} -static void -vl_api_rpc_call_reply_t_handler (vl_api_rpc_call_reply_t * mp) -{ - clib_warning ("unimplemented"); -} - -void -vl_api_send_pending_rpc_requests (vlib_main_t * vm) -{ - vlib_main_t *vm_global = vlib_get_first_main (); - - ASSERT (vm != vm_global); + vl_api_send_msg (reg, (u8 *) rmp); +#else - clib_spinlock_lock_if_init (&vm_global->pending_rpc_lock); - vec_append (vm_global->pending_rpc_requests, vm->pending_rpc_requests); - vec_reset_length (vm->pending_rpc_requests); - clib_spinlock_unlock_if_init (&vm_global->pending_rpc_lock); + /* unimplemented support */ + rv = -9; + clib_warning ("power pc does not support show threads api"); + REPLY_MACRO2 (VL_API_SHOW_THREADS_REPLY, ({ rmp->count = htonl (count); })); +#endif } -always_inline void -vl_api_rpc_call_main_thread_inline (void *fp, u8 * data, u32 data_length, - u8 force_rpc) +static void +vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t *mp) { - vl_api_rpc_call_t *mp; - vlib_main_t *vm_global = vlib_get_first_main (); + int rv = 0; + u8 *vector = 0; vlib_main_t *vm = vlib_get_main (); + void *oldheap; + vl_api_get_node_graph_reply_t *rmp; + static vlib_node_t ***node_dups; + static vlib_main_t **stat_vms; - /* Main thread and not a forced RPC: call the function directly */ - if ((force_rpc == 0) && (vlib_get_thread_index () == 0)) - { - void (*call_fp) (void *); - - vlib_worker_thread_barrier_sync (vm); + oldheap = vl_msg_push_heap (); - call_fp = fp; - call_fp (data); + /* + * Keep the number of memcpy ops to a minimum (e.g. 1). + */ + vec_validate (vector, 16384); + vec_reset_length (vector); - vlib_worker_thread_barrier_release (vm); - return; - } + vlib_node_get_nodes (vm, 0 /* main threads */, 0 /* include stats */, + 1 /* barrier sync */, &node_dups, &stat_vms); + vector = vlib_node_serialize (vm, node_dups, vector, 1 /* include nexts */, + 1 /* include stats */); - /* Otherwise, actually do an RPC */ - mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + data_length); - - clib_memset (mp, 0, sizeof (*mp)); - clib_memcpy_fast (mp->data, data, data_length); - mp->_vl_msg_id = ntohs (VL_API_RPC_CALL); - mp->function = pointer_to_uword (fp); - mp->need_barrier_sync = 1; - - /* Add to the pending vector. Thread 0 requires locking. */ - if (vm == vm_global) - clib_spinlock_lock_if_init (&vm_global->pending_rpc_lock); - vec_add1 (vm->pending_rpc_requests, (uword) mp); - if (vm == vm_global) - clib_spinlock_unlock_if_init (&vm_global->pending_rpc_lock); -} + vl_msg_pop_heap (oldheap); -/* - * Check if called from worker threads. - * If so, make rpc call of fp through shmem. - * Otherwise, call fp directly - */ -void -vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length) -{ - vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */ - 0); -} - -/* - * Always make rpc call of fp through shmem, useful for calling from threads - * not setup as worker threads, such as DPDK callback thread - */ -void -vl_api_force_rpc_call_main_thread (void *fp, u8 * data, u32 data_length) -{ - vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */ - 1); + REPLY_MACRO2 (VL_API_GET_NODE_GRAPH_REPLY, + ({ rmp->reply_in_shmem = (uword) vector; })); } static void -vl_api_trace_plugin_msg_ids_t_handler (vl_api_trace_plugin_msg_ids_t * mp) +vl_api_get_next_index_t_handler (vl_api_get_next_index_t *mp) { - api_main_t *am = vlibapi_get_main (); - vl_api_msg_range_t *rp; + vlib_main_t *vm = vlib_get_main (); + vl_api_get_next_index_reply_t *rmp; + vlib_node_t *node, *next_node; + int rv = 0; + u32 next_node_index = ~0, next_index = ~0; uword *p; - /* Noop (except for tracing) during normal operation */ - if (am->replay_in_progress == 0) - return; + node = vlib_get_node_by_name (vm, mp->node_name); - p = hash_get_mem (am->msg_range_by_name, mp->plugin_name); - if (p == 0) + if (node == 0) { - clib_warning ("WARNING: traced plugin '%s' not in current image", - mp->plugin_name); - return; + rv = VNET_API_ERROR_NO_SUCH_NODE; + goto out; } - rp = vec_elt_at_index (am->msg_ranges, p[0]); - if (rp->first_msg_id != clib_net_to_host_u16 (mp->first_msg_id)) + next_node = vlib_get_node_by_name (vm, mp->next_name); + + if (next_node == 0) { - clib_warning ("WARNING: traced plugin '%s' first message id %d not %d", - mp->plugin_name, clib_net_to_host_u16 (mp->first_msg_id), - rp->first_msg_id); + rv = VNET_API_ERROR_NO_SUCH_NODE2; + goto out; } + else + next_node_index = next_node->index; - if (rp->last_msg_id != clib_net_to_host_u16 (mp->last_msg_id)) + p = hash_get (node->next_slot_by_node, next_node_index); + + if (p == 0) { - clib_warning ("WARNING: traced plugin '%s' last message id %d not %d", - mp->plugin_name, clib_net_to_host_u16 (mp->last_msg_id), - rp->last_msg_id); + rv = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; } -} + else + next_index = p[0]; -#define foreach_rpc_api_msg \ -_(RPC_CALL,rpc_call) \ -_(RPC_CALL_REPLY,rpc_call_reply) +out: + REPLY_MACRO2 (VL_API_GET_NEXT_INDEX_REPLY, + ({ rmp->next_index = htonl (next_index); })); +} -#define foreach_plugin_trace_msg \ -_(TRACE_PLUGIN_MSG_IDS,trace_plugin_msg_ids) +static void +vl_api_get_f64_endian_value_t_handler (vl_api_get_f64_endian_value_t *mp) +{ + int rv = 0; + f64 one = 1.0; + vl_api_get_f64_endian_value_reply_t *rmp; + if (1.0 != clib_net_to_host_f64 (mp->f64_one)) + rv = VNET_API_ERROR_API_ENDIAN_FAILED; + + REPLY_MACRO2 (VL_API_GET_F64_ENDIAN_VALUE_REPLY, + ({ rmp->f64_one_result = clib_host_to_net_f64 (one); })); +} -/* - * Set the rpc callback at our earliest possible convenience. - * This avoids ordering issues between thread_init() -> start_workers and - * an init function which we could define here. If we ever intend to use - * vlib all by itself, we can't create a link-time dependency on - * an init function here and a typical "call foo_init first" - * guitar lick. - */ +static void +vl_api_get_f64_increment_by_one_t_handler ( + vl_api_get_f64_increment_by_one_t *mp) +{ + int rv = 0; + vl_api_get_f64_increment_by_one_reply_t *rmp; -extern void *rpc_call_main_thread_cb_fn; + REPLY_MACRO2 (VL_API_GET_F64_INCREMENT_BY_ONE_REPLY, ({ + rmp->f64_value = clib_host_to_net_f64 ( + clib_net_to_host_f64 (mp->f64_value) + 1.0); + })); +} +#include <vlibmemory/vlib.api.c> static clib_error_t * -rpc_api_hookup (vlib_main_t * vm) +vlib_apis_hookup (vlib_main_t *vm) { api_main_t *am = vlibapi_get_main (); -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 0 /* do not trace */); - foreach_rpc_api_msg; -#undef _ - -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1 /* do trace */); - foreach_plugin_trace_msg; -#undef _ - - /* No reason to halt the parade to create a trace record... */ - am->is_mp_safe[VL_API_TRACE_PLUGIN_MSG_IDS] = 1; - rpc_call_main_thread_cb_fn = vl_api_rpc_call_main_thread; + + /* + * Set up the (msg_name, crc, message-id) table + */ + msg_id_base = setup_message_id_table (); + + am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1; + return 0; } -VLIB_API_INIT_FUNCTION (rpc_api_hookup); +VLIB_API_INIT_FUNCTION (vlib_apis_hookup); /* * fd.io coding-style-patch-verification: ON diff --git a/src/vlibmemory/vlibapi_test.c b/src/vlibmemory/vlibapi_test.c new file mode 100644 index 00000000000..820096ab80d --- /dev/null +++ b/src/vlibmemory/vlibapi_test.c @@ -0,0 +1,470 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2021 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 <vat/vat.h> +#include <vlibapi/api.h> +#include <vlibmemory/api.h> +#include <vppinfra/error.h> + +#include <vpp/api/types.h> +#include <vnet/mpls/packet.h> +#include <vnet/ip/ip_types_api.h> + +typedef struct +{ + u16 msg_id_base; + vat_main_t *vat_main; +} vlib_test_main_t; +vlib_test_main_t vlib_test_main; + +#define __plugin_msg_base vlib_test_main.msg_id_base +#include <vlibapi/vat_helper_macros.h> + +/* Declare message IDs */ +#include <vlibmemory/vlib.api_enum.h> +#include <vlibmemory/vlib.api_types.h> + +static void +vl_api_cli_reply_t_handler (vl_api_cli_reply_t *mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->shmem_result = uword_to_pointer (mp->reply_in_shmem, u8 *); + vam->result_ready = 1; +} + +static void +vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t *mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vec_reset_length (vam->cmd_reply); + + vam->retval = retval; + if (retval == 0) + vam->cmd_reply = vl_api_from_api_to_new_vec (mp, &mp->reply); + vam->result_ready = 1; +} + +static void +vl_api_get_node_index_reply_t_handler (vl_api_get_node_index_reply_t *mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0) + errmsg ("node index %d", ntohl (mp->node_index)); + vam->result_ready = 1; + } +} + +static void +vl_api_get_next_index_reply_t_handler (vl_api_get_next_index_reply_t *mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0) + errmsg ("next node index %d", ntohl (mp->next_index)); + vam->result_ready = 1; + } +} + +static void +vl_api_add_node_next_reply_t_handler (vl_api_add_node_next_reply_t *mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0) + errmsg ("next index %d", ntohl (mp->next_index)); + vam->result_ready = 1; + } +} + +static void +vl_api_get_f64_endian_value_reply_t_handler ( + vl_api_get_f64_endian_value_reply_t *mp) +{ + // not yet implemented +} + +static void +vl_api_get_f64_increment_by_one_reply_t_handler ( + vl_api_get_f64_increment_by_one_reply_t *mp) +{ + // not yet implemented +} + +static int +api_get_f64_endian_value (vat_main_t *vam) +{ + // not yet implemented + return -1; +} + +static int +api_get_f64_increment_by_one (vat_main_t *vam) +{ + // not yet implemented + return -1; +} + +/* + * Pass CLI buffers directly in the CLI_INBAND API message, + * instead of an additional shared memory area. + */ +static int +exec_inband (vat_main_t *vam) +{ + vl_api_cli_inband_t *mp; + unformat_input_t *i = vam->input; + int ret; + + if (vec_len (i->buffer) == 0) + return -1; + + if (vam->exec_mode == 0 && unformat (i, "mode")) + { + vam->exec_mode = 1; + return 0; + } + if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit"))) + { + vam->exec_mode = 0; + return 0; + } + + /* + * In order for the CLI command to work, it + * must be a vector ending in \n, not a C-string ending + * in \n\0. + */ + M2 (CLI_INBAND, mp, vec_len (vam->input->buffer)); + vl_api_vec_to_api_string (vam->input->buffer, &mp->cmd); + + S (mp); + W (ret); + /* json responses may or may not include a useful reply... */ + if (vec_len (vam->cmd_reply)) + print (vam->ofp, "%v", (char *) (vam->cmd_reply)); + return ret; +} +static int +api_cli_inband (vat_main_t *vam) +{ + return exec_inband (vam); +} + +int +exec (vat_main_t *vam) +{ + return exec_inband (vam); +} + +static int +api_cli (vat_main_t *vam) +{ + return exec (vam); +} + +static int +api_get_node_index (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_get_node_index_t *mp; + u8 *name = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node %s", &name)) + ; + else + break; + } + if (name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + + M (GET_NODE_INDEX, mp); + clib_memcpy (mp->node_name, name, vec_len (name)); + vec_free (name); + + S (mp); + W (ret); + return ret; +} + +static int +api_get_next_index (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_get_next_index_t *mp; + u8 *node_name = 0, *next_node_name = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node-name %s", &node_name)) + ; + else if (unformat (i, "next-node-name %s", &next_node_name)) + break; + } + + if (node_name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (node_name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + + if (next_node_name == 0) + { + errmsg ("next node name required"); + return -99; + } + if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name)) + { + errmsg ("next node name too long, max %d", ARRAY_LEN (mp->next_name)); + return -99; + } + + M (GET_NEXT_INDEX, mp); + clib_memcpy (mp->node_name, node_name, vec_len (node_name)); + clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name)); + vec_free (node_name); + vec_free (next_node_name); + + S (mp); + W (ret); + return ret; +} + +static int +api_add_node_next (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_add_node_next_t *mp; + u8 *name = 0; + u8 *next = 0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node %s", &name)) + ; + else if (unformat (i, "next %s", &next)) + ; + else + break; + } + if (name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + if (next == 0) + { + errmsg ("next node required"); + return -99; + } + if (vec_len (next) >= ARRAY_LEN (mp->next_name)) + { + errmsg ("next name too long, max %d", ARRAY_LEN (mp->next_name)); + return -99; + } + + M (ADD_NODE_NEXT, mp); + clib_memcpy (mp->node_name, name, vec_len (name)); + clib_memcpy (mp->next_name, next, vec_len (next)); + vec_free (name); + vec_free (next); + + S (mp); + W (ret); + return ret; +} + +static void +vl_api_show_threads_reply_t_handler (vl_api_show_threads_reply_t *mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + int i, count = 0; + + if (retval >= 0) + count = ntohl (mp->count); + + for (i = 0; i < count; i++) + print (vam->ofp, "\n%-2d %-11s %-11s %-5d %-6d %-4d %-6d", + ntohl (mp->thread_data[i].id), mp->thread_data[i].name, + mp->thread_data[i].type, ntohl (mp->thread_data[i].pid), + ntohl (mp->thread_data[i].cpu_id), ntohl (mp->thread_data[i].core), + ntohl (mp->thread_data[i].cpu_socket)); + + vam->retval = retval; + vam->result_ready = 1; +} + +static int +api_show_threads (vat_main_t *vam) +{ + vl_api_show_threads_t *mp; + int ret; + + print (vam->ofp, "\n%-2s %-11s %-11s %-5s %-6s %-4s %-6s", "ID", "Name", + "Type", "LWP", "cpu_id", "Core", "Socket"); + + M (SHOW_THREADS, mp); + + S (mp); + W (ret); + return ret; +} + +static void +vl_api_get_node_graph_reply_t_handler (vl_api_get_node_graph_reply_t *mp) +{ + vat_main_t *vam = &vat_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 = uword_to_pointer (mp->reply_in_shmem, u8 *); + pvt_copy = vec_dup (reply); + + /* Toss the shared-memory original... */ + oldheap = vl_msg_push_heap (); + + vec_free (reply); + + vl_msg_pop_heap (oldheap); + + if (vam->graph_nodes) + { + hash_free (vam->graph_node_index_by_name); + + for (i = 0; i < vec_len (vam->graph_nodes[0]); i++) + { + node = vam->graph_nodes[0][i]; + vec_free (node->name); + vec_free (node->next_nodes); + vec_free (node); + } + vec_free (vam->graph_nodes[0]); + 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[0]); i++) + { + node = vam->graph_nodes[0][i]; + hash_set_mem (vam->graph_node_index_by_name, node->name, i); + } +} + +static int +api_get_node_graph (vat_main_t *vam) +{ + vl_api_get_node_graph_t *mp; + int ret; + + M (GET_NODE_GRAPH, mp); + + /* send it... */ + S (mp); + /* Wait for the reply */ + W (ret); + return ret; +} + +#define VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE local_setup_message_id_table +static void +local_setup_message_id_table (vat_main_t *vam) +{ + /* Add exec as an alias for cli_inband */ + hash_set_mem (vam->function_by_name, "exec", api_cli_inband); + hash_set_mem (vam->help_by_name, "exec", + "usage: exec <vpe-debug-CLI-command>"); +} + +#include <vlibmemory/vlib.api_test.c> + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index 68133308b76..2dbde7c5259 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -1520,6 +1520,12 @@ add_vpp_library (vatclient DEPENDS api_headers ) +add_vat_test_library(vnet + ip/ip_test.c + arp/arp_test.c + ip6-nd/ip6_nd_test.c +) + ############################################################################## # VAT2 plugins ############################################################################## diff --git a/src/vnet/arp/arp_test.c b/src/vnet/arp/arp_test.c index 29eeeb59d0f..b92fa06f9f6 100644 --- a/src/vnet/arp/arp_test.c +++ b/src/vnet/arp/arp_test.c @@ -158,8 +158,6 @@ api_proxy_arp_intfc_enable_disable (vat_main_t * vam) #include <vnet/arp/arp.api_test.c> -VAT_REGISTER_FEATURE_FUNCTION (vat_arp_plugin_register); - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/ip/ip_test.c b/src/vnet/ip/ip_test.c index 6bdeca5ff32..81a84c12a3b 100644 --- a/src/vnet/ip/ip_test.c +++ b/src/vnet/ip/ip_test.c @@ -1547,8 +1547,6 @@ vl_api_ip_details_t_handler (vl_api_ip_details_t *mp) #include <vnet/ip/ip.api_test.c> -VAT_REGISTER_FEATURE_FUNCTION (vat_ip_plugin_register); - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/ip6-nd/ip6_nd_test.c b/src/vnet/ip6-nd/ip6_nd_test.c index 5ca37029a76..99f869a5a1d 100644 --- a/src/vnet/ip6-nd/ip6_nd_test.c +++ b/src/vnet/ip6-nd/ip6_nd_test.c @@ -318,6 +318,12 @@ api_sw_interface_ip6nd_ra_config (vat_main_t * vam) W (ret); return ret; } +static int +api_ip6nd_proxy_enable_disable (vat_main_t *vam) +{ + // not yet implemented + return -1; +} #include <ip6-nd/ip6_nd.api_test.c> diff --git a/src/vpp/CMakeLists.txt b/src/vpp/CMakeLists.txt index e15037cccb7..32f702de36d 100644 --- a/src/vpp/CMakeLists.txt +++ b/src/vpp/CMakeLists.txt @@ -73,8 +73,6 @@ if(VPP_API_TEST_BUILTIN) api/api_main.c api/plugin.c api/types.c - ../vnet/arp/arp_test.c - ../vnet/ip/ip_test.c ) add_definitions(-DVPP_API_TEST_BUILTIN=1) endif() diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index b935c002228..5477ec949ae 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -76,20 +76,11 @@ #undef vl_printfun #include <vlibapi/api_helper_macros.h> -#define foreach_vpe_api_msg \ -_(CONTROL_PING, control_ping) \ -_(CLI, cli) \ -_(CLI_INBAND, cli_inband) \ -_(GET_NODE_INDEX, get_node_index) \ -_(ADD_NODE_NEXT, add_node_next) \ -_(SHOW_VERSION, show_version) \ -_(SHOW_THREADS, show_threads) \ -_(GET_NODE_GRAPH, get_node_graph) \ -_(GET_NEXT_INDEX, get_next_index) \ -_(LOG_DUMP, log_dump) \ -_(SHOW_VPE_SYSTEM_TIME, show_vpe_system_time) \ -_(GET_F64_ENDIAN_VALUE, get_f64_endian_value) \ -_(GET_F64_INCREMENT_BY_ONE, get_f64_increment_by_one) \ +#define foreach_vpe_api_msg \ + _ (CONTROL_PING, control_ping) \ + _ (SHOW_VERSION, show_version) \ + _ (SHOW_VPE_SYSTEM_TIME, show_vpe_system_time) \ + _ (LOG_DUMP, log_dump) #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) @@ -139,108 +130,6 @@ vl_api_control_ping_t_handler (vl_api_control_ping_t * mp) } static void -shmem_cli_output (uword arg, u8 * buffer, uword buffer_bytes) -{ - u8 **shmem_vecp = (u8 **) arg; - u8 *shmem_vec; - void *oldheap; - u32 offset; - - shmem_vec = *shmem_vecp; - - offset = vec_len (shmem_vec); - - oldheap = vl_msg_push_heap (); - - vec_validate (shmem_vec, offset + buffer_bytes - 1); - - clib_memcpy (shmem_vec + offset, buffer, buffer_bytes); - - vl_msg_pop_heap (oldheap); - - *shmem_vecp = shmem_vec; -} - - -static void -vl_api_cli_t_handler (vl_api_cli_t * mp) -{ - vl_api_cli_reply_t *rp; - vl_api_registration_t *reg; - vlib_main_t *vm = vlib_get_main (); - unformat_input_t input; - u8 *shmem_vec = 0; - void *oldheap; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return;; - - rp = vl_msg_api_alloc (sizeof (*rp)); - rp->_vl_msg_id = ntohs (VL_API_CLI_REPLY); - rp->context = mp->context; - - unformat_init_vector (&input, (u8 *) (uword) mp->cmd_in_shmem); - - vlib_cli_input (vm, &input, shmem_cli_output, (uword) & shmem_vec); - - oldheap = vl_msg_push_heap (); - vec_add1 (shmem_vec, 0); - vl_msg_pop_heap (oldheap); - - rp->reply_in_shmem = (uword) shmem_vec; - - vl_api_send_msg (reg, (u8 *) rp); -} - -static void -inband_cli_output (uword arg, u8 * buffer, uword buffer_bytes) -{ - u8 **mem_vecp = (u8 **) arg; - u8 *mem_vec = *mem_vecp; - u32 offset = vec_len (mem_vec); - - vec_validate (mem_vec, offset + buffer_bytes - 1); - clib_memcpy (mem_vec + offset, buffer, buffer_bytes); - *mem_vecp = mem_vec; -} - -static void -vl_api_cli_inband_t_handler (vl_api_cli_inband_t * mp) -{ - vl_api_cli_inband_reply_t *rmp; - int rv = 0; - vlib_main_t *vm = vlib_get_main (); - unformat_input_t input; - u8 *out_vec = 0; - u8 *cmd_vec = 0; - - if (vl_msg_api_get_msg_length (mp) < - vl_api_string_len (&mp->cmd) + sizeof (*mp)) - { - rv = -1; - goto error; - } - - cmd_vec = vl_api_from_api_to_new_vec (mp, &mp->cmd); - - unformat_init_string (&input, (char *) cmd_vec, - vl_api_string_len (&mp->cmd)); - rv = vlib_cli_input (vm, &input, inband_cli_output, (uword) & out_vec); - unformat_free (&input); - -error: - /* *INDENT-OFF* */ - REPLY_MACRO3(VL_API_CLI_INBAND_REPLY, vec_len (out_vec), - ({ - vl_api_vec_to_api_string(out_vec, &rmp->reply); - })); - /* *INDENT-ON* */ - vec_free (out_vec); - vec_free (cmd_vec); -} - -static void vl_api_show_version_t_handler (vl_api_show_version_t * mp) { vl_api_show_version_reply_t *rmp; @@ -264,204 +153,14 @@ vl_api_show_version_t_handler (vl_api_show_version_t * mp) } static void -get_thread_data (vl_api_thread_data_t * td, int index) +vl_api_show_vpe_system_time_t_handler (vl_api_show_vpe_system_time_t *mp) { - vlib_worker_thread_t *w = vlib_worker_threads + index; - td->id = htonl (index); - if (w->name) - strncpy ((char *) td->name, (char *) w->name, ARRAY_LEN (td->name) - 1); - if (w->registration) - strncpy ((char *) td->type, (char *) w->registration->name, - ARRAY_LEN (td->type) - 1); - td->pid = htonl (w->lwp); - td->cpu_id = htonl (w->cpu_id); - td->core = htonl (w->core_id); - td->cpu_socket = htonl (w->numa_id); -} - -static void -vl_api_show_threads_t_handler (vl_api_show_threads_t * mp) -{ - int count = 0; - -#if !defined(__powerpc64__) - vl_api_registration_t *reg; - vl_api_show_threads_reply_t *rmp; - vl_api_thread_data_t *td; - int i, msg_size = 0; - count = vec_len (vlib_worker_threads); - if (!count) - return; - - msg_size = sizeof (*rmp) + sizeof (rmp->thread_data[0]) * count; - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return; - - rmp = vl_msg_api_alloc (msg_size); - clib_memset (rmp, 0, msg_size); - rmp->_vl_msg_id = htons (VL_API_SHOW_THREADS_REPLY); - rmp->context = mp->context; - rmp->count = htonl (count); - td = rmp->thread_data; - - for (i = 0; i < count; i++) - { - get_thread_data (&td[i], i); - } - - vl_api_send_msg (reg, (u8 *) rmp); -#else - - /* unimplemented support */ - rv = -9; - clib_warning ("power pc does not support show threads api"); - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_SHOW_THREADS_REPLY, - ({ - rmp->count = htonl(count); - })); - /* *INDENT-ON* */ -#endif -} - -static void -vl_api_get_node_index_t_handler (vl_api_get_node_index_t * mp) -{ - vlib_main_t *vm = vlib_get_main (); - vl_api_get_node_index_reply_t *rmp; - vlib_node_t *n; int rv = 0; - u32 node_index = ~0; - - n = vlib_get_node_by_name (vm, mp->node_name); - - if (n == 0) - rv = VNET_API_ERROR_NO_SUCH_NODE; - else - node_index = n->index; - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_GET_NODE_INDEX_REPLY, - ({ - rmp->node_index = htonl(node_index); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_get_next_index_t_handler (vl_api_get_next_index_t * mp) -{ - vlib_main_t *vm = vlib_get_main (); - vl_api_get_next_index_reply_t *rmp; - vlib_node_t *node, *next_node; - int rv = 0; - u32 next_node_index = ~0, next_index = ~0; - uword *p; - - node = vlib_get_node_by_name (vm, mp->node_name); - - if (node == 0) - { - rv = VNET_API_ERROR_NO_SUCH_NODE; - goto out; - } - - next_node = vlib_get_node_by_name (vm, mp->next_name); - - if (next_node == 0) - { - rv = VNET_API_ERROR_NO_SUCH_NODE2; - goto out; - } - else - next_node_index = next_node->index; - - p = hash_get (node->next_slot_by_node, next_node_index); - - if (p == 0) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto out; - } - else - next_index = p[0]; - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_GET_NEXT_INDEX_REPLY, - ({ - rmp->next_index = htonl(next_index); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_add_node_next_t_handler (vl_api_add_node_next_t * mp) -{ - vlib_main_t *vm = vlib_get_main (); - vl_api_add_node_next_reply_t *rmp; - vlib_node_t *n, *next; - int rv = 0; - u32 next_index = ~0; - - n = vlib_get_node_by_name (vm, mp->node_name); - - if (n == 0) - { - rv = VNET_API_ERROR_NO_SUCH_NODE; - goto out; - } - - next = vlib_get_node_by_name (vm, mp->next_name); - - if (next == 0) - rv = VNET_API_ERROR_NO_SUCH_NODE2; - else - next_index = vlib_node_add_next (vm, n->index, next->index); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_ADD_NODE_NEXT_REPLY, - ({ - rmp->next_index = htonl(next_index); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t * mp) -{ - int rv = 0; - u8 *vector = 0; - vlib_main_t *vm = vlib_get_main (); - void *oldheap; - vl_api_get_node_graph_reply_t *rmp; - static vlib_node_t ***node_dups; - static vlib_main_t **stat_vms; - - oldheap = vl_msg_push_heap (); - - /* - * Keep the number of memcpy ops to a minimum (e.g. 1). - */ - vec_validate (vector, 16384); - vec_reset_length (vector); - - vlib_node_get_nodes (vm, 0 /* main threads */ , - 0 /* include stats */ , - 1 /* barrier sync */ , - &node_dups, &stat_vms); - vector = vlib_node_serialize (vm, node_dups, vector, 1 /* include nexts */ , - 1 /* include stats */ ); - - vl_msg_pop_heap (oldheap); - + vl_api_show_vpe_system_time_reply_t *rmp; /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_GET_NODE_GRAPH_REPLY, - ({ - rmp->reply_in_shmem = (uword) vector; - })); + REPLY_MACRO2 ( + VL_API_SHOW_VPE_SYSTEM_TIME_REPLY, + ({ rmp->vpe_system_time = clib_host_to_net_f64 (unix_time_now ()); })); /* *INDENT-ON* */ } @@ -530,51 +229,6 @@ vl_api_log_dump_t_handler (vl_api_log_dump_t * mp) } -static void -vl_api_show_vpe_system_time_t_handler (vl_api_show_vpe_system_time_t * mp) -{ - int rv = 0; - vl_api_show_vpe_system_time_reply_t *rmp; - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_SHOW_VPE_SYSTEM_TIME_REPLY, - ({ - rmp->vpe_system_time = clib_host_to_net_f64 (unix_time_now ()); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_get_f64_endian_value_t_handler (vl_api_get_f64_endian_value_t * mp) -{ - int rv = 0; - f64 one = 1.0; - vl_api_get_f64_endian_value_reply_t *rmp; - if (1.0 != clib_net_to_host_f64 (mp->f64_one)) - rv = VNET_API_ERROR_API_ENDIAN_FAILED; - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_GET_F64_ENDIAN_VALUE_REPLY, - ({ - rmp->f64_one_result = clib_host_to_net_f64 (one); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_get_f64_increment_by_one_t_handler (vl_api_get_f64_increment_by_one_t * - mp) -{ - int rv = 0; - vl_api_get_f64_increment_by_one_reply_t *rmp; - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_GET_F64_INCREMENT_BY_ONE_REPLY, - ({ - rmp->f64_value = clib_host_to_net_f64 (clib_net_to_host_f64(mp->f64_value) + 1.0); - })); - /* *INDENT-ON* */ -} - #define BOUNCE_HANDLER(nn) \ static void vl_api_##nn##_t_handler ( \ vl_api_##nn##_t *mp) \ @@ -642,7 +296,6 @@ vpe_api_hookup (vlib_main_t * vm) am->is_mp_safe[VL_API_CONTROL_PING] = 1; am->is_mp_safe[VL_API_CONTROL_PING_REPLY] = 1; am->is_mp_safe[VL_API_IP_ROUTE_ADD_DEL] = 1; - am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1; /* * Set up the (msg_name, crc, message-id) table diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 9047d0e1aa9..3c4c0214ad5 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -19,7 +19,7 @@ called through a shared memory interface. */ -option version = "1.6.1"; +option version = "1.7.0"; import "vpp/api/vpe_types.api"; @@ -77,92 +77,6 @@ define control_ping_reply u32 vpe_pid; }; -/** \brief Process a vpe parser cli string request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param cmd_in_shmem - pointer to cli command string -*/ -define cli -{ - u32 client_index; - u32 context; - u64 cmd_in_shmem; -}; -define cli_inband -{ - u32 client_index; - u32 context; - string cmd[]; -}; - -/** \brief vpe parser cli string response - @param context - sender context, to match reply w/ request - @param retval - return code for request - @param reply_in_shmem - Reply string from cli processing if any -*/ -define cli_reply -{ - u32 context; - i32 retval; - u64 reply_in_shmem; -}; -define cli_inband_reply -{ - u32 context; - i32 retval; - string reply[]; -}; - -/** \brief Get node index using name request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param node_name[] - name of the node -*/ -define get_node_index -{ - u32 client_index; - u32 context; - string node_name[64]; -}; - -/** \brief Get node index using name request - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param node_index - index of the desired node if found, else ~0 -*/ -define get_node_index_reply -{ - u32 context; - i32 retval; - u32 node_index; -}; - -/** \brief Set the next node for a given node request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param node_name[] - node to add the next node to - @param next_name[] - node to add as the next node -*/ -define add_node_next -{ - u32 client_index; - u32 context; - string node_name[64]; - string next_name[64]; -}; - -/** \brief IP Set the next node for a given node response - @param context - sender context, to match reply w/ request - @param retval - return code for the add next node request - @param next_index - the index of the next node if success, else ~0 -*/ -define add_node_next_reply -{ - u32 context; - i32 retval; - u32 next_index; -}; - /** \brief show version @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -190,99 +104,26 @@ define show_version_reply string build_directory[256]; }; - -/** \brief show_threads display the information about vpp - threads running on system along with their process id, - cpu id, physical core and cpu socket. -*/ -define show_threads -{ - u32 client_index; - u32 context; -}; - -/** \brief thread data - @param id - thread index - @param name - thread name i.e. vpp_main or vpp_wk_0 - @param type - thread type i.e. workers or stats - @param pid - thread Process Id - @param cpu_id - thread pinned to cpu. - "CPUs or Logical cores are the number of physical cores times - the number of threads that can run on each core through - the use of hyperthreading." (from unix.stackexchange.com) - @param core - thread pinned to actual physical core. - @param cpu_socket - thread is running on which cpu socket. -*/ -typedef thread_data -{ - u32 id; - string name[64]; - string type[64]; - u32 pid; - u32 cpu_id; - u32 core; - u32 cpu_socket; -}; - -/** \brief show_threads_reply - @param context - returned sender context, to match reply w/ request - @param retval - return code - @param count - number of threads in thread_data array - @param thread_data - array of thread data -*/ -define show_threads_reply -{ - u32 context; - i32 retval; - u32 count; - vl_api_thread_data_t thread_data[count]; -}; - -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; -}; - -/** \brief Query relative index via node names +/** \brief Show the current system timestamp. @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param node_name - name of node to find relative index from - @param next_name - next node from node_name to find relative index of */ -define get_next_index +define show_vpe_system_time { u32 client_index; u32 context; - string node_name[64]; - string next_name[64]; }; -/** \brief Reply for get next node index +/** \brief Reply for show vpe system time. @param context - sender context which was passed in the request @param retval - return value - @param next_index - index of the next_node + @param vpe_system_time - the time in seconds since epoch of the host system. */ -define get_next_index_reply +define show_vpe_system_time_reply { u32 context; i32 retval; - u32 next_index; + vl_api_timestamp_t vpe_system_time; }; define log_dump { @@ -299,76 +140,6 @@ define log_details { string message[256]; }; -/** \brief Show the current system timestamp. - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define show_vpe_system_time -{ - u32 client_index; - u32 context; -}; - -/** \brief Reply for show vpe system time. - @param context - sender context which was passed in the request - @param retval - return value - @param vpe_system_time - the time in seconds since epoch of the host system. -*/ -define show_vpe_system_time_reply -{ - u32 context; - i32 retval; - vl_api_timestamp_t vpe_system_time; -}; - -/** \brief f64 types are not standardized across the wire. Sense wire format in each direction by sending the f64 value 1.0. - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param f64_one - The constant of 1.0. If you send a different value, expect an rv=VNET_API_ERROR_API_ENDIAN_FAILED. -*/ -define get_f64_endian_value -{ - u32 client_index; - u32 context; - f64 f64_one [default=1.0]; -}; - -/** \brief get_f64_endian_value reply message - @param context - sender context which was passed in the request - @param retval - return value - VNET_API_ERROR_API_ENDIAN_FAILED if f64_one != 1.0 - @param f64_one_result - The value of 'f64 1.0' -*/ -define get_f64_endian_value_reply -{ - u32 context; - u32 retval; - f64 f64_one_result; -}; - -/** \brief Verify f64 wire format by sending a value and receiving the value + 1.0 - @param client_index - opaque cookie to identify the sender. - @param context - sender context, to match reply w/ request. - @param f64_value - The value you want to test. Default: 1.0. -*/ -define get_f64_increment_by_one -{ - u32 client_index; - u32 context; - f64 f64_value [default=1.0]; -}; - -/** \brief get_f64_increment_by_one reply - @param client_index - opaque cookie to identify the sender. - @param context - sender context, to match reply w/ request. - @param f64_value - The input f64_value incremented by 1.0. -*/ -define get_f64_increment_by_one_reply -{ - u32 context; - u32 retval; - f64 f64_value; -}; - /* * Local Variables: * eval: (c-set-style "gnu") |