From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vpp-api/python/pneum/pneum.c | 259 ++++++++++++++++++++++++++++++++++ src/vpp-api/python/pneum/pneum.h | 31 ++++ src/vpp-api/python/pneum/test_pneum.c | 143 +++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 src/vpp-api/python/pneum/pneum.c create mode 100644 src/vpp-api/python/pneum/pneum.h create mode 100644 src/vpp-api/python/pneum/test_pneum.c (limited to 'src/vpp-api/python/pneum') diff --git a/src/vpp-api/python/pneum/pneum.c b/src/vpp-api/python/pneum/pneum.c new file mode 100644 index 00000000000..b805f04b11e --- /dev/null +++ b/src/vpp-api/python/pneum/pneum.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "pneum.h" + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +vlib_main_t vlib_global_main; +vlib_main_t **vlib_mains; + +typedef struct { + u8 rx_thread_jmpbuf_valid; + u8 connected_to_vlib; + jmp_buf rx_thread_jmpbuf; + pthread_t rx_thread_handle; +} pneum_main_t; + +pneum_main_t pneum_main; + +pneum_callback_t pneum_callback; + +/* + * Satisfy external references when -lvlib is not available. + */ +void vlib_cli_output (struct vlib_main_t * vm, char * fmt, ...) +{ + clib_warning ("vlib_cli_output called..."); +} + +void +pneum_free (void * msg) +{ + vl_msg_api_free (msg); +} + +static void +pneum_api_handler (void *msg) +{ + u16 id = ntohs(*((u16 *)msg)); + if (id == VL_API_RX_THREAD_EXIT) { + pneum_main_t *pm = &pneum_main; + vl_msg_api_free(msg); + longjmp(pm->rx_thread_jmpbuf, 1); + } + msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data)); + int l = ntohl(msgbuf->data_len); + if (l == 0) + clib_warning("Message ID %d has wrong length: %d\n", id, l); + + /* Call Python callback */ + ASSERT(pneum_callback); + (pneum_callback)(msg, l); + pneum_free(msg); +} + +static void * +pneum_rx_thread_fn (void *arg) +{ + unix_shared_memory_queue_t *q; + pneum_main_t *pm = &pneum_main; + api_main_t *am = &api_main; + uword msg; + + q = am->vl_input_queue; + + /* So we can make the rx thread terminate cleanly */ + if (setjmp(pm->rx_thread_jmpbuf) == 0) { + pm->rx_thread_jmpbuf_valid = 1; + while (1) + while (!unix_shared_memory_queue_sub(q, (u8 *)&msg, 0)) + pneum_api_handler((void *)msg); + } + pthread_exit(0); +} + +uword * +pneum_msg_table_get_hash (void) +{ + api_main_t *am = &api_main; + return (am->msg_index_by_name_and_crc); +} + +int +pneum_msg_table_size(void) +{ + api_main_t *am = &api_main; + return hash_elts(am->msg_index_by_name_and_crc); +} + +int +pneum_connect (char * name, char * chroot_prefix, pneum_callback_t cb) +{ + int rv = 0; + pneum_main_t *pm = &pneum_main; + + if (chroot_prefix != NULL) + vl_set_memory_root_path (chroot_prefix); + + if ((rv = vl_client_api_map("/vpe-api"))) { + clib_warning ("vl_client_api map rv %d", rv); + return rv; + } + + if (vl_client_connect(name, 0, 32) < 0) { + vl_client_api_unmap(); + return (-1); + } + + if (cb) { + /* Start the rx queue thread */ + rv = pthread_create(&pm->rx_thread_handle, NULL, pneum_rx_thread_fn, 0); + if (rv) { + clib_warning("pthread_create returned %d", rv); + vl_client_api_unmap(); + return (-1); + } + pneum_callback = cb; + } + + pm->connected_to_vlib = 1; + + return (0); +} + +int +pneum_disconnect (void) +{ + api_main_t *am = &api_main; + pneum_main_t *pm = &pneum_main; + + if (pm->rx_thread_jmpbuf_valid) { + vl_api_rx_thread_exit_t *ep; + uword junk; + ep = vl_msg_api_alloc (sizeof (*ep)); + ep->_vl_msg_id = ntohs(VL_API_RX_THREAD_EXIT); + vl_msg_api_send_shmem(am->vl_input_queue, (u8 *)&ep); + pthread_join(pm->rx_thread_handle, (void **) &junk); + } + if (pm->connected_to_vlib) { + vl_client_disconnect(); + vl_client_api_unmap(); + pneum_callback = 0; + } + memset (pm, 0, sizeof (*pm)); + + return (0); +} + +int +pneum_read (char **p, int *l) +{ + unix_shared_memory_queue_t *q; + api_main_t *am = &api_main; + pneum_main_t *pm = &pneum_main; + uword msg; + + if (!pm->connected_to_vlib) return -1; + + *l = 0; + + if (am->our_pid == 0) return (-1); + + q = am->vl_input_queue; + int rv = unix_shared_memory_queue_sub(q, (u8 *)&msg, 0); + if (rv == 0) { + u16 msg_id = ntohs(*((u16 *)msg)); + msgbuf_t *msgbuf = (msgbuf_t *)(((u8 *)msg) - offsetof(msgbuf_t, data)); + *l = ntohl(msgbuf->data_len); + if (*l == 0) { + printf("Unregistered API message: %d\n", msg_id); + return (-1); + } + *p = (char *)msg; + } else { + printf("Read failed with %d\n", rv); + } + return (rv); +} + +/* + * XXX: Makes the assumption that client_index is the first member + */ +typedef VL_API_PACKED(struct _vl_api_header { + u16 _vl_msg_id; + u32 client_index; +}) vl_api_header_t; + +static unsigned int +pneum_client_index (void) +{ + return (api_main.my_client_index); +} + +int +pneum_write (char *p, int l) +{ + int rv = -1; + api_main_t *am = &api_main; + vl_api_header_t *mp = vl_msg_api_alloc(l); + unix_shared_memory_queue_t *q; + pneum_main_t *pm = &pneum_main; + + if (!pm->connected_to_vlib) return -1; + if (!mp) return (-1); + memcpy(mp, p, l); + mp->client_index = pneum_client_index(); + q = am->shmem_hdr->vl_input_queue; + rv = unix_shared_memory_queue_add(q, (u8 *)&mp, 0); + if (rv != 0) { + printf("vpe_api_write fails: %d\n", rv); + /* Clear message */ + pneum_free(mp); + } + return (rv); +} + +uint32_t +pneum_get_msg_index (unsigned char * name) +{ + return vl_api_get_msg_index (name); +} diff --git a/src/vpp-api/python/pneum/pneum.h b/src/vpp-api/python/pneum/pneum.h new file mode 100644 index 00000000000..a347bd25f62 --- /dev/null +++ b/src/vpp-api/python/pneum/pneum.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef included_pneum_h +#define included_pneum_h + +#include +#include + +typedef void (*pneum_callback_t)(unsigned char * data, int len); +int pneum_connect(char * name, char * chroot_prefix, pneum_callback_t cb); +int pneum_disconnect(void); +int pneum_read(char **data, int *l); +int pneum_write(char *data, int len); +void pneum_free(void * msg); +uword * pneum_msg_table_get_hash (void); +int pneum_msg_table_size(void); +uint32_t pneum_get_msg_index(unsigned char * name); + +#endif diff --git a/src/vpp-api/python/pneum/test_pneum.c b/src/vpp-api/python/pneum/test_pneum.c new file mode 100644 index 00000000000..0d55b8a9b8e --- /dev/null +++ b/src/vpp-api/python/pneum/test_pneum.c @@ -0,0 +1,143 @@ +/* + *------------------------------------------------------------------ + * test_pneum.c + * + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* time_t, time (for timestamp in second) */ +#include /* ftime, timeb (for timestamp in millisecond) */ +#include /* gettimeofday, timeval (for timestamp in microsecond) */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "pneum.h" + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +/* we are not linking with vlib */ +vlib_main_t vlib_global_main; +vlib_main_t **vlib_mains; + +volatile int sigterm_received = 0; +volatile u32 result_ready; +volatile u16 result_msg_id; + +/* M_NOALLOC: construct, but don't yet send a message */ + +#define M_NOALLOC(T,t) \ + do { \ + result_ready = 0; \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T); \ + mp->client_index = am->my_client_index; \ + } while(0); + + + +int +wrap_pneum_callback (char *data, int len) +{ + //printf("Callback %d\n", len); + result_ready = 1; + result_msg_id = ntohs(*((u16 *)data)); + return (0); +} + +int main (int argc, char ** argv) +{ + api_main_t * am = &api_main; + vl_api_show_version_t message; + vl_api_show_version_t *mp; + int async = 1; + int rv = pneum_connect("pneum_client", NULL, NULL); + + if (rv != 0) { + printf("Connect failed: %d\n", rv); + exit(rv); + } + + struct timeb timer_msec; + long long int timestamp_msec_start; /* timestamp in millisecond. */ + if (!ftime(&timer_msec)) { + timestamp_msec_start = ((long long int) timer_msec.time) * 1000ll + + (long long int) timer_msec.millitm; + } + else { + timestamp_msec_start = -1; + } + + + /* + * Test vpe_api_write and vpe_api_read to send and recv message for an + * API + */ + int i; + long int no_msgs = 10000; + mp = &message; + + for (i = 0; i < no_msgs; i++) { + /* Construct the API message */ + M_NOALLOC(SHOW_VERSION, show_version); + pneum_write((char *)mp, sizeof(*mp)); +#ifndef __COVERITY__ + /* As given, async is always 1. Shut up Coverity about it */ + if (!async) + while (result_ready == 0); +#endif + } + if (async) { + vl_api_control_ping_t control; + vl_api_control_ping_t *mp; + mp = &control; + M_NOALLOC(CONTROL_PING, control_ping); + pneum_write((char *)mp, sizeof(*mp)); + + while (result_msg_id != VL_API_CONTROL_PING_REPLY); + } + + long long int timestamp_msec_end; /* timestamp in millisecond. */ + if (!ftime(&timer_msec)) { + timestamp_msec_end = ((long long int) timer_msec.time) * 1000ll + + (long long int) timer_msec.millitm; + } + else { + timestamp_msec_end = -1; + } + + printf("Took %lld msec, %lld msgs/msec \n", (timestamp_msec_end - timestamp_msec_start), + no_msgs/(timestamp_msec_end - timestamp_msec_start)); + fformat(stdout, "Exiting...\n"); + pneum_disconnect(); + exit (0); +} -- cgit 1.2.3-korg