From: Ole Troan Date: Wed, 31 Aug 2016 12:50:49 +0000 (+0200) Subject: Add in-message cli_request/cli_reply API X-Git-Tag: v17.01-rc0~253 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=c27213a30f4d6b5395ba70f011615ae9c7be93ce;p=vpp.git Add in-message cli_request/cli_reply API This new CLI API is meant to replace the cli_request/cli_reply that uses shared memory. PS: checkstyle -- *hate* Change-Id: I6318f8f6b9be2c2398b49dac9e2193c1998ea724 Signed-off-by: Ole Troan --- diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c index a87828feef1..b9cfd751e20 100644 --- a/vpp-api-test/vat/api_format.c +++ b/vpp-api-test/vat/api_format.c @@ -893,6 +893,34 @@ vl_api_cli_reply_t_handler_json (vl_api_cli_reply_t * mp) 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); + + vam->retval = retval; + vam->cmd_reply = 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; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_string_copy (&node, "reply", mp->reply); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + static void vl_api_classify_add_del_table_reply_t_handler (vl_api_classify_add_del_table_reply_t * mp) { @@ -3448,6 +3476,7 @@ _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \ _(CONTROL_PING_REPLY, control_ping_reply) \ _(NOPRINT_CONTROL_PING_REPLY, noprint_control_ping_reply) \ _(CLI_REPLY, cli_reply) \ +_(CLI_INBAND_REPLY, cli_inband_reply) \ _(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, \ sw_interface_add_del_address_reply) \ _(SW_INTERFACE_SET_TABLE_REPLY, sw_interface_set_table_reply) \ @@ -4087,6 +4116,45 @@ exec (vat_main_t * vam) return -99; } +/* + * Future replacement of exec() that passes CLI buffers directly in + * the API messages instead of an additional shared memory area. + */ +static int +exec_inband (vat_main_t * vam) +{ + vl_api_cli_inband_t *mp; + f64 timeout; + unformat_input_t *i = vam->input; + + 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. + */ + u32 len = vec_len (vam->input->buffer); + M2 (CLI_INBAND, cli_inband, len); + clib_memcpy (mp->cmd, vam->input->buffer, len); + mp->length = htonl (len); + + S; + W2 (fformat (vam->ofp, "%s", vam->cmd_reply)); +} + static int api_create_loopback (vat_main_t * vam) { @@ -15893,6 +15961,7 @@ _(dump_macro_table, "usage: dump_macro_table ") \ _(dump_node_table, "usage: dump_node_table") \ _(echo, "usage: echo ") \ _(exec, "usage: exec ") \ +_(exec_inband, "usage: exec_inband ") \ _(help, "usage: help") \ _(q, "usage: quit") \ _(quit, "usage: quit") \ diff --git a/vpp-api-test/vat/vat.h b/vpp-api-test/vat/vat.h index 311b9c72d24..ce8b16674b0 100644 --- a/vpp-api-test/vat/vat.h +++ b/vpp-api-test/vat/vat.h @@ -166,6 +166,7 @@ typedef struct volatile i32 retval; volatile u32 sw_if_index; volatile u8 *shmem_result; + volatile u8 *cmd_reply; /* our client index */ u32 my_client_index; diff --git a/vpp-api/python/tests/test_cli.py b/vpp-api/python/tests/test_cli.py new file mode 100755 index 00000000000..66fb6943e70 --- /dev/null +++ b/vpp-api/python/tests/test_cli.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +from __future__ import print_function +import unittest, sys, time, threading, struct +import test_base +import vpp_papi +from ipaddress import * + +import glob, subprocess +class TestPAPI(unittest.TestCase): + @classmethod + def setUpClass(cls): + # + # Start main VPP process + cls.vpp_bin = glob.glob(test_base.scriptdir+'/../../../build-root/install-vpp*-native/vpp/bin/vpp')[0] + print("VPP BIN:", cls.vpp_bin) + cls.vpp = subprocess.Popen([cls.vpp_bin, "unix", "nodaemon"], stderr=subprocess.PIPE) + print('Started VPP') + # For some reason unless we let VPP start up the API cannot connect. + time.sleep(0.3) + @classmethod + def tearDownClass(cls): + cls.vpp.terminate() + + def setUp(self): + print("Connecting API") + r = vpp_papi.connect("test_papi") + self.assertEqual(r, 0) + + def tearDown(self): + r = vpp_papi.disconnect() + self.assertEqual(r, 0) + + # + # The tests themselves + # + + # + # Basic request / reply + # + def test_cli_request(self): + print(vpp_papi.cli_exec('show version verbose')) + #t = vpp_papi.cli_inband_request(len(cmd), cmd) + #print('T:',t) + #reply = t.reply[0].decode().rstrip('\x00') + #print(reply) + #program = t.program.decode().rstrip('\x00') + #self.assertEqual('vpe', program) + + +if __name__ == '__main__': + unittest.main() diff --git a/vpp-api/python/vpp_papi/vpp_papi.py b/vpp-api/python/vpp_papi/vpp_papi.py index 6a7a358f6cd..144151c4154 100644 --- a/vpp-api/python/vpp_papi/vpp_papi.py +++ b/vpp-api/python/vpp_papi/vpp_papi.py @@ -99,6 +99,12 @@ def disconnect(): logging.info("Disconnected") return rv +# CLI convenience wrapper +def cli_exec(cmd): + cmd += '\n' + r = cli_inband(len(cmd), cmd) + return r.reply[0].decode().rstrip('\x00') + def register_event_callback(callback): event_callback_set(callback) diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index fbebfa6b970..ead5f0cd925 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -155,6 +155,22 @@ do { \ vl_msg_api_send_shmem (q, (u8 *)&rmp); \ } while(0); +#define REPLY_MACRO3(t, n, body) \ +do { \ + unix_shared_memory_queue_t * q; \ + rv = vl_msg_api_pd_handler (mp, rv); \ + q = vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \ + rmp->_vl_msg_id = ntohs((t)); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + do {body;} while (0); \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + #if (1 || CLIB_DEBUG > 0) /* "trust, but verify" */ #define VALIDATE_SW_IF_INDEX(mp) \ @@ -268,6 +284,7 @@ _(CREATE_LOOPBACK, create_loopback) \ _(CONTROL_PING, control_ping) \ _(NOPRINT_CONTROL_PING, noprint_control_ping) \ _(CLI_REQUEST, cli_request) \ +_(CLI_INBAND, cli_inband) \ _(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit) \ _(L2_PATCH_ADD_DEL, l2_patch_add_del) \ _(CLASSIFY_ADD_DEL_TABLE, classify_add_del_table) \ @@ -3692,6 +3709,46 @@ vl_api_cli_request_t_handler (vl_api_cli_request_t * mp) vl_msg_api_send_shmem (q, (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; + unix_shared_memory_queue_t *q; + vlib_main_t *vm = vlib_get_main (); + unformat_input_t input; + u8 *out_vec = 0; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (!q) + return; + + unformat_init_string (&input, (char *) mp->cmd, ntohl (mp->length)); + vlib_cli_input (vm, &input, inband_cli_output, (uword) & out_vec); + + u32 len = vec_len (out_vec); + /* *INDENT-OFF* */ + REPLY_MACRO3(VL_API_CLI_INBAND_REPLY, len, + ({ + rmp->length = htonl (len); + clib_memcpy (rmp->reply, out_vec, len); + })); + /* *INDENT-ON* */ + vec_free (out_vec); +} + static void vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp) { diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c index 566bcb9fa74..5ca7ccc9299 100644 --- a/vpp/vpp-api/custom_dump.c +++ b/vpp/vpp-api/custom_dump.c @@ -1621,6 +1621,16 @@ static void *vl_api_cli_request_t_print FINISH; } +static void *vl_api_cli_inband_t_print + (vl_api_cli_inband_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: cli_inband "); + + FINISH; +} + static void *vl_api_memclnt_create_t_print (vl_api_memclnt_create_t * mp, void *handle) { @@ -2695,6 +2705,7 @@ _(SW_INTERFACE_DUMP, sw_interface_dump) \ _(CONTROL_PING, control_ping) \ _(WANT_INTERFACE_EVENTS, want_interface_events) \ _(CLI_REQUEST, cli_request) \ +_(CLI_INBAND, cli_inband) \ _(MEMCLNT_CREATE, memclnt_create) \ _(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) \ _(SHOW_VERSION, show_version) \ diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api index 1f26d5519bf..51862f744a7 100644 --- a/vpp/vpp-api/vpe.api +++ b/vpp/vpp-api/vpe.api @@ -1183,6 +1183,13 @@ define cli_request u32 context; u64 cmd_in_shmem; }; +define cli_inband +{ + u32 client_index; + u32 context; + u32 length; + u8 cmd[length]; +}; /** \brief vpe parser cli string response @param context - sender context, to match reply w/ request @@ -1195,6 +1202,13 @@ define cli_reply i32 retval; u64 reply_in_shmem; }; +define cli_inband_reply +{ + u32 context; + i32 retval; + u32 length; + u8 reply[length]; +}; /** \brief Set max allowed ARP or ip6 neighbor entries request @param client_index - opaque cookie to identify the sender