| /* |
| *------------------------------------------------------------------ |
| * 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: |
| */ |