Add new C API

Change-Id: I717ce3cd7c867c155de149ec56623269d26d0ff7
Signed-off-by: Klement Sekera <ksekera@cisco.com>
This commit is contained in:
Klement Sekera
2017-05-04 06:15:18 +02:00
committed by Neale Ranns
parent f4215a65cb
commit 8f2a4eafea
19 changed files with 3943 additions and 14 deletions

1
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -80,6 +80,8 @@ if ENABLE_JAPI
SUBDIRS += vpp-api/java
endif
SUBDIRS += vpp-api/vapi
###############################################################################
# API
###############################################################################

View File

@@ -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

View File

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

View File

@@ -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);

View 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

View 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

File diff suppressed because it is too large Load Diff

285
src/vpp-api/vapi/vapi.h Normal file
View 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

File diff suppressed because it is too large Load Diff

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

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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
View 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)