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 <ot@cisco.com>
diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c
index a87828f..b9cfd75 100644
--- a/vpp-api-test/vat/api_format.c
+++ b/vpp-api-test/vat/api_format.c
@@ -893,6 +893,34 @@
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 @@
_(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 @@
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_node_table, "usage: dump_node_table") \
_(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/vpp-api-test/vat/vat.h b/vpp-api-test/vat/vat.h
index 311b9c7..ce8b166 100644
--- a/vpp-api-test/vat/vat.h
+++ b/vpp-api-test/vat/vat.h
@@ -166,6 +166,7 @@
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 0000000..66fb694
--- /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 6a7a358..144151c 100644
--- a/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/vpp-api/python/vpp_papi/vpp_papi.py
@@ -99,6 +99,12 @@
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 fbebfa6..ead5f0c 100644
--- a/vpp/vpp-api/api.c
+++ b/vpp/vpp-api/api.c
@@ -155,6 +155,22 @@
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 @@
_(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) \
@@ -3693,6 +3710,46 @@
}
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)
{
int rv;
diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c
index 566bcb9..5ca7ccc 100644
--- a/vpp/vpp-api/custom_dump.c
+++ b/vpp/vpp-api/custom_dump.c
@@ -1621,6 +1621,16 @@
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 @@
_(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 1f26d55..51862f7 100644
--- a/vpp/vpp-api/vpe.api
+++ b/vpp/vpp-api/vpe.api
@@ -1183,6 +1183,13 @@
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 @@
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