Add new C API
Change-Id: I717ce3cd7c867c155de149ec56623269d26d0ff7 Signed-off-by: Klement Sekera <ksekera@cisco.com>
This commit is contained in:

committed by
Neale Ranns

parent
f4215a65cb
commit
8f2a4eafea
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@
|
||||
/build-root/test-doc/
|
||||
/build-root/test-cov/
|
||||
/build-root/python/
|
||||
/build-root/vapi_test/
|
||||
/build-config.mk
|
||||
/dpdk/*.tar.gz
|
||||
/dpdk/*.tar.xz
|
||||
|
11
Makefile
11
Makefile
@@ -62,7 +62,7 @@ DEB_DEPENDS = curl build-essential autoconf automake bison libssl-dev ccache
|
||||
DEB_DEPENDS += debhelper dkms git libtool libapr1-dev dh-systemd
|
||||
DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config
|
||||
DEB_DEPENDS += lcov chrpath autoconf nasm indent libnuma-dev
|
||||
DEB_DEPENDS += python-all python-dev python-virtualenv python-pip libffi6
|
||||
DEB_DEPENDS += python-all python-dev python-virtualenv python-pip libffi6 check
|
||||
ifeq ($(OS_VERSION_ID),14.04)
|
||||
DEB_DEPENDS += openjdk-8-jdk-headless
|
||||
else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-8)
|
||||
@@ -76,6 +76,7 @@ RPM_DEPENDS = redhat-lsb glibc-static java-1.8.0-openjdk-devel yum-utils
|
||||
RPM_DEPENDS += apr-devel
|
||||
RPM_DEPENDS += openssl-devel
|
||||
RPM_DEPENDS += numactl-devel
|
||||
RPM_DEPENDS += check
|
||||
ifeq ($(OS_ID)-$(OS_VERSION_ID),fedora-25)
|
||||
RPM_DEPENDS += python-devel
|
||||
RPM_DEPENDS += python2-virtualenv
|
||||
@@ -101,7 +102,13 @@ endif
|
||||
|
||||
RPM_SUSE_DEPENDS = autoconf automake bison ccache chrpath distribution-release gcc6 glibc-devel-static
|
||||
RPM_SUSE_DEPENDS += java-1_8_0-openjdk-devel libopenssl-devel libtool lsb-release make openssl-devel
|
||||
RPM_SUSE_DEPENDS += python-devel python-pip python-rpm-macros shadow nasm libnuma-devel
|
||||
RPM_SUSE_DEPENDS += python-devel python-pip python-rpm-macros shadow nasm libnuma-devel python3
|
||||
|
||||
ifeq ($(filter rhel centos,$(OS_ID)),$(OS_ID))
|
||||
RPM_DEPENDS += python34
|
||||
else
|
||||
RPM_DEPENDS += python3
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),)
|
||||
STARTUP_CONF ?= $(STARTUP_DIR)/startup.conf
|
||||
|
@@ -80,6 +80,8 @@ if ENABLE_JAPI
|
||||
SUBDIRS += vpp-api/java
|
||||
endif
|
||||
|
||||
SUBDIRS += vpp-api/vapi
|
||||
|
||||
###############################################################################
|
||||
# API
|
||||
###############################################################################
|
||||
|
@@ -3,7 +3,7 @@ LT_INIT
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
AC_CONFIG_FILES([Makefile plugins/Makefile vpp-api/python/Makefile vpp-api/java/Makefile])
|
||||
AC_CONFIG_FILES([Makefile plugins/Makefile vpp-api/python/Makefile vpp-api/java/Makefile vpp-api/vapi/Makefile])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_PROG_CC
|
||||
|
@@ -234,6 +234,71 @@ unix_shared_memory_queue_add (unix_shared_memory_queue_t * q,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* unix_shared_memory_queue_add2
|
||||
*/
|
||||
int
|
||||
unix_shared_memory_queue_add2 (unix_shared_memory_queue_t * q, u8 * elem,
|
||||
u8 * elem2, int nowait)
|
||||
{
|
||||
i8 *tailp;
|
||||
int need_broadcast = 0;
|
||||
|
||||
if (nowait)
|
||||
{
|
||||
/* zero on success */
|
||||
if (pthread_mutex_trylock (&q->mutex))
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
pthread_mutex_lock (&q->mutex);
|
||||
|
||||
if (PREDICT_FALSE (q->cursize + 1 == q->maxsize))
|
||||
{
|
||||
if (nowait)
|
||||
{
|
||||
pthread_mutex_unlock (&q->mutex);
|
||||
return (-2);
|
||||
}
|
||||
while (q->cursize + 1 == q->maxsize)
|
||||
{
|
||||
(void) pthread_cond_wait (&q->condvar, &q->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
|
||||
clib_memcpy (tailp, elem, q->elsize);
|
||||
|
||||
q->tail++;
|
||||
q->cursize++;
|
||||
|
||||
if (q->tail == q->maxsize)
|
||||
q->tail = 0;
|
||||
|
||||
need_broadcast = (q->cursize == 1);
|
||||
|
||||
tailp = (i8 *) (&q->data[0] + q->elsize * q->tail);
|
||||
clib_memcpy (tailp, elem2, q->elsize);
|
||||
|
||||
q->tail++;
|
||||
q->cursize++;
|
||||
|
||||
if (q->tail == q->maxsize)
|
||||
q->tail = 0;
|
||||
|
||||
if (need_broadcast)
|
||||
{
|
||||
(void) pthread_cond_broadcast (&q->condvar);
|
||||
if (q->signal_when_queue_non_empty)
|
||||
kill (q->consumer_pid, q->signal_when_queue_non_empty);
|
||||
}
|
||||
pthread_mutex_unlock (&q->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* unix_shared_memory_queue_sub
|
||||
*/
|
||||
|
@@ -21,7 +21,6 @@
|
||||
#define included_unix_shared_memory_queue_h
|
||||
|
||||
#include <pthread.h>
|
||||
#include <vppinfra/mem.h>
|
||||
|
||||
typedef struct _unix_shared_memory_queue
|
||||
{
|
||||
@@ -43,10 +42,12 @@ unix_shared_memory_queue_t *unix_shared_memory_queue_init (int nels,
|
||||
int
|
||||
signal_when_queue_non_empty);
|
||||
void unix_shared_memory_queue_free (unix_shared_memory_queue_t * q);
|
||||
int unix_shared_memory_queue_add (unix_shared_memory_queue_t * q,
|
||||
u8 * elem, int nowait);
|
||||
int unix_shared_memory_queue_sub (unix_shared_memory_queue_t * q,
|
||||
u8 * elem, int nowait);
|
||||
int unix_shared_memory_queue_add (unix_shared_memory_queue_t * q, u8 * elem,
|
||||
int nowait);
|
||||
int unix_shared_memory_queue_add2 (unix_shared_memory_queue_t * q, u8 * elem,
|
||||
u8 * elem2, int nowait);
|
||||
int unix_shared_memory_queue_sub (unix_shared_memory_queue_t * q, u8 * elem,
|
||||
int nowait);
|
||||
void unix_shared_memory_queue_lock (unix_shared_memory_queue_t * q);
|
||||
void unix_shared_memory_queue_unlock (unix_shared_memory_queue_t * q);
|
||||
int unix_shared_memory_queue_is_full (unix_shared_memory_queue_t * q);
|
||||
|
63
src/vpp-api/vapi/Makefile.am
Normal file
63
src/vpp-api/vapi/Makefile.am
Normal file
@@ -0,0 +1,63 @@
|
||||
# Copyright (c) 2017 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.
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
AM_LIBTOOLFLAGS = --quiet
|
||||
|
||||
AM_CFLAGS = -Wall -I${top_srcdir} -I${top_builddir} -I. -I$(top_srcdir)/vpp-api/vapi
|
||||
|
||||
AM_LDFLAGS = -shared -avoid-version -rpath /none -no-undefined
|
||||
|
||||
bin_PROGRAMS =
|
||||
noinst_LTLIBRARIES =
|
||||
CLEANDIRS =
|
||||
|
||||
%.api.vapi.h: %.api.json vapi_c_gen.py
|
||||
@echo " VAPI C GEN $< " $@ ; \
|
||||
mkdir -p `dirname $@` ; \
|
||||
$(top_srcdir)/vpp-api/vapi/vapi_c_gen.py $<
|
||||
|
||||
%.api.json:
|
||||
find $(top_builddir) -name '$@' | xargs ln -s
|
||||
|
||||
BUILT_SOURCES = $(shell find $(top_builddir) -name '*.api.json' | xargs -n1 basename) \
|
||||
$(patsubst %.api.json,%.api.vapi.h,$(JSON_FILES))
|
||||
|
||||
vapi.c: $(BUILT_SOURCES)
|
||||
|
||||
JSON_FILES = $(wildcard *.api.json)
|
||||
|
||||
|
||||
lib_LTLIBRARIES = libvapiclient.la
|
||||
|
||||
libvapiclient_la_SOURCES = vapi.c
|
||||
|
||||
libvapiclient_la_LIBADD = -lpthread -lm -lrt \
|
||||
$(top_builddir)/libvppinfra.la \
|
||||
$(top_builddir)/libvlibmemoryclient.la \
|
||||
$(top_builddir)/libsvm.la
|
||||
|
||||
libvapiclient_la_LDFLAGS = \
|
||||
-Wl,-L$(top_builddir)/.libs,--whole-archive,--no-whole-archive \
|
||||
-Wl,--version-script=$(srcdir)/libvapiclient.map,-lrt
|
||||
|
||||
libvapiclient_la_CPPFLAGS = -I. -I$(top_builddir)/vpp-api/vapi
|
||||
|
||||
nobase_include_HEADERS = ${top_srcdir}/vpp-api/client/vppapiclient.h \
|
||||
vapi.h \
|
||||
vapi_dbg.h \
|
||||
vapi_internal.h \
|
||||
$(patsubst %.api.json,%.api.vapi.h,$(JSON_FILES))
|
||||
|
||||
# vi:syntax=automake
|
41
src/vpp-api/vapi/libvapiclient.map
Normal file
41
src/vpp-api/vapi/libvapiclient.map
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
VAPICLIENT_17.07 {
|
||||
global:
|
||||
vapi_msg_alloc;
|
||||
vapi_msg_free;
|
||||
vapi_ctx_alloc;
|
||||
vapi_ctx_free;
|
||||
vapi_is_msg_available;
|
||||
vapi_connect;
|
||||
vapi_disconnect;
|
||||
vapi_get_fd;
|
||||
vapi_send;
|
||||
vapi_send2;
|
||||
vapi_recv;
|
||||
vapi_wait;
|
||||
vapi_dispatch_one;
|
||||
vapi_dispatch;
|
||||
vapi_set_event_cb;
|
||||
vapi_clear_event_cb;
|
||||
vapi_set_generic_event_cb;
|
||||
vapi_clear_generic_event_cb;
|
||||
vapi_get_client_index;
|
||||
vapi_register_msg;
|
||||
vapi_get_client_index;
|
||||
vapi_is_nonblocking;
|
||||
vapi_requests_full;
|
||||
vapi_gen_req_context;
|
||||
vapi_producer_lock;
|
||||
vapi_send_with_control_ping;
|
||||
vapi_store_request;
|
||||
vapi_is_nonblocking;
|
||||
vapi_producer_unlock;
|
||||
vapi_lookup_vl_msg_id;
|
||||
vapi_lookup_vapi_msg_id_t;
|
||||
vapi_msg_is_with_context;
|
||||
vapi_get_context_offset;
|
||||
vapi_msg_id_control_ping;
|
||||
vapi_msg_id_control_ping_reply;
|
||||
|
||||
local: *;
|
||||
};
|
895
src/vpp-api/vapi/vapi.c
Normal file
895
src/vpp-api/vapi/vapi.c
Normal file
File diff suppressed because it is too large
Load Diff
285
src/vpp-api/vapi/vapi.h
Normal file
285
src/vpp-api/vapi/vapi.h
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
*------------------------------------------------------------------
|
||||
* Copyright (c) 2017 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 vpp_api_h_included
|
||||
#define vpp_api_h_included
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <vppinfra/types.h>
|
||||
|
||||
/**
|
||||
* @file vapi.h
|
||||
*
|
||||
* common vpp api C declarations
|
||||
*
|
||||
* This file declares the common C API functions. These include connect,
|
||||
* disconnect and utility functions as well as the low-level vapi_send and
|
||||
* vapi_recv API. This is only the transport layer.
|
||||
*
|
||||
* Message formats and higher-level APIs are generated by running the
|
||||
* vapi_c_gen.py script (which is run for in-tree APIs as part of the build
|
||||
* process). It's not recommended to mix the higher and lower level APIs. Due
|
||||
* to version issues, the higher-level APIs are not part of the shared library.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VAPI_OK = 0, /**< success */
|
||||
VAPI_EINVAL, /**< invalid value encountered */
|
||||
VAPI_EAGAIN, /**< operation would block */
|
||||
VAPI_ENOTSUP, /**< operation not supported */
|
||||
VAPI_ENOMEM, /**< out of memory */
|
||||
VAPI_ENORESP, /**< no response to request */
|
||||
VAPI_EMAP_FAIL, /**< failure while mapping api */
|
||||
VAPI_ECON_FAIL, /**< failure while connecting to vpp */
|
||||
VAPI_EINCOMPATIBLE, /**< fundamental incompatibility while connecting to vpp
|
||||
(control ping/control ping reply mismatch) */
|
||||
VAPI_MUTEX_FAILURE, /**< failure manipulating internal mutex(es) */
|
||||
VAPI_EUSER, /**< user error used for breaking dispatch,
|
||||
never used by VAPI */
|
||||
} vapi_error_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VAPI_MODE_BLOCKING = 1, /**< operations block until response received */
|
||||
VAPI_MODE_NONBLOCKING = 2, /**< operations never block */
|
||||
} vapi_mode_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VAPI_WAIT_FOR_READ, /**< wait until a message can be read */
|
||||
VAPI_WAIT_FOR_WRITE, /**< wait until a message can be written */
|
||||
VAPI_WAIT_FOR_READ_WRITE, /**< wait until a read or write can be done */
|
||||
} vapi_wait_mode_e;
|
||||
|
||||
typedef int vapi_msg_id_t;
|
||||
typedef struct vapi_ctx_s *vapi_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief allocate vapi message of given size
|
||||
*
|
||||
* @note message must be freed by vapi_msg_free if not consumed by vapi_send
|
||||
* call
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
*
|
||||
* @return pointer to message or NULL if out of memory
|
||||
*/
|
||||
void *vapi_msg_alloc (vapi_ctx_t ctx, size_t size);
|
||||
|
||||
/**
|
||||
* @brief free a vapi message
|
||||
*
|
||||
* @note messages received by vapi_recv must be freed when no longer needed
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param msg message to be freed
|
||||
*/
|
||||
void vapi_msg_free (vapi_ctx_t ctx, void *msg);
|
||||
|
||||
/**
|
||||
* @brief allocate vapi context
|
||||
*
|
||||
* @param[out] pointer to result variable
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_ctx_alloc (vapi_ctx_t * result);
|
||||
|
||||
/**
|
||||
* @brief free vapi context
|
||||
*/
|
||||
void vapi_ctx_free (vapi_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief check if message identified by it's message id is known by the vpp to
|
||||
* which the connection is open
|
||||
*/
|
||||
bool vapi_is_msg_available (vapi_ctx_t ctx, vapi_msg_id_t type);
|
||||
|
||||
/**
|
||||
* @brief connect to vpp
|
||||
*
|
||||
* @param ctx opaque vapi context, must be allocated using vapi_ctx_alloc first
|
||||
* @param name application name
|
||||
* @param chroot_prefix shared memory prefix
|
||||
* @param max_outstanding_requests max number of outstanding requests queued
|
||||
* @param response_queue_size size of the response queue
|
||||
* @param mode mode of operation - blocking or nonblocking
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_connect (vapi_ctx_t ctx, const char *name,
|
||||
const char *chroot_prefix,
|
||||
int max_outstanding_requests,
|
||||
int response_queue_size, vapi_mode_e mode);
|
||||
|
||||
/**
|
||||
* @brief disconnect from vpp
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_disconnect (vapi_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief get event file descriptor
|
||||
*
|
||||
* @note this file descriptor becomes readable when messages (from vpp)
|
||||
* are waiting in queue
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param[out] fd pointer to result variable
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_get_fd (vapi_ctx_t ctx, int *fd);
|
||||
|
||||
/**
|
||||
* @brief low-level api for sending messages to vpp
|
||||
*
|
||||
* @note it is not recommended to use this api directly, use generated api
|
||||
* instead
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param msg message to send
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_send (vapi_ctx_t ctx, void *msg);
|
||||
|
||||
/**
|
||||
* @brief low-level api for atomically sending two messages to vpp - either
|
||||
* both messages are sent or neither one is
|
||||
*
|
||||
* @note it is not recommended to use this api directly, use generated api
|
||||
* instead
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param msg1 first message to send
|
||||
* @param msg2 second message to send
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_send2 (vapi_ctx_t ctx, void *msg1, void *msg2);
|
||||
|
||||
/**
|
||||
* @brief low-level api for reading messages from vpp
|
||||
*
|
||||
* @note it is not recommended to use this api directly, use generated api
|
||||
* instead
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param[out] msg pointer to result variable containing message
|
||||
* @param[out] msg_size pointer to result variable containing message size
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_recv (vapi_ctx_t ctx, void **msg, size_t * msg_size);
|
||||
|
||||
/**
|
||||
* @brief wait for connection to become readable or writable
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param mode type of property to wait for - readability, writability or both
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_wait (vapi_ctx_t ctx, vapi_wait_mode_e mode);
|
||||
|
||||
/**
|
||||
* @brief pick next message sent by vpp and call the appropriate callback
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_dispatch_one (vapi_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief loop vapi_dispatch_one until responses to all currently outstanding
|
||||
* requests have been received and their callbacks called
|
||||
*
|
||||
* @note the dispatch loop is interrupted if any error is encountered or
|
||||
* returned from the callback, in which case this error is returned as the
|
||||
* result of vapi_dispatch. In this case it might be necessary to call dispatch
|
||||
* again to process the remaining messages. Returning VAPI_EUSER from
|
||||
* a callback allows the user to break the dispatch loop (and distinguish
|
||||
* this case in the calling code from other failures). VAPI never returns
|
||||
* VAPI_EUSER on its own.
|
||||
*
|
||||
* @return VAPI_OK on success, other error code on error
|
||||
*/
|
||||
vapi_error_e vapi_dispatch (vapi_ctx_t ctx);
|
||||
|
||||
/** generic vapi event callback */
|
||||
typedef vapi_error_e (*vapi_event_cb) (vapi_ctx_t ctx, void *callback_ctx,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* @brief set event callback to call when message with given id is dispatched
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param id message id
|
||||
* @param callback callback
|
||||
* @param callback_ctx context pointer stored and passed to callback
|
||||
*/
|
||||
void vapi_set_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id,
|
||||
vapi_event_cb callback, void *callback_ctx);
|
||||
|
||||
/**
|
||||
* @brief clear event callback for given message id
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param id message id
|
||||
*/
|
||||
void vapi_clear_event_cb (vapi_ctx_t ctx, vapi_msg_id_t id);
|
||||
|
||||
/** generic vapi event callback */
|
||||
typedef vapi_error_e (*vapi_generic_event_cb) (vapi_ctx_t ctx,
|
||||
void *callback_ctx,
|
||||
vapi_msg_id_t id, void *msg);
|
||||
/**
|
||||
* @brief set generic event callback
|
||||
*
|
||||
* @note this callback is called by dispatch if no message-type specific
|
||||
* callback is set (so it's a fallback callback)
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
* @param callback callback
|
||||
* @param callback_ctx context pointer stored and passed to callback
|
||||
*/
|
||||
void vapi_set_generic_event_cb (vapi_ctx_t ctx,
|
||||
vapi_generic_event_cb callback,
|
||||
void *callback_ctx);
|
||||
|
||||
/**
|
||||
* @brief clear generic event callback
|
||||
*
|
||||
* @param ctx opaque vapi context
|
||||
*/
|
||||
void vapi_clear_generic_event_cb (vapi_ctx_t ctx);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
809
src/vpp-api/vapi/vapi_c_gen.py
Executable file
809
src/vpp-api/vapi/vapi_c_gen.py
Executable file
File diff suppressed because it is too large
Load Diff
76
src/vpp-api/vapi/vapi_dbg.h
Normal file
76
src/vpp-api/vapi/vapi_dbg.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
*------------------------------------------------------------------
|
||||
* Copyright (c) 2017 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_vapi_debug_h__
|
||||
#define __included_vapi_debug_h__
|
||||
|
||||
/* controls debug prints */
|
||||
#define VAPI_DEBUG (0)
|
||||
#define VAPI_DEBUG_CONNECT (0)
|
||||
#define VAPI_DEBUG_ALLOC (0)
|
||||
|
||||
#if VAPI_DEBUG
|
||||
#include <stdio.h>
|
||||
#define VAPI_DEBUG_FILE_DEF \
|
||||
static const char *__file = NULL; \
|
||||
{ \
|
||||
__file = strrchr (__FILE__, '/'); \
|
||||
if (__file) \
|
||||
{ \
|
||||
++__file; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
__file = __FILE__; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VAPI_DBG(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
VAPI_DEBUG_FILE_DEF \
|
||||
printf ("DBG:%s:%d:%s():" fmt, __file, __LINE__, __func__, \
|
||||
##__VA_ARGS__); \
|
||||
printf ("\n"); \
|
||||
fflush (stdout); \
|
||||
} \
|
||||
while (0);
|
||||
|
||||
#define VAPI_ERR(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
VAPI_DEBUG_FILE_DEF \
|
||||
printf ("ERR:%s:%d:%s():" fmt, __file, __LINE__, __func__, \
|
||||
##__VA_ARGS__); \
|
||||
printf ("\n"); \
|
||||
fflush (stdout); \
|
||||
} \
|
||||
while (0);
|
||||
#else
|
||||
#define VAPI_DBG(...)
|
||||
#define VAPI_ERR(...)
|
||||
#endif
|
||||
|
||||
#endif /* __included_vapi_debug_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
126
src/vpp-api/vapi/vapi_internal.h
Normal file
126
src/vpp-api/vapi/vapi_internal.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
*------------------------------------------------------------------
|
||||
* Copyright (c) 2017 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 VAPI_INTERNAL_H
|
||||
#define VAPI_INTERNAL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <vppinfra/types.h>
|
||||
|
||||
/**
|
||||
* @file vapi_internal.h
|
||||
*
|
||||
* internal vpp api C declarations
|
||||
*
|
||||
* This file contains internal vpp api C declarations. It's not intended to be
|
||||
* used by the client programmer and the API defined here might change at any
|
||||
* time..
|
||||
*/
|
||||
|
||||
struct vapi_ctx_s;
|
||||
|
||||
typedef struct __attribute__ ((__packed__))
|
||||
{
|
||||
u16 _vl_msg_id;
|
||||
u32 context;
|
||||
} vapi_type_msg_header1_t;
|
||||
|
||||
typedef struct __attribute__ ((__packed__))
|
||||
{
|
||||
u16 _vl_msg_id;
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
} vapi_type_msg_header2_t;
|
||||
|
||||
static inline void
|
||||
vapi_type_msg_header1_t_hton (vapi_type_msg_header1_t * h)
|
||||
{
|
||||
h->_vl_msg_id = htobe16 (h->_vl_msg_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
vapi_type_msg_header1_t_ntoh (vapi_type_msg_header1_t * h)
|
||||
{
|
||||
h->_vl_msg_id = be16toh (h->_vl_msg_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
vapi_type_msg_header2_t_hton (vapi_type_msg_header2_t * h)
|
||||
{
|
||||
h->_vl_msg_id = htobe16 (h->_vl_msg_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
vapi_type_msg_header2_t_ntoh (vapi_type_msg_header2_t * h)
|
||||
{
|
||||
h->_vl_msg_id = be16toh (h->_vl_msg_id);
|
||||
}
|
||||
|
||||
|
||||
#include <vapi.h>
|
||||
|
||||
typedef vapi_error_e (*vapi_cb_t) (struct vapi_ctx_s *, void *, vapi_error_e,
|
||||
bool, void *);
|
||||
|
||||
typedef void (*generic_swap_fn_t) (void *payload);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
const char *name_with_crc;
|
||||
size_t name_with_crc_len;
|
||||
bool has_context;
|
||||
size_t context_offset;
|
||||
size_t payload_offset;
|
||||
size_t size;
|
||||
generic_swap_fn_t swap_to_be;
|
||||
generic_swap_fn_t swap_to_host;
|
||||
vapi_msg_id_t id; /* assigned at run-time */
|
||||
} vapi_message_desc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
int payload_offset;
|
||||
size_t size;
|
||||
void (*swap_to_be) (void *payload);
|
||||
void (*swap_to_host) (void *payload);
|
||||
} vapi_event_desc_t;
|
||||
|
||||
extern bool *__vapi_msg_is_with_context;
|
||||
|
||||
vapi_msg_id_t vapi_register_msg (vapi_message_desc_t * msg);
|
||||
u16 vapi_lookup_vl_msg_id (vapi_ctx_t ctx, vapi_msg_id_t id);
|
||||
int vapi_get_client_index (vapi_ctx_t ctx);
|
||||
bool vapi_is_nonblocking (vapi_ctx_t ctx);
|
||||
bool vapi_requests_full (vapi_ctx_t ctx);
|
||||
size_t vapi_get_request_count (vapi_ctx_t ctx);
|
||||
size_t vapi_get_max_request_count (vapi_ctx_t ctx);
|
||||
u32 vapi_gen_req_context (vapi_ctx_t ctx);
|
||||
void vapi_store_request (vapi_ctx_t ctx, u32 context, bool is_dump,
|
||||
vapi_cb_t callback, void *callback_ctx);
|
||||
int vapi_get_payload_offset (vapi_msg_id_t id);
|
||||
void (*vapi_get_swap_to_host_func (vapi_msg_id_t id)) (void *payload);
|
||||
void (*vapi_get_swap_to_be_func (vapi_msg_id_t id)) (void *payload);
|
||||
size_t vapi_get_message_size (vapi_msg_id_t id);
|
||||
size_t vapi_get_context_offset (vapi_msg_id_t id);
|
||||
|
||||
vapi_error_e vapi_producer_lock (vapi_ctx_t ctx);
|
||||
vapi_error_e vapi_producer_unlock (vapi_ctx_t ctx);
|
||||
|
||||
#endif
|
303
src/vpp-api/vapi/vapi_json_parser.py
Normal file
303
src/vpp-api/vapi/vapi_json_parser.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -107,7 +107,11 @@ sanity: verify-no-running-vpp
|
||||
echo \"*******************************************************************\" &&\
|
||||
false)"
|
||||
|
||||
test: verify-python-path $(PAPI_INSTALL_DONE) sanity reset
|
||||
.PHONY: ext
|
||||
ext:
|
||||
make -C ext
|
||||
|
||||
test: verify-python-path $(PAPI_INSTALL_DONE) ext sanity reset
|
||||
$(call retest-func)
|
||||
|
||||
retest: verify-python-path sanity reset
|
||||
|
17
test/ext/Makefile
Normal file
17
test/ext/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
BINDIR = $(BR)/vapi_test/
|
||||
BIN = $(addprefix $(BINDIR), vapi_test)
|
||||
LIBS = -L$(VPP_TEST_BUILD_DIR)/vpp/.libs/ -L$(VPP_TEST_BUILD_DIR)/vpp/vpp-api/vapi/.libs/ -lvppinfra -lvlibmemoryclient -lsvm -lpthread -lcheck -lsubunit -lrt -lm -lvapiclient
|
||||
CFLAGS = -ggdb -O0 -Wall -pthread -I$(WS_ROOT)/src -I$(VPP_TEST_BUILD_DIR)/vpp/vpp-api/vapi -I$(WS_ROOT)/src/vpp-api/vapi/
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BINDIR):
|
||||
mkdir -p $(BINDIR)
|
||||
|
||||
SRC = vapi_test.c
|
||||
|
||||
$(BIN): $(SRC) $(BINDIR) $(VPP_TEST_BUILD_DIR)/vpp/vpp-api/vapi/.libs/libvapiclient.so $(VPP_TEST_BUILD_DIR)/vpp/.libs/libvppinfra.so $(VPP_TEST_BUILD_DIR)/vpp/.libs/libvlibmemoryclient.so $(VPP_TEST_BUILD_DIR)/vpp/.libs/libsvm.so
|
||||
gcc -ggdb -o $@ $(SRC) $(CFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -rf $(BINDIR)
|
1152
test/ext/vapi_test.c
Normal file
1152
test/ext/vapi_test.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,15 @@
|
||||
function usage() {
|
||||
echo "$0" 1>&2
|
||||
echo "" 1>&2
|
||||
echo "Usage: $0 [-p <pre-exec-cmd>] [-m <email>] -- <make test options>" 1>&2
|
||||
echo "Usage: $0 [-p <pre-exec-cmd>] [-m <email>] -- <make test options|verify>" 1>&2
|
||||
echo "" 1>&2
|
||||
echo "Parameters:" 1>&2
|
||||
echo " -p <pre-exec-cmd> - run a command before each test loop (e.g. 'git pull')" 1>&2
|
||||
echo " -m <email> - if set, email is sent to this address on failure" 1>&2
|
||||
echo "" 1>&2
|
||||
echo "Example:" 1>&2
|
||||
echo " $0 -m <somebody@cisco.com> -- test-debug TEST=l2bd"
|
||||
echo "Examples:" 1>&2
|
||||
echo " $0 -m <somebody@cisco.com> -- test-debug TEST=l2bd" 1>&2
|
||||
echo " $0 -m <somebody@cisco.com> -- verify" 1>&2
|
||||
exit 1;
|
||||
}
|
||||
|
||||
@@ -44,8 +45,11 @@ shift $((OPTIND-1))
|
||||
|
||||
if ! echo $* | grep test >/dev/null
|
||||
then
|
||||
echo "Error: command line doesn't look right - should contain \`test' token..." >&2
|
||||
usage
|
||||
if ! echo $* | grep verify >/dev/null
|
||||
then
|
||||
echo "Error: command line doesn't look right - should contain \`test' or \`verify' token..." >&2
|
||||
usage
|
||||
fi
|
||||
fi
|
||||
|
||||
function finish {
|
||||
|
78
test/test_vapi.py
Normal file
78
test/test_vapi.py
Normal file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
""" VAPI test """
|
||||
|
||||
from __future__ import division
|
||||
import unittest
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
from threading import Thread
|
||||
from log import single_line_delim
|
||||
from framework import VppTestCase, running_extended_tests, VppTestRunner
|
||||
|
||||
|
||||
class Worker(Thread):
|
||||
def __init__(self, args, logger):
|
||||
self.logger = logger
|
||||
self.args = args
|
||||
self.result = None
|
||||
super(Worker, self).__init__()
|
||||
|
||||
def run(self):
|
||||
executable = self.args[0]
|
||||
self.logger.debug("Running executable w/args `%s'" % self.args)
|
||||
env = os.environ.copy()
|
||||
env["CK_LOG_FILE_NAME"] = "-"
|
||||
self.process = subprocess.Popen(
|
||||
self.args, shell=False, env=env, preexec_fn=os.setpgrp,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = self.process.communicate()
|
||||
self.logger.debug("Finished running `%s'" % executable)
|
||||
self.logger.info("Return code is `%s'" % self.process.returncode)
|
||||
self.logger.info(single_line_delim)
|
||||
self.logger.info("Executable `%s' wrote to stdout:" % executable)
|
||||
self.logger.info(single_line_delim)
|
||||
self.logger.info(out)
|
||||
self.logger.info(single_line_delim)
|
||||
self.logger.info("Executable `%s' wrote to stderr:" % executable)
|
||||
self.logger.info(single_line_delim)
|
||||
self.logger.error(err)
|
||||
self.logger.info(single_line_delim)
|
||||
self.result = self.process.returncode
|
||||
|
||||
|
||||
@unittest.skipUnless(running_extended_tests(), "part of extended tests")
|
||||
class VAPITestCase(VppTestCase):
|
||||
""" VAPI test """
|
||||
|
||||
def test_vapi(self):
|
||||
""" run VAPI tests """
|
||||
var = "BR"
|
||||
built_root = os.getenv(var, None)
|
||||
self.assertIsNotNone(built_root,
|
||||
"Environment variable `%s' not set" % var)
|
||||
executable = "%s/vapi_test/vapi_test" % built_root
|
||||
worker = Worker(
|
||||
[executable, "vapi client", self.shm_prefix], self.logger)
|
||||
worker.start()
|
||||
timeout = 45
|
||||
worker.join(timeout)
|
||||
self.logger.info("Worker result is `%s'" % worker.result)
|
||||
error = False
|
||||
if worker.result is None:
|
||||
try:
|
||||
error = True
|
||||
self.logger.error(
|
||||
"Timeout! Worker did not finish in %ss" % timeout)
|
||||
os.killpg(os.getpgid(worker.process.pid), signal.SIGTERM)
|
||||
worker.join()
|
||||
except:
|
||||
raise Exception("Couldn't kill worker-spawned process")
|
||||
if error:
|
||||
raise Exception(
|
||||
"Timeout! Worker did not finish in %ss" % timeout)
|
||||
self.assert_equal(worker.result, 0, "Binary test return code")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=VppTestRunner)
|
Reference in New Issue
Block a user