aboutsummaryrefslogtreecommitdiffstats
path: root/src/vlibapi
diff options
context:
space:
mode:
Diffstat (limited to 'src/vlibapi')
-rw-r--r--src/vlibapi/CMakeLists.txt21
-rw-r--r--src/vlibapi/api.h33
-rw-r--r--src/vlibapi/api_common.h119
-rw-r--r--src/vlibapi/api_doc.rst1
-rw-r--r--src/vlibapi/api_format.c39
-rw-r--r--src/vlibapi/api_helper_macros.h589
-rw-r--r--src/vlibapi/api_shared.c431
-rw-r--r--src/vlibapi/memory_shared.c815
-rw-r--r--src/vlibapi/memory_shared.h147
-rw-r--r--src/vlibapi/node_serialize.c4
10 files changed, 1674 insertions, 525 deletions
diff --git a/src/vlibapi/CMakeLists.txt b/src/vlibapi/CMakeLists.txt
index e6937a6db01..6476b5a2f33 100644
--- a/src/vlibapi/CMakeLists.txt
+++ b/src/vlibapi/CMakeLists.txt
@@ -11,16 +11,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-install(
- FILES
- api_helper_macros.h
+add_vpp_library (vlibapi
+ SOURCES
+ api_shared.c
+ api_format.c
+ node_serialize.c
+ memory_shared.c
+
+ INSTALL_HEADERS
api.h
- vat_helper_macros.h
api_common.h
+ api_helper_macros.h
api_types.h
-
- DESTINATION
- ${CMAKE_INSTALL_INCLUDEDIR}/vlibapi
-
- COMPONENT vpp-dev
+ vat_helper_macros.h
+ memory_shared.h
)
+
diff --git a/src/vlibapi/api.h b/src/vlibapi/api.h
index d05395a213c..74957a6f0f6 100644
--- a/src/vlibapi/api.h
+++ b/src/vlibapi/api.h
@@ -28,13 +28,11 @@
#include <vlib/unix/unix.h>
#include <vlibapi/api_common.h>
-/* *INDENT-OFF* */
typedef CLIB_PACKED ( struct {
u32 nitems;
u32 msgtbl_size;
u8 wrapped;
}) vl_api_trace_file_header_t;
-/* *INDENT-ON* */
int vl_msg_api_trace_save (api_main_t *am, vl_api_trace_which_t which,
FILE *fp, u8 is_json);
@@ -105,10 +103,6 @@ int vl_msg_api_trace_onoff (api_main_t * am, vl_api_trace_which_t which,
int vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which);
int vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
u32 nitems);
-void vl_msg_api_handler_with_vm_node (api_main_t * am, svm_region_t * vlib_rp,
- void *the_msg, vlib_main_t * vm,
- vlib_node_runtime_t * node,
- u8 is_private);
u32 vl_msg_api_max_length (void *mp);
vl_api_trace_t *vl_msg_api_trace_get (api_main_t * am,
vl_api_trace_which_t which);
@@ -128,6 +122,33 @@ typedef int (*vl_msg_traverse_trace_fn) (u8 *, void *);
int vl_msg_traverse_trace (vl_api_trace_t *tp, vl_msg_traverse_trace_fn fn,
void *ctx);
+always_inline void
+vl_api_increase_msg_trace_size (api_main_t *am, u32 msg_id, u32 inc)
+{
+ am->msg_data[msg_id].trace_size += inc;
+}
+
+always_inline void
+vl_api_set_msg_thread_safe (api_main_t *am, u32 msg_id, int v)
+{
+ am->msg_data[msg_id].is_mp_safe = v != 0;
+}
+
+always_inline void
+vl_api_set_msg_autoendian (api_main_t *am, u32 msg_id, int v)
+{
+ am->msg_data[msg_id].is_autoendian = v != 0;
+}
+
+always_inline void
+vl_api_allow_msg_replay (api_main_t *am, u32 msg_id, int v)
+{
+ am->msg_data[msg_id].replay_allowed = v != 0;
+}
+
+format_function_t format_vl_api_msg_text;
+format_function_t format_vl_api_msg_json;
+
#endif /* included_api_h */
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vlibapi/api_common.h b/src/vlibapi/api_common.h
index 320e7c44e16..c09334136c0 100644
--- a/src/vlibapi/api_common.h
+++ b/src/vlibapi/api_common.h
@@ -75,18 +75,12 @@ typedef struct vl_api_registration_
/* socket client only */
u32 server_handle; /**< Socket client only: server handle */
u32 server_index; /**< Socket client only: server index */
+
+ bool keepalive; /**< Dead client scan */
} vl_api_registration_t;
#define VL_API_INVALID_FI ((u32)~0)
-/** Trace configuration for a single message */
-typedef struct
-{
- int size; /**< for sanity checking */
- int trace_enable; /**< trace this message */
- int replay_enable; /**< This message can be replayed */
-} trace_cfg_t;
-
/**
* API trace state
*/
@@ -128,16 +122,16 @@ typedef struct
void *handler; /**< the message handler */
void *cleanup; /**< non-default message cleanup handler */
void *endian; /**< message endian function */
- void *print; /**< message print function */
- void *print_json; /**< message print function (JSON format) */
+ void *format_fn; /**< message format function */
void *tojson; /**< binary to JSON convert function */
void *fromjson; /**< JSON to binary convert function */
+ void *calc_size; /**< message size calculation */
int size; /**< message size */
- int traced; /**< is this message to be traced? */
- int replay; /**< is this message to be replayed? */
- int message_bounce; /**< do not free message after processing */
- int is_mp_safe; /**< worker thread barrier required? */
- int is_autoendian; /**< endian conversion required? */
+ u32 traced : 1; /**< is this message to be traced? */
+ u32 replay : 1; /**< is this message to be replayed? */
+ u32 message_bounce : 1; /**< do not free message after processing */
+ u32 is_mp_safe : 1; /**< worker thread barrier required? */
+ u32 is_autoendian : 1; /**< endian conversion required? */
} vl_msg_api_msg_config_t;
/** Message header structure */
@@ -149,38 +143,34 @@ typedef struct msgbuf_
u8 data[0]; /**< actual message begins here */
} msgbuf_t;
-CLIB_NOSANITIZE_ADDR static inline void
+__clib_nosanitize_addr static inline void
VL_MSG_API_UNPOISON (const void *a)
{
const msgbuf_t *m = &((const msgbuf_t *) a)[-1];
- CLIB_MEM_UNPOISON (m, sizeof (*m) + ntohl (m->data_len));
+ clib_mem_unpoison (m, sizeof (*m) + ntohl (m->data_len));
}
-CLIB_NOSANITIZE_ADDR static inline void
-VL_MSG_API_SVM_QUEUE_UNPOISON (const svm_queue_t * q)
+__clib_nosanitize_addr static inline void
+VL_MSG_API_SVM_QUEUE_UNPOISON (const svm_queue_t *q)
{
- CLIB_MEM_UNPOISON (q, sizeof (*q) + q->elsize * q->maxsize);
+ clib_mem_unpoison (q, sizeof (*q) + q->elsize * q->maxsize);
}
static inline void
VL_MSG_API_POISON (const void *a)
{
const msgbuf_t *m = &((const msgbuf_t *) a)[-1];
- CLIB_MEM_POISON (m, sizeof (*m) + ntohl (m->data_len));
+ clib_mem_poison (m, sizeof (*m) + ntohl (m->data_len));
}
/* api_shared.c prototypes */
-void vl_msg_api_handler (void *the_msg);
-void vl_msg_api_handler_no_free (void *the_msg);
-void vl_msg_api_handler_no_trace_no_free (void *the_msg);
-void vl_msg_api_trace_only (void *the_msg);
+void vl_msg_api_handler (void *the_msg, uword msg_len);
+void vl_msg_api_handler_no_free (void *the_msg, uword msg_len);
+void vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len);
+void vl_msg_api_trace_only (void *the_msg, uword msg_len);
void vl_msg_api_cleanup_handler (void *the_msg);
void vl_msg_api_replay_handler (void *the_msg);
-void vl_msg_api_socket_handler (void *the_msg);
-void vl_msg_api_set_handlers (int msg_id, char *msg_name, void *handler,
- void *cleanup, void *endian, void *print,
- int msg_size, int traced, void *print_json,
- void *tojson, void *fromjson);
+void vl_msg_api_socket_handler (void *the_msg, uword msg_len);
void vl_msg_api_clean_handlers (int msg_id);
void vl_msg_api_config (vl_msg_api_msg_config_t *);
void vl_msg_api_set_cleanup_handler (int msg_id, void *fp);
@@ -195,13 +185,11 @@ void vl_msg_api_barrier_trace_context (const char *context)
#define vl_msg_api_barrier_trace_context(X)
#endif
void vl_msg_api_free (void *);
-void vl_noop_handler (void *mp);
void vl_msg_api_increment_missing_client_counter (void);
void vl_msg_api_post_mortem_dump (void);
void vl_msg_api_post_mortem_dump_enable_disable (int enable);
void vl_msg_api_register_pd_handler (void *handler,
u16 msg_id_host_byte_order);
-int vl_msg_api_pd_handler (void *mp, int rv);
void vl_msg_api_set_first_available_msg_id (u16 first_avail);
u16 vl_msg_api_get_msg_ids (const char *name, int n);
@@ -227,44 +215,51 @@ typedef struct
char name[64];
} api_version_t;
-/** API main structure, used by both vpp and binary API clients */
-typedef struct api_main_t
+typedef struct
{
/** Message handler vector */
- void (**msg_handlers) (void *);
+ void (*handler) (void *);
/** non-default message cleanup handler vector */
- void (**msg_cleanup_handlers) (void *);
-
- /** Message endian handler vector */
- void (**msg_endian_handlers) (void *);
+ void (*cleanup_handler) (void *);
- /** Message print function vector */
- void (**msg_print_handlers) (void *, void *);
+ /** Message name vector */
+ const char *name;
- /** Message print function vector in JSON */
- void (**msg_print_json_handlers) (void *, void *);
+ /** Message format function */
+ format_function_t *format_fn;
/** Message convert function vector */
- cJSON *(**msg_tojson_handlers) (void *);
+ cJSON *(*tojson_handler) (void *);
/** Message convert function vector */
- void *(**msg_fromjson_handlers) (cJSON *, int *);
+ void *(*fromjson_handler) (cJSON *, int *);
- /** Message name vector */
- const char **msg_names;
+ /** Message endian handler vector. */
+ void (*endian_handler) (void *, bool to_net);
- /** API message ID by name hash table */
- uword *msg_id_by_name;
+ /** Message calc size function vector */
+ uword (*calc_size_func) (void *);
- /** Don't automatically free message buffer vetor */
- u8 *message_bounce;
+ /** trace size for sanity checking */
+ int trace_size;
- /** Message is mp safe vector */
- u8 *is_mp_safe;
+ /** Flags */
+ u8 bounce : 1; /**> Don't automatically free message buffer vetor */
+ u8 is_mp_safe : 1; /**< Message is mp safe vector */
+ u8 is_autoendian : 1; /**< Message requires us to do endian conversion */
+ u8 trace_enable : 1; /**< trace this message */
+ u8 replay_allowed : 1; /**< This message can be replayed */
- /** Message requires us to do endian conversion */
- u8 *is_autoendian;
+} vl_api_msg_data_t;
+
+/** API main structure, used by both vpp and binary API clients */
+typedef struct api_main_t
+{
+ vl_api_msg_data_t *msg_data;
+
+ /** API message ID by name hash table */
+ uword *msg_id_by_name;
/** Allocator ring vectors (in shared memory) */
struct ring_alloc_ *arings;
@@ -287,9 +282,6 @@ typedef struct api_main_t
/** Print every received message */
int msg_print_flag;
- /** Current trace configuration */
- trace_cfg_t *api_trace_cfg;
-
/** Current process PID */
int our_pid;
@@ -362,6 +354,8 @@ typedef struct api_main_t
/** client message index hash table */
uword *msg_index_by_name_and_crc;
+ /** plugin JSON representation vector table */
+ u8 **json_api_repr;
/** api version list */
api_version_t *api_version_list;
@@ -397,7 +391,6 @@ typedef struct api_main_t
} api_main_t;
extern __thread api_main_t *my_api_main;
-extern api_main_t api_global_main;
always_inline api_main_t *
vlibapi_get_main (void)
@@ -405,6 +398,14 @@ vlibapi_get_main (void)
return my_api_main;
}
+always_inline vl_api_msg_data_t *
+vl_api_get_msg_data (api_main_t *am, u32 msg_id)
+{
+ if (msg_id >= vec_len (am->msg_data))
+ return 0;
+ return am->msg_data + msg_id;
+}
+
always_inline void
vlibapi_set_main (api_main_t * am)
{
diff --git a/src/vlibapi/api_doc.rst b/src/vlibapi/api_doc.rst
index 7d2b80a2e06..2131cc1919c 100644
--- a/src/vlibapi/api_doc.rst
+++ b/src/vlibapi/api_doc.rst
@@ -300,7 +300,6 @@ Set up message handlers about as follows:
#undef vl_endianfun
/* instantiate all the print functions we know about */
- #define vl_print(handle, ...)
#define vl_printfun
#include <vpp/api/vpe_all_api_h.h>
#undef vl_printfun
diff --git a/src/vlibapi/api_format.c b/src/vlibapi/api_format.c
new file mode 100644
index 00000000000..f7bb9d3970f
--- /dev/null
+++ b/src/vlibapi/api_format.c
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2022 Cisco Systems, Inc.
+ */
+
+#include <vppinfra/format.h>
+#include <vlibapi/api.h>
+
+u8 *
+format_vl_api_msg_text (u8 *s, va_list *args)
+{
+ api_main_t *am = va_arg (*args, api_main_t *);
+ u32 msg_id = va_arg (*args, u32);
+ void *msg = va_arg (*args, void *);
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
+
+ if (m->format_fn)
+ s = format (s, "%U", m->format_fn, msg);
+ else
+ s = format (s, "[format handler missing for `%s`]", m->name);
+ return s;
+}
+
+u8 *
+format_vl_api_msg_json (u8 *s, va_list *args)
+{
+ api_main_t *am = va_arg (*args, api_main_t *);
+ u32 msg_id = va_arg (*args, u32);
+ void *msg = va_arg (*args, void *);
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
+
+ cJSON *o = m->tojson_handler (msg);
+ char *out = cJSON_Print (o);
+
+ s = format (s, "%s", out);
+
+ cJSON_Delete (o);
+ cJSON_free (out);
+ return s;
+}
diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h
index 7a04bb056f2..0380692b80e 100644
--- a/src/vlibapi/api_helper_macros.h
+++ b/src/vlibapi/api_helper_macros.h
@@ -27,72 +27,96 @@
#define REPLY_MSG_ID_BASE 0
#endif
-#define REPLY_MACRO(t) \
-do { \
- vl_api_registration_t *rp; \
- rp = vl_api_client_index_to_registration (mp->client_index); \
- if (rp == 0) \
- return; \
- \
- rmp = vl_msg_api_alloc (sizeof (*rmp)); \
- rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE)); \
- rmp->context = mp->context; \
- rmp->retval = ntohl(rv); \
- \
- vl_api_send_msg (rp, (u8 *)rmp); \
-} while(0);
+#define _NATIVE_TO_NETWORK(t, rmp) \
+ api_main_t *am = vlibapi_get_main (); \
+ void (*endian_fp) (void *, bool); \
+ endian_fp = am->msg_data[t + (REPLY_MSG_ID_BASE)].endian_handler; \
+ (*endian_fp) (rmp, 1 /* to network */);
-#define REPLY_MACRO_END(t) \
-do { \
- vl_api_registration_t *rp; \
- rp = vl_api_client_index_to_registration (mp->client_index); \
- if (rp == 0) \
- return; \
- \
- rmp = vl_msg_api_alloc (sizeof (*rmp)); \
- rmp->_vl_msg_id = t+(REPLY_MSG_ID_BASE); \
- rmp->context = mp->context; \
- rmp->retval = rv; \
- api_main_t *am = vlibapi_get_main (); \
- void (*endian_fp) (void *); \
- endian_fp = am->msg_endian_handlers[t+(REPLY_MSG_ID_BASE)]; \
- (*endian_fp) (rmp); \
- vl_api_send_msg (rp, (u8 *)rmp); \
-} while(0);
+#define REPLY_MACRO(msg) \
+ do \
+ { \
+ STATIC_ASSERT ( \
+ msg##_IS_CONSTANT_SIZE, \
+ "REPLY_MACRO can only be used with constant size messages, " \
+ "use REPLY_MACRO[3|4]* instead"); \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ rmp->_vl_msg_id = htons (msg + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = ntohl (rv); \
+ \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
-#define REPLY_MACRO2(t, body) \
-do { \
- vl_api_registration_t *rp; \
- rp = vl_api_client_index_to_registration (mp->client_index); \
- if (rp == 0) \
- return; \
- \
- rmp = vl_msg_api_alloc (sizeof (*rmp)); \
- rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE)); \
- rmp->context = mp->context; \
- rmp->retval = ntohl(rv); \
- do {body;} while (0); \
- vl_api_send_msg (rp, (u8 *)rmp); \
-} while(0);
+#define REPLY_MACRO_END(t) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ rmp->_vl_msg_id = t + (REPLY_MSG_ID_BASE); \
+ rmp->context = mp->context; \
+ rmp->retval = rv; \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
-#define REPLY_MACRO2_END(t, body) \
-do { \
- vl_api_registration_t *rp; \
- rp = vl_api_client_index_to_registration (mp->client_index); \
- if (rp == 0) \
- return; \
- \
- rmp = vl_msg_api_alloc (sizeof (*rmp)); \
- rmp->_vl_msg_id = t+(REPLY_MSG_ID_BASE); \
- rmp->context = mp->context; \
- rmp->retval = rv; \
- do {body;} while (0); \
- api_main_t *am = vlibapi_get_main (); \
- void (*endian_fp) (void *); \
- endian_fp = am->msg_endian_handlers[t+(REPLY_MSG_ID_BASE)]; \
- (*endian_fp) (rmp); \
- vl_api_send_msg (rp, (u8 *)rmp); \
-} while(0);
+#define REPLY_MACRO2(t, body) \
+ do \
+ { \
+ STATIC_ASSERT ( \
+ t##_IS_CONSTANT_SIZE, \
+ "REPLY_MACRO2 can only be used with constant size messages, " \
+ "use REPLY_MACRO[3|4]* instead"); \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ rmp->_vl_msg_id = htons ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = ntohl (rv); \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
+#define REPLY_MACRO2_END(t, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ rmp->_vl_msg_id = t + (REPLY_MSG_ID_BASE); \
+ rmp->context = mp->context; \
+ rmp->retval = rv; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
#define REPLY_MACRO2_ZERO(t, body) \
do { \
@@ -109,6 +133,28 @@ do { \
vl_api_send_msg (rp, (u8 *)rmp); \
} while(0);
+#define REPLY_MACRO2_ZERO_END(t, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc_zero (sizeof (*rmp)); \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = rv; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
#define REPLY_MACRO_DETAILS2(t, body) \
do { \
vl_api_registration_t *rp; \
@@ -123,6 +169,27 @@ do { \
vl_api_send_msg (rp, (u8 *)rmp); \
} while(0);
+#define REPLY_MACRO_DETAILS2_END(t, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
#define REPLY_MACRO_DETAILS4(t, rp, context, body) \
do { \
rmp = vl_msg_api_alloc (sizeof (*rmp)); \
@@ -132,20 +199,95 @@ do { \
vl_api_send_msg (rp, (u8 *)rmp); \
} while(0);
-#define REPLY_MACRO3(t, n, body) \
-do { \
- vl_api_registration_t *rp; \
- rp = vl_api_client_index_to_registration (mp->client_index); \
- if (rp == 0) \
- return; \
- \
- rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \
- rmp->_vl_msg_id = htons((t)+(REPLY_MSG_ID_BASE)); \
- rmp->context = mp->context; \
- rmp->retval = ntohl(rv); \
- do {body;} while (0); \
- vl_api_send_msg (rp, (u8 *)rmp); \
-} while(0);
+#define REPLY_MACRO_DETAILS4_END(t, rp, context, body) \
+ do \
+ { \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = context; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
+#define REPLY_MACRO_DETAILS5(t, n, rp, context, body) \
+ do \
+ { \
+ rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \
+ rmp->_vl_msg_id = htons ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = context; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
+#define REPLY_MACRO_DETAILS5_END(t, n, rp, context, body) \
+ do \
+ { \
+ rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = context; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
+#define REPLY_MACRO3(t, n, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp) + (n)); \
+ rmp->_vl_msg_id = htons ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = ntohl (rv); \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
+#define REPLY_MACRO3_END(t, n, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp) + n); \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = rv; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
#define REPLY_MACRO3_ZERO(t, n, body) \
do { \
@@ -162,6 +304,28 @@ do { \
vl_api_send_msg (rp, (u8 *)rmp); \
} while(0);
+#define REPLY_MACRO3_ZERO_END(t, n, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc_zero (sizeof (*rmp) + n); \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = rv; \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
#define REPLY_MACRO4(t, n, body) \
do { \
vl_api_registration_t *rp; \
@@ -192,6 +356,43 @@ do { \
vl_api_send_msg (rp, (u8 *)rmp); \
} while(0);
+#define REPLY_MACRO4_END(t, n, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ u8 is_error = 0; \
+ \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ \
+ rmp = vl_msg_api_alloc_or_null (sizeof (*rmp) + n); \
+ if (!rmp) \
+ { \
+ /* if there isn't enough memory, try to allocate */ \
+ /* some at least for returning an error */ \
+ rmp = vl_msg_api_alloc (sizeof (*rmp)); \
+ if (!rmp) \
+ return; \
+ \
+ clib_memset (rmp, 0, sizeof (*rmp)); \
+ rv = VNET_API_ERROR_TABLE_TOO_BIG; \
+ is_error = 1; \
+ } \
+ rmp->_vl_msg_id = ((t) + (REPLY_MSG_ID_BASE)); \
+ rmp->context = mp->context; \
+ rmp->retval = rv; \
+ if (!is_error) \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ _NATIVE_TO_NETWORK (t, rmp); \
+ vl_api_send_msg (rp, (u8 *) rmp); \
+ } \
+ while (0);
+
#define REPLY_AND_DETAILS_MACRO(t, p, body) \
do \
{ \
@@ -232,6 +433,46 @@ do { \
} \
while (0);
+#define REPLY_AND_DETAILS_MACRO_END(t, p, body) \
+ do \
+ { \
+ if (pool_elts (p) == 0) \
+ { \
+ REPLY_MACRO_END (t); \
+ break; \
+ } \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ u32 cursor = mp->cursor; \
+ vlib_main_t *vm = vlib_get_main (); \
+ f64 start = vlib_time_now (vm); \
+ if (pool_is_free_index (p, cursor)) \
+ { \
+ cursor = pool_next_index (p, cursor); \
+ if (cursor == ~0) \
+ rv = VNET_API_ERROR_INVALID_VALUE; \
+ } \
+ while (cursor != ~0) \
+ { \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ cursor = pool_next_index (p, cursor); \
+ if (vl_api_process_may_suspend (vm, rp, start)) \
+ { \
+ if (cursor != ~0) \
+ rv = VNET_API_ERROR_EAGAIN; \
+ break; \
+ } \
+ } \
+ REPLY_MACRO2_END (t, ({ rmp->cursor = cursor; })); \
+ } \
+ while (0);
+
#define REPLY_AND_DETAILS_VEC_MACRO(t, v, mp, rmp, rv, body) \
do { \
vl_api_registration_t *rp; \
@@ -260,6 +501,41 @@ do { \
})); \
} while(0);
+#define REPLY_AND_DETAILS_VEC_MACRO_END(t, v, mp, rmp, rv, body) \
+ do \
+ { \
+ vl_api_registration_t *rp; \
+ rp = vl_api_client_index_to_registration (mp->client_index); \
+ if (rp == 0) \
+ return; \
+ u32 cursor = mp->cursor; \
+ vlib_main_t *vm = vlib_get_main (); \
+ f64 start = vlib_time_now (vm); \
+ if (!v || vec_len (v) == 0) \
+ { \
+ cursor = ~0; \
+ rv = VNET_API_ERROR_INVALID_VALUE; \
+ } \
+ else if (cursor == ~0) \
+ cursor = 0; \
+ while (cursor != ~0 && cursor < vec_len (v)) \
+ { \
+ do \
+ { \
+ body; \
+ } \
+ while (0); \
+ ++cursor; \
+ if (vl_api_process_may_suspend (vm, rp, start)) \
+ { \
+ if (cursor < vec_len (v)) \
+ rv = VNET_API_ERROR_EAGAIN; \
+ break; \
+ } \
+ } \
+ REPLY_MACRO2_END (t, ({ rmp->cursor = cursor; })); \
+ } \
+ while (0);
/* "trust, but verify" */
#define vnet_sw_if_index_is_api_valid(sw_if_index) \
@@ -273,6 +549,17 @@ do { \
} \
} while(0);
+#define VALIDATE_SW_IF_INDEX_END(mp) \
+ do \
+ { \
+ if (!vnet_sw_if_index_is_api_valid ((mp)->sw_if_index)) \
+ { \
+ rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \
+ goto bad_sw_if_index; \
+ } \
+ } \
+ while (0);
+
#define BAD_SW_IF_INDEX_LABEL \
do { \
bad_sw_if_index: \
@@ -287,6 +574,17 @@ bad_sw_if_index: \
} \
} while(0);
+#define VALIDATE_RX_SW_IF_INDEX_END(mp) \
+ do \
+ { \
+ if (!vnet_sw_if_index_is_api_valid ((mp)->rx_sw_if_index)) \
+ { \
+ rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \
+ goto bad_rx_sw_if_index; \
+ } \
+ } \
+ while (0);
+
#define BAD_RX_SW_IF_INDEX_LABEL \
do { \
bad_rx_sw_if_index: \
@@ -301,6 +599,17 @@ bad_rx_sw_if_index: \
} \
} while(0);
+#define VALIDATE_TX_SW_IF_INDEX_END(mp) \
+ do \
+ { \
+ if (!vnet_sw_if_index_is_api_valid (mp->tx_sw_if_index)) \
+ { \
+ rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \
+ goto bad_tx_sw_if_index; \
+ } \
+ } \
+ while (0);
+
#define BAD_TX_SW_IF_INDEX_LABEL \
do { \
bad_tx_sw_if_index: \
@@ -315,68 +624,82 @@ bad_tx_sw_if_index: \
} \
} while(0);
+#define VALIDATE_BD_ID_END(mp) \
+ do \
+ { \
+ if (mp->bd_id > L2_BD_ID_MAX) \
+ { \
+ rv = VNET_API_ERROR_BD_ID_EXCEED_MAX; \
+ goto bad_bd_id; \
+ } \
+ } \
+ while (0);
+
#define BAD_BD_ID_LABEL \
do { \
bad_bd_id: \
; \
} while (0);
-#define pub_sub_handler(lca,UCA) \
-static void vl_api_want_##lca##_t_handler ( \
- vl_api_want_##lca##_t *mp) \
-{ \
- vpe_api_main_t *vam = &vpe_api_main; \
- vpe_client_registration_t *rp; \
- vl_api_want_##lca##_reply_t *rmp; \
- uword *p; \
- i32 rv = 0; \
- \
- p = hash_get (vam->lca##_registration_hash, mp->client_index); \
- if (p) { \
- if (mp->enable_disable) { \
- clib_warning ("pid %d: already enabled...", ntohl(mp->pid)); \
- rv = VNET_API_ERROR_INVALID_REGISTRATION; \
- goto reply; \
- } else { \
- rp = pool_elt_at_index (vam->lca##_registrations, p[0]); \
- pool_put (vam->lca##_registrations, rp); \
- hash_unset (vam->lca##_registration_hash, \
- mp->client_index); \
- goto reply; \
- } \
- } \
- if (mp->enable_disable == 0) { \
- clib_warning ("pid %d: already disabled...", mp->pid); \
- rv = VNET_API_ERROR_INVALID_REGISTRATION; \
- goto reply; \
- } \
- pool_get (vam->lca##_registrations, rp); \
- rp->client_index = mp->client_index; \
- rp->client_pid = mp->pid; \
- hash_set (vam->lca##_registration_hash, rp->client_index, \
- rp - vam->lca##_registrations); \
- \
-reply: \
- REPLY_MACRO (VL_API_WANT_##UCA##_REPLY); \
-} \
- \
-static clib_error_t * vl_api_want_##lca##_t_reaper (u32 client_index) \
-{ \
- vpe_api_main_t *vam = &vpe_api_main; \
- vpe_client_registration_t *rp; \
- uword *p; \
- \
- p = hash_get (vam->lca##_registration_hash, client_index); \
- if (p) \
- { \
- rp = pool_elt_at_index (vam->lca##_registrations, p[0]); \
- pool_put (vam->lca##_registrations, rp); \
- hash_unset (vam->lca##_registration_hash, client_index); \
- } \
- return (NULL); \
-} \
- \
-VL_MSG_API_REAPER_FUNCTION (vl_api_want_##lca##_t_reaper); \
+#define pub_sub_handler(lca, UCA) \
+ static void vl_api_want_##lca##_t_handler (vl_api_want_##lca##_t *mp) \
+ { \
+ vpe_api_main_t *vam = &vpe_api_main; \
+ vpe_client_registration_t *rp; \
+ vl_api_want_##lca##_reply_t *rmp; \
+ uword *p; \
+ i32 rv = 0; \
+ \
+ p = hash_get (vam->lca##_registration_hash, mp->client_index); \
+ if (p) \
+ { \
+ if (mp->enable_disable) \
+ { \
+ clib_warning ("pid %d: already enabled...", ntohl (mp->pid)); \
+ rv = VNET_API_ERROR_INVALID_REGISTRATION; \
+ goto reply; \
+ } \
+ else \
+ { \
+ rp = pool_elt_at_index (vam->lca##_registrations, p[0]); \
+ pool_put (vam->lca##_registrations, rp); \
+ hash_unset (vam->lca##_registration_hash, mp->client_index); \
+ goto reply; \
+ } \
+ } \
+ if (mp->enable_disable == 0) \
+ { \
+ clib_warning ("pid %d: already disabled...", mp->pid); \
+ rv = VNET_API_ERROR_INVALID_REGISTRATION; \
+ goto reply; \
+ } \
+ pool_get (vam->lca##_registrations, rp); \
+ rp->client_index = mp->client_index; \
+ rp->client_pid = mp->pid; \
+ hash_set (vam->lca##_registration_hash, rp->client_index, \
+ rp - vam->lca##_registrations); \
+ \
+ reply: \
+ REPLY_MACRO (VL_API_WANT_##UCA##_REPLY); \
+ } \
+ \
+ static clib_error_t *vl_api_want_##lca##_t_reaper (u32 client_index) \
+ { \
+ vpe_api_main_t *vam = &vpe_api_main; \
+ vpe_client_registration_t *rp; \
+ uword *p; \
+ \
+ p = hash_get (vam->lca##_registration_hash, client_index); \
+ if (p) \
+ { \
+ rp = pool_elt_at_index (vam->lca##_registrations, p[0]); \
+ pool_put (vam->lca##_registrations, rp); \
+ hash_unset (vam->lca##_registration_hash, client_index); \
+ } \
+ return (NULL); \
+ } \
+ \
+ VL_MSG_API_REAPER_FUNCTION (vl_api_want_##lca##_t_reaper);
#define foreach_registration_hash \
_(interface_events) \
diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c
index dd51ee5fae1..79064b292c9 100644
--- a/src/vlibapi/api_shared.c
+++ b/src/vlibapi/api_shared.c
@@ -32,14 +32,11 @@
#include <vppinfra/elog.h>
#include <vppinfra/callback.h>
-/* *INDENT-OFF* */
-api_main_t api_global_main =
- {
- .region_name = "/unset",
- .api_uid = -1,
- .api_gid = -1,
- };
-/* *INDENT-ON* */
+static api_main_t api_global_main = {
+ .region_name = "/unset",
+ .api_uid = -1,
+ .api_gid = -1,
+};
/* Please use vlibapi_get_main() to access my_api_main */
__thread api_main_t *my_api_main = &api_global_main;
@@ -80,13 +77,11 @@ vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg)
u8 **old_trace;
u8 *msg_copy;
u32 length;
- trace_cfg_t *cfgp;
u16 msg_id = clib_net_to_host_u16 (*((u16 *) msg));
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
msgbuf_t *header = (msgbuf_t *) (((u8 *) msg) - offsetof (msgbuf_t, data));
- cfgp = am->api_trace_cfg + msg_id;
-
- if (!cfgp || !cfgp->trace_enable)
+ if (!m || !m->trace_enable)
return;
msg_copy = 0;
@@ -212,13 +207,11 @@ vl_api_serialize_message_table (api_main_t * am, u8 * vector)
/* serialize the count */
serialize_integer (sm, nmsg, sizeof (u32));
- /* *INDENT-OFF* */
hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
({
serialize_likely_small_unsigned_integer (sm, hp->value[0]);
serialize_cstring (sm, (char *) hp->key);
}));
- /* *INDENT-ON* */
return serialize_close_vector (sm);
}
@@ -228,21 +221,21 @@ vl_msg_api_trace_write_one (api_main_t *am, u8 *msg, FILE *fp)
{
u8 *tmpmem = 0;
int tlen, slen;
- cJSON *(*tojson_fn) (void *);
u32 msg_length = vec_len (msg);
vec_validate (tmpmem, msg_length - 1);
clib_memcpy_fast (tmpmem, msg, msg_length);
u16 id = clib_net_to_host_u16 (*((u16 *) msg));
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, id);
- void (*endian_fp) (void *);
- endian_fp = am->msg_endian_handlers[id];
- (*endian_fp) (tmpmem);
+ if (m && m->endian_handler)
+ {
+ m->endian_handler (tmpmem, 1);
+ }
- if (id < vec_len (am->msg_tojson_handlers) && am->msg_tojson_handlers[id])
+ if (m && m->tojson_handler)
{
- tojson_fn = am->msg_tojson_handlers[id];
- cJSON *o = tojson_fn (tmpmem);
+ cJSON *o = m->tojson_handler (tmpmem);
char *s = cJSON_Print (o);
slen = strlen (s);
tlen = fwrite (s, 1, slen, fp);
@@ -500,76 +493,87 @@ vl_msg_api_barrier_release (void)
}
always_inline void
-msg_handler_internal (api_main_t * am,
- void *the_msg, int trace_it, int do_it, int free_it)
+msg_handler_internal (api_main_t *am, void *the_msg, uword msg_len,
+ int trace_it, int do_it, int free_it)
{
u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
- u8 *(*print_fp) (void *, void *);
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, id);
if (PREDICT_FALSE (am->elog_trace_api_messages))
{
- /* *INDENT-OFF* */
ELOG_TYPE_DECLARE (e) =
{
.format = "api-msg: %s",
.format_args = "T4",
};
- /* *INDENT-ON* */
struct
{
u32 c;
} *ed;
ed = ELOG_DATA (am->elog_main, e);
- if (id < vec_len (am->msg_names) && am->msg_names[id])
- ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
+ if (m && m->name)
+ ed->c = elog_string (am->elog_main, (char *) m->name);
else
ed->c = elog_string (am->elog_main, "BOGUS");
}
- if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
+ if (m && m->handler)
{
if (trace_it)
vl_msg_api_trace (am, am->rx_trace, the_msg);
if (am->msg_print_flag)
{
- fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
- print_fp = (void *) am->msg_print_handlers[id];
- if (print_fp == 0)
- {
- fformat (stdout, " [no registered print fn]\n");
- }
- else
+ fformat (stdout, "[%d]: %s\n", id, m->name);
+ fformat (stdout, "%U", format_vl_api_msg_text, am, id, the_msg);
+ }
+
+ uword calc_size = 0;
+ ASSERT (NULL != m->calc_size_func);
+ if (m->calc_size_func)
+ {
+ calc_size = m->calc_size_func (the_msg);
+ if (calc_size > msg_len)
{
- (*print_fp) (the_msg, stdout);
+ clib_warning (
+ "Truncated message '%s' (id %u) received, calculated size "
+ "%lu is bigger than actual size %llu, message dropped.",
+ m->name, id, calc_size, msg_len);
}
}
+ else
+ {
+ clib_warning ("Message '%s' (id %u) has NULL calc_size_func, cannot "
+ "verify message size is correct",
+ m->name, id);
+ }
- if (do_it)
+ /* don't process message if it's truncated, otherwise byte swaps
+ * and stuff could corrupt memory even beyond message if it's malicious
+ * e.g. VLA length field set to 1M elements, but VLA empty */
+ if (do_it && calc_size <= msg_len)
{
- if (!am->is_mp_safe[id])
+
+ if (!m->is_mp_safe)
{
vl_msg_api_barrier_trace_context (am->msg_names[id]);
vl_msg_api_barrier_sync ();
}
- if (am->is_autoendian[id])
- {
- void (*endian_fp) (void *);
- endian_fp = am->msg_endian_handlers[id];
- (*endian_fp) (the_msg);
- }
+ if (m->is_autoendian)
+ m->endian_handler (the_msg, 0);
if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
clib_call_callbacks (am->perf_counter_cbs, am, id,
0 /* before */ );
- (*am->msg_handlers[id]) (the_msg);
+ m->handler (the_msg);
if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
clib_call_callbacks (am->perf_counter_cbs, am, id,
1 /* after */ );
- if (!am->is_mp_safe[id])
+
+ if (!m->is_mp_safe)
vl_msg_api_barrier_release ();
}
}
@@ -583,7 +587,6 @@ msg_handler_internal (api_main_t * am,
if (PREDICT_FALSE (am->elog_trace_api_messages))
{
- /* *INDENT-OFF* */
ELOG_TYPE_DECLARE (e) =
{
.format = "api-msg-done(%s): %s",
@@ -595,7 +598,6 @@ msg_handler_internal (api_main_t * am,
"mp-safe",
}
};
- /* *INDENT-ON* */
struct
{
@@ -603,10 +605,10 @@ msg_handler_internal (api_main_t * am,
u32 c;
} *ed;
ed = ELOG_DATA (am->elog_main, e);
- if (id < vec_len (am->msg_names) && am->msg_names[id])
+ if (m && m->name)
{
- ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
- ed->barrier = !am->is_mp_safe[id];
+ ed->c = elog_string (am->elog_main, (char *) m->name);
+ ed->barrier = !m->is_mp_safe;
}
else
{
@@ -616,183 +618,31 @@ msg_handler_internal (api_main_t * am,
}
}
-void (*vl_msg_api_fuzz_hook) (u16, void *);
-
-/* This is only to be called from a vlib/vnet app */
void
-vl_msg_api_handler_with_vm_node (api_main_t * am, svm_region_t * vlib_rp,
- void *the_msg, vlib_main_t * vm,
- vlib_node_runtime_t * node, u8 is_private)
-{
- u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
- u8 *(*handler) (void *, void *, void *);
- u8 *(*print_fp) (void *, void *);
- svm_region_t *old_vlib_rp;
- void *save_shmem_hdr;
- int is_mp_safe = 1;
-
- if (PREDICT_FALSE (am->elog_trace_api_messages))
- {
- /* *INDENT-OFF* */
- ELOG_TYPE_DECLARE (e) =
- {
- .format = "api-msg: %s",
- .format_args = "T4",
- };
- /* *INDENT-ON* */
- struct
- {
- u32 c;
- } *ed;
- ed = ELOG_DATA (am->elog_main, e);
- if (id < vec_len (am->msg_names) && am->msg_names[id])
- ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
- else
- ed->c = elog_string (am->elog_main, "BOGUS");
- }
-
- if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
- {
- handler = (void *) am->msg_handlers[id];
-
- if (PREDICT_FALSE (am->rx_trace && am->rx_trace->enabled))
- vl_msg_api_trace (am, am->rx_trace, the_msg);
-
- if (PREDICT_FALSE (am->msg_print_flag))
- {
- fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
- print_fp = (void *) am->msg_print_handlers[id];
- if (print_fp == 0)
- {
- fformat (stdout, " [no registered print fn for msg %d]\n", id);
- }
- else
- {
- (*print_fp) (the_msg, vm);
- }
- }
- is_mp_safe = am->is_mp_safe[id];
-
- if (!is_mp_safe)
- {
- vl_msg_api_barrier_trace_context (am->msg_names[id]);
- vl_msg_api_barrier_sync ();
- }
- if (is_private)
- {
- old_vlib_rp = am->vlib_rp;
- save_shmem_hdr = am->shmem_hdr;
- am->vlib_rp = vlib_rp;
- am->shmem_hdr = (void *) vlib_rp->user_ctx;
- }
-
- if (PREDICT_FALSE (vl_msg_api_fuzz_hook != 0))
- (*vl_msg_api_fuzz_hook) (id, the_msg);
-
- if (am->is_autoendian[id])
- {
- void (*endian_fp) (void *);
- endian_fp = am->msg_endian_handlers[id];
- (*endian_fp) (the_msg);
- }
- if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
- clib_call_callbacks (am->perf_counter_cbs, am, id, 0 /* before */ );
-
- (*handler) (the_msg, vm, node);
-
- if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
- clib_call_callbacks (am->perf_counter_cbs, am, id, 1 /* after */ );
- if (is_private)
- {
- am->vlib_rp = old_vlib_rp;
- am->shmem_hdr = save_shmem_hdr;
- }
- if (!is_mp_safe)
- vl_msg_api_barrier_release ();
- }
- else
- {
- clib_warning ("no handler for msg id %d", id);
- }
-
- /*
- * Special-case, so we can e.g. bounce messages off the vnet
- * main thread without copying them...
- */
- if (id >= vec_len (am->message_bounce) || !(am->message_bounce[id]))
- {
- if (is_private)
- {
- old_vlib_rp = am->vlib_rp;
- save_shmem_hdr = am->shmem_hdr;
- am->vlib_rp = vlib_rp;
- am->shmem_hdr = (void *) vlib_rp->user_ctx;
- }
- vl_msg_api_free (the_msg);
- if (is_private)
- {
- am->vlib_rp = old_vlib_rp;
- am->shmem_hdr = save_shmem_hdr;
- }
- }
-
- if (PREDICT_FALSE (am->elog_trace_api_messages))
- {
- /* *INDENT-OFF* */
- ELOG_TYPE_DECLARE (e) =
- {
- .format = "api-msg-done(%s): %s",
- .format_args = "t4T4",
- .n_enum_strings = 2,
- .enum_strings =
- {
- "barrier",
- "mp-safe",
- }
- };
- /* *INDENT-ON* */
-
- struct
- {
- u32 barrier;
- u32 c;
- } *ed;
- ed = ELOG_DATA (am->elog_main, e);
- if (id < vec_len (am->msg_names) && am->msg_names[id])
- ed->c = elog_string (am->elog_main, (char *) am->msg_names[id]);
- else
- ed->c = elog_string (am->elog_main, "BOGUS");
- ed->barrier = is_mp_safe;
- }
-}
-
-void
-vl_msg_api_handler (void *the_msg)
+vl_msg_api_handler (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
- msg_handler_internal (am, the_msg,
- (am->rx_trace
- && am->rx_trace->enabled) /* trace_it */ ,
- 1 /* do_it */ , 1 /* free_it */ );
+ msg_handler_internal (am, the_msg, msg_len,
+ (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+ 1 /* do_it */, 1 /* free_it */);
}
void
-vl_msg_api_handler_no_free (void *the_msg)
+vl_msg_api_handler_no_free (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
- msg_handler_internal (am, the_msg,
- (am->rx_trace
- && am->rx_trace->enabled) /* trace_it */ ,
- 1 /* do_it */ , 0 /* free_it */ );
+ msg_handler_internal (am, the_msg, msg_len,
+ (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+ 1 /* do_it */, 0 /* free_it */);
}
void
-vl_msg_api_handler_no_trace_no_free (void *the_msg)
+vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
- msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
- 0 /* free_it */ );
+ msg_handler_internal (am, the_msg, msg_len, 0 /* trace_it */, 1 /* do_it */,
+ 0 /* free_it */);
}
/*
@@ -805,14 +655,13 @@ vl_msg_api_handler_no_trace_no_free (void *the_msg)
*
*/
void
-vl_msg_api_trace_only (void *the_msg)
+vl_msg_api_trace_only (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
- msg_handler_internal (am, the_msg,
- (am->rx_trace
- && am->rx_trace->enabled) /* trace_it */ ,
- 0 /* do_it */ , 0 /* free_it */ );
+ msg_handler_internal (am, the_msg, msg_len,
+ (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+ 0 /* do_it */, 0 /* free_it */);
}
void
@@ -820,14 +669,16 @@ vl_msg_api_cleanup_handler (void *the_msg)
{
api_main_t *am = vlibapi_get_main ();
u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, id);
- if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
+ if (PREDICT_FALSE (!m))
{
clib_warning ("_vl_msg_id too large: %d\n", id);
return;
}
- if (am->msg_cleanup_handlers[id])
- (*am->msg_cleanup_handlers[id]) (the_msg);
+
+ if (m->cleanup_handler)
+ m->cleanup_handler (the_msg);
vl_msg_api_free (the_msg);
}
@@ -839,17 +690,17 @@ void
vl_msg_api_replay_handler (void *the_msg)
{
api_main_t *am = vlibapi_get_main ();
-
u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, id);
- if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
+ if (PREDICT_FALSE (!m))
{
clib_warning ("_vl_msg_id too large: %d\n", id);
return;
}
/* do NOT trace the message... */
- if (am->msg_handlers[id])
- (*am->msg_handlers[id]) (the_msg);
+ if (m->handler)
+ m->handler (the_msg);
/* do NOT free the message buffer... */
}
@@ -863,34 +714,20 @@ vl_msg_api_get_msg_length (void *msg_arg)
* vl_msg_api_socket_handler
*/
void
-vl_msg_api_socket_handler (void *the_msg)
+vl_msg_api_socket_handler (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
- msg_handler_internal (am, the_msg,
- (am->rx_trace
- && am->rx_trace->enabled) /* trace_it */ ,
- 1 /* do_it */ , 0 /* free_it */ );
+ msg_handler_internal (am, the_msg, msg_len,
+ (am->rx_trace && am->rx_trace->enabled) /* trace_it */,
+ 1 /* do_it */, 0 /* free_it */);
}
-#define foreach_msg_api_vector \
- _ (msg_names) \
- _ (msg_handlers) \
- _ (msg_cleanup_handlers) \
- _ (msg_endian_handlers) \
- _ (msg_print_handlers) \
- _ (msg_print_json_handlers) \
- _ (msg_tojson_handlers) \
- _ (msg_fromjson_handlers) \
- _ (api_trace_cfg) \
- _ (message_bounce) \
- _ (is_mp_safe) \
- _ (is_autoendian)
-
void
vl_msg_api_config (vl_msg_api_msg_config_t * c)
{
api_main_t *am = vlibapi_get_main ();
+ vl_api_msg_data_t *m;
/*
* This happens during the java core tests if the message
@@ -909,31 +746,29 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c)
return;
}
-#define _(a) vec_validate (am->a, c->id);
- foreach_msg_api_vector;
-#undef _
-
- if (am->msg_handlers[c->id] && am->msg_handlers[c->id] != c->handler)
- clib_warning
- ("BUG: re-registering 'vl_api_%s_t_handler'."
- "Handler was %llx, replaced by %llx",
- c->name, am->msg_handlers[c->id], c->handler);
-
- am->msg_names[c->id] = c->name;
- am->msg_handlers[c->id] = c->handler;
- am->msg_cleanup_handlers[c->id] = c->cleanup;
- am->msg_endian_handlers[c->id] = c->endian;
- am->msg_print_handlers[c->id] = c->print;
- am->msg_print_json_handlers[c->id] = c->print_json;
- am->msg_tojson_handlers[c->id] = c->tojson;
- am->msg_fromjson_handlers[c->id] = c->fromjson;
- am->message_bounce[c->id] = c->message_bounce;
- am->is_mp_safe[c->id] = c->is_mp_safe;
- am->is_autoendian[c->id] = c->is_autoendian;
-
- am->api_trace_cfg[c->id].size = c->size;
- am->api_trace_cfg[c->id].trace_enable = c->traced;
- am->api_trace_cfg[c->id].replay_enable = c->replay;
+ vec_validate (am->msg_data, c->id);
+ m = vl_api_get_msg_data (am, c->id);
+
+ if (m->handler && m->handler != c->handler)
+ clib_warning ("BUG: re-registering 'vl_api_%s_t_handler'."
+ "Handler was %llx, replaced by %llx",
+ c->name, m->handler, c->handler);
+
+ m->name = c->name;
+ m->handler = c->handler;
+ m->cleanup_handler = c->cleanup;
+ m->endian_handler = c->endian;
+ m->format_fn = c->format_fn;
+ m->tojson_handler = c->tojson;
+ m->fromjson_handler = c->fromjson;
+ m->calc_size_func = c->calc_size;
+ m->bounce = c->message_bounce;
+ m->is_mp_safe = c->is_mp_safe;
+ m->is_autoendian = c->is_autoendian;
+
+ m->trace_size = c->size;
+ m->trace_enable = c->traced;
+ m->replay_allowed = c->replay;
if (!am->msg_id_by_name)
am->msg_id_by_name = hash_create_string (0, sizeof (uword));
@@ -941,37 +776,6 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c)
hash_set_mem (am->msg_id_by_name, c->name, c->id);
}
-/*
- * vl_msg_api_set_handlers
- * preserve the old API for a while
- */
-void
-vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
- void *endian, void *print, int size, int traced,
- void *print_json, void *tojson, void *fromjson)
-{
- vl_msg_api_msg_config_t cfg;
- vl_msg_api_msg_config_t *c = &cfg;
-
- clib_memset (c, 0, sizeof (*c));
-
- c->id = id;
- c->name = name;
- c->handler = handler;
- c->cleanup = cleanup;
- c->endian = endian;
- c->print = print;
- c->traced = traced;
- c->replay = 1;
- c->message_bounce = 0;
- c->is_mp_safe = 0;
- c->is_autoendian = 0;
- c->tojson = tojson;
- c->fromjson = fromjson;
- c->print_json = print_json;
- vl_msg_api_config (c);
-}
-
void
vl_msg_api_clean_handlers (int msg_id)
{
@@ -988,10 +792,10 @@ void
vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
{
api_main_t *am = vlibapi_get_main ();
+ vl_api_msg_data_t *m = vl_api_get_msg_data (am, msg_id);
ASSERT (msg_id > 0);
- vec_validate (am->msg_cleanup_handlers, msg_id);
- am->msg_cleanup_handlers[msg_id] = fp;
+ m->cleanup_handler = fp;
}
void
@@ -999,8 +803,12 @@ vl_msg_api_queue_handler (svm_queue_t * q)
{
uword msg;
- while (!svm_queue_sub (q, (u8 *) & msg, SVM_Q_WAIT, 0))
- vl_msg_api_handler ((void *) msg);
+ while (!svm_queue_sub (q, (u8 *) &msg, SVM_Q_WAIT, 0))
+ {
+ VL_MSG_API_UNPOISON ((u8 *) msg);
+ msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) msg - offsetof (msgbuf_t, data));
+ vl_msg_api_handler ((void *) msg, ntohl (msgbuf->data_len));
+ }
}
u32
@@ -1032,12 +840,6 @@ vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
}
}
-void
-vl_noop_handler (void *mp)
-{
-}
-
-
static u8 post_mortem_dump_enabled;
void
@@ -1250,8 +1052,9 @@ vl_api_from_api_to_new_vec (void *mp, vl_api_string_t * astr)
u8 *v = 0;
if (vl_msg_api_max_length (mp) < clib_net_to_host_u32 (astr->length))
- return format (0, "insane astr->length %u%c",
- clib_net_to_host_u32 (astr->length), 0);
+ return format (0, "Invalid astr->length %u > max (%u)%c",
+ clib_net_to_host_u32 (astr->length),
+ vl_msg_api_max_length (mp), 0);
vec_add (v, astr->buf, clib_net_to_host_u32 (astr->length));
return v;
}
diff --git a/src/vlibapi/memory_shared.c b/src/vlibapi/memory_shared.c
new file mode 100644
index 00000000000..efa45e1f5b5
--- /dev/null
+++ b/src/vlibapi/memory_shared.c
@@ -0,0 +1,815 @@
+/*
+ *------------------------------------------------------------------
+ * memclnt_shared.c - API message handling, common code for both clients
+ * and the vlib process itself.
+ *
+ *
+ * Copyright (c) 2009 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 <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <vppinfra/format.h>
+#include <vppinfra/byte_order.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+#include <svm/queue.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vlibmemory/memory_api.h>
+#include <vlibmemory/vl_memory_msg_enum.h>
+#include <vlibapi/api_common.h>
+
+#define vl_typedefs
+#include <vlibmemory/vl_memory_api_h.h>
+#undef vl_typedefs
+
+#define DEBUG_MESSAGE_BUFFER_OVERRUN 0
+
+__clib_nosanitize_addr static inline void *
+vl_msg_api_alloc_internal (svm_region_t *vlib_rp, int nbytes, int pool,
+ int may_return_null)
+{
+ int i;
+ msgbuf_t *rv;
+ ring_alloc_t *ap;
+ svm_queue_t *q;
+ void *oldheap;
+ vl_shmem_hdr_t *shmem_hdr;
+ api_main_t *am = vlibapi_get_main ();
+
+ shmem_hdr = (void *) vlib_rp->user_ctx;
+
+#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
+ nbytes += 4;
+#endif
+
+ ASSERT (pool == 0 || vlib_get_thread_index () == 0);
+
+ if (shmem_hdr == 0)
+ {
+ clib_warning ("shared memory header NULL");
+ return 0;
+ }
+
+ /* account for the msgbuf_t header */
+ nbytes += sizeof (msgbuf_t);
+
+ if (shmem_hdr->vl_rings == 0)
+ {
+ clib_warning ("vl_rings NULL");
+ ASSERT (0);
+ abort ();
+ }
+
+ if (shmem_hdr->client_rings == 0)
+ {
+ clib_warning ("client_rings NULL");
+ ASSERT (0);
+ abort ();
+ }
+
+ ap = pool ? shmem_hdr->vl_rings : shmem_hdr->client_rings;
+ for (i = 0; i < vec_len (ap); i++)
+ {
+ /* Too big? */
+ if (nbytes > ap[i].size)
+ {
+ continue;
+ }
+
+ q = ap[i].rp;
+ if (pool == 0)
+ {
+ pthread_mutex_lock (&q->mutex);
+ }
+ rv = (msgbuf_t *) (&q->data[0] + q->head * q->elsize);
+ /*
+ * Is this item still in use?
+ */
+ if (rv->q)
+ {
+ u32 now = (u32) time (0);
+
+ if (PREDICT_TRUE (rv->gc_mark_timestamp == 0))
+ rv->gc_mark_timestamp = now;
+ else
+ {
+ if (now - rv->gc_mark_timestamp > 10)
+ {
+ if (CLIB_DEBUG > 0)
+ {
+ u16 *msg_idp, msg_id;
+ vl_api_msg_data_t *m;
+ clib_warning
+ ("garbage collect pool %d ring %d index %d", pool, i,
+ q->head);
+ msg_idp = (u16 *) (rv->data);
+ msg_id = clib_net_to_host_u16 (*msg_idp);
+ m = vl_api_get_msg_data (am, msg_id);
+ if (m)
+ clib_warning ("msg id %d name %s", (u32) msg_id,
+ m->name);
+ }
+ shmem_hdr->garbage_collects++;
+ goto collected;
+ }
+ }
+
+
+ /* yes, loser; try next larger pool */
+ ap[i].misses++;
+ if (pool == 0)
+ pthread_mutex_unlock (&q->mutex);
+ continue;
+ }
+ collected:
+
+ /* OK, we have a winner */
+ ap[i].hits++;
+ /*
+ * Remember the source queue, although we
+ * don't need to know the queue to free the item.
+ */
+ rv->q = q;
+ rv->gc_mark_timestamp = 0;
+ q->head++;
+ if (q->head == q->maxsize)
+ q->head = 0;
+
+ if (pool == 0)
+ pthread_mutex_unlock (&q->mutex);
+ goto out;
+ }
+
+ /*
+ * Request too big, or head element of all size-compatible rings
+ * still in use. Fall back to shared-memory malloc.
+ */
+ am->ring_misses++;
+
+ oldheap = vl_msg_push_heap_w_region (vlib_rp);
+ if (may_return_null)
+ {
+ rv = clib_mem_alloc_or_null (nbytes);
+ if (PREDICT_FALSE (rv == 0))
+ {
+ vl_msg_pop_heap_w_region (vlib_rp, oldheap);
+ return 0;
+ }
+ }
+ else
+ rv = clib_mem_alloc (nbytes);
+
+ rv->q = 0;
+ rv->gc_mark_timestamp = 0;
+ vl_msg_pop_heap_w_region (vlib_rp, oldheap);
+
+out:
+#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
+ {
+ nbytes -= 4;
+ u32 *overrun;
+ overrun = (u32 *) (rv->data + nbytes - sizeof (msgbuf_t));
+ *overrun = 0x1badbabe;
+ }
+#endif
+ rv->data_len = htonl (nbytes - sizeof (msgbuf_t));
+
+ VL_MSG_API_UNPOISON (rv->data);
+ return (rv->data);
+}
+
+void *
+vl_msg_api_alloc (int nbytes)
+{
+ int pool;
+ api_main_t *am = vlibapi_get_main ();
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+
+ /*
+ * Clients use pool-0, vlib proc uses pool 1
+ */
+ pool = (am->our_pid == shmem_hdr->vl_pid);
+ return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, pool,
+ 0 /* may_return_null */ );
+}
+
+void *
+vl_msg_api_alloc_zero (int nbytes)
+{
+ void *ret;
+
+ ret = vl_msg_api_alloc (nbytes);
+ clib_memset (ret, 0, nbytes);
+ return ret;
+}
+
+void *
+vl_msg_api_alloc_or_null (int nbytes)
+{
+ int pool;
+ api_main_t *am = vlibapi_get_main ();
+ vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+
+ pool = (am->our_pid == shmem_hdr->vl_pid);
+ return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, pool,
+ 1 /* may_return_null */ );
+}
+
+void *
+vl_msg_api_alloc_as_if_client (int nbytes)
+{
+ api_main_t *am = vlibapi_get_main ();
+ return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, 0,
+ 0 /* may_return_null */ );
+}
+
+void *
+vl_msg_api_alloc_zero_as_if_client (int nbytes)
+{
+ void *ret;
+
+ ret = vl_msg_api_alloc_as_if_client (nbytes);
+ clib_memset (ret, 0, nbytes);
+ return ret;
+}
+
+void *
+vl_msg_api_alloc_as_if_client_or_null (int nbytes)
+{
+ api_main_t *am = vlibapi_get_main ();
+ return vl_msg_api_alloc_internal (am->vlib_rp, nbytes, 0,
+ 1 /* may_return_null */ );
+}
+
+void *
+vl_mem_api_alloc_as_if_client_w_reg (vl_api_registration_t * reg, int nbytes)
+{
+ return vl_msg_api_alloc_internal (reg->vlib_rp, nbytes, 0,
+ 0 /* may_return_null */ );
+}
+
+void
+vl_msg_api_free_w_region (svm_region_t * vlib_rp, void *a)
+{
+ msgbuf_t *rv;
+ void *oldheap;
+
+ rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
+
+ /*
+ * Here's the beauty of the scheme. Only one proc/thread has
+ * control of a given message buffer. To free a buffer, we just clear the
+ * queue field, and leave. No locks, no hits, no errors...
+ */
+ if (rv->q)
+ {
+ rv->q = 0;
+ rv->gc_mark_timestamp = 0;
+#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
+ {
+ u32 *overrun;
+ overrun = (u32 *) (rv->data + ntohl (rv->data_len));
+ ASSERT (*overrun == 0x1badbabe);
+ }
+#endif
+ VL_MSG_API_POISON (rv->data);
+ return;
+ }
+
+ oldheap = vl_msg_push_heap_w_region (vlib_rp);
+
+#if DEBUG_MESSAGE_BUFFER_OVERRUN > 0
+ {
+ u32 *overrun;
+ overrun = (u32 *) (rv->data + ntohl (rv->data_len));
+ ASSERT (*overrun == 0x1badbabe);
+ }
+#endif
+
+ clib_mem_free (rv);
+ vl_msg_pop_heap_w_region (vlib_rp, oldheap);
+}
+
+void
+vl_msg_api_free (void *a)
+{
+ api_main_t *am = vlibapi_get_main ();
+ vl_msg_api_free_w_region (am->vlib_rp, a);
+}
+
+static void
+vl_msg_api_free_nolock (void *a)
+{
+ msgbuf_t *rv;
+ void *oldheap;
+ api_main_t *am = vlibapi_get_main ();
+
+ rv = (msgbuf_t *) (((u8 *) a) - offsetof (msgbuf_t, data));
+ /*
+ * Here's the beauty of the scheme. Only one proc/thread has
+ * control of a given message buffer. To free a buffer, we just clear the
+ * queue field, and leave. No locks, no hits, no errors...
+ */
+ if (rv->q)
+ {
+ rv->q = 0;
+ VL_MSG_API_POISON (rv->data);
+ return;
+ }
+
+ oldheap = svm_push_data_heap (am->vlib_rp);
+ clib_mem_free (rv);
+ svm_pop_heap (oldheap);
+}
+
+void
+vl_set_memory_root_path (const char *name)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->root_path = name;
+}
+
+void
+vl_set_memory_uid (int uid)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->api_uid = uid;
+}
+
+void
+vl_set_memory_gid (int gid)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->api_gid = gid;
+}
+
+void
+vl_set_global_memory_baseva (u64 baseva)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->global_baseva = baseva;
+}
+
+void
+vl_set_global_memory_size (u64 size)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->global_size = size;
+}
+
+void
+vl_set_api_memory_size (u64 size)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->api_size = size;
+}
+
+void
+vl_set_global_pvt_heap_size (u64 size)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->global_pvt_heap_size = size;
+}
+
+void
+vl_set_api_pvt_heap_size (u64 size)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ am->api_pvt_heap_size = size;
+}
+
+static void
+vl_api_default_mem_config (vl_shmem_hdr_t * shmem_hdr)
+{
+ api_main_t *am = vlibapi_get_main ();
+ u32 vlib_input_queue_length;
+
+ /* vlib main input queue */
+ vlib_input_queue_length = 1024;
+ if (am->vlib_input_queue_length)
+ vlib_input_queue_length = am->vlib_input_queue_length;
+
+ shmem_hdr->vl_input_queue =
+ svm_queue_alloc_and_init (vlib_input_queue_length, sizeof (uword),
+ getpid ());
+
+#define _(sz,n) \
+ do { \
+ ring_alloc_t _rp; \
+ _rp.rp = svm_queue_alloc_and_init ((n), (sz), 0); \
+ _rp.size = (sz); \
+ _rp.nitems = n; \
+ _rp.hits = 0; \
+ _rp.misses = 0; \
+ vec_add1(shmem_hdr->vl_rings, _rp); \
+ } while (0);
+
+ foreach_vl_aring_size;
+#undef _
+
+#define _(sz,n) \
+ do { \
+ ring_alloc_t _rp; \
+ _rp.rp = svm_queue_alloc_and_init ((n), (sz), 0); \
+ _rp.size = (sz); \
+ _rp.nitems = n; \
+ _rp.hits = 0; \
+ _rp.misses = 0; \
+ vec_add1(shmem_hdr->client_rings, _rp); \
+ } while (0);
+
+ foreach_clnt_aring_size;
+#undef _
+}
+
+void
+vl_api_mem_config (vl_shmem_hdr_t * hdr, vl_api_shm_elem_config_t * config)
+{
+ vl_api_shm_elem_config_t *c;
+ ring_alloc_t *rp;
+ u32 size;
+
+ if (!config)
+ {
+ vl_api_default_mem_config (hdr);
+ return;
+ }
+
+ vec_foreach (c, config)
+ {
+ switch (c->type)
+ {
+ case VL_API_QUEUE:
+ hdr->vl_input_queue = svm_queue_alloc_and_init (c->count, c->size,
+ getpid ());
+ continue;
+ case VL_API_VLIB_RING:
+ vec_add2 (hdr->vl_rings, rp, 1);
+ break;
+ case VL_API_CLIENT_RING:
+ vec_add2 (hdr->client_rings, rp, 1);
+ break;
+ default:
+ clib_warning ("unknown config type: %d", c->type);
+ continue;
+ }
+
+ size = sizeof (ring_alloc_t) + c->size;
+ rp->rp = svm_queue_alloc_and_init (c->count, size, 0);
+ rp->size = size;
+ rp->nitems = c->count;
+ rp->hits = 0;
+ rp->misses = 0;
+ }
+}
+
+void
+vl_init_shmem (svm_region_t * vlib_rp, vl_api_shm_elem_config_t * config,
+ int is_vlib, int is_private_region)
+{
+ api_main_t *am = vlibapi_get_main ();
+ vl_shmem_hdr_t *shmem_hdr = 0;
+ void *oldheap;
+ ASSERT (vlib_rp);
+
+ /* $$$$ need private region config parameters */
+
+ oldheap = svm_push_data_heap (vlib_rp);
+
+ vec_validate (shmem_hdr, 0);
+ shmem_hdr->version = VL_SHM_VERSION;
+ shmem_hdr->clib_file_index = VL_API_INVALID_FI;
+
+ /* Set up the queue and msg ring allocator */
+ vl_api_mem_config (shmem_hdr, config);
+
+ if (is_private_region == 0)
+ {
+ am->shmem_hdr = shmem_hdr;
+ am->vlib_rp = vlib_rp;
+ am->our_pid = getpid ();
+ if (is_vlib)
+ am->shmem_hdr->vl_pid = am->our_pid;
+ }
+ else
+ shmem_hdr->vl_pid = am->our_pid;
+
+ svm_pop_heap (oldheap);
+
+ /*
+ * After absolutely everything that a client might see is set up,
+ * declare the shmem region valid
+ */
+ vlib_rp->user_ctx = shmem_hdr;
+
+ pthread_mutex_unlock (&vlib_rp->mutex);
+}
+
+int
+vl_map_shmem (const char *region_name, int is_vlib)
+{
+ svm_map_region_args_t _a, *a = &_a;
+ svm_region_t *vlib_rp, *root_rp;
+ api_main_t *am = vlibapi_get_main ();
+ int i;
+ struct timespec ts, tsrem;
+ char *vpe_api_region_suffix = "-vpe-api";
+
+ clib_memset (a, 0, sizeof (*a));
+
+ if (strstr (region_name, vpe_api_region_suffix))
+ {
+ u8 *root_path = format (0, "%s", region_name);
+ vec_set_len (root_path,
+ vec_len (root_path) - strlen (vpe_api_region_suffix));
+ vec_terminate_c_string (root_path);
+ a->root_path = (const char *) root_path;
+ am->root_path = (const char *) root_path;
+ }
+
+ if (is_vlib == 0)
+ {
+ int tfd;
+ u8 *api_name;
+ /*
+ * Clients wait for vpp to set up the root / API regioins
+ */
+ if (am->root_path)
+ api_name = format (0, "/dev/shm/%s-%s%c", am->root_path,
+ region_name + 1, 0);
+ else
+ api_name = format (0, "/dev/shm%s%c", region_name, 0);
+
+ /* Wait up to 100 seconds... */
+ for (i = 0; i < 10000; i++)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 10000 * 1000; /* 10 ms */
+ while (nanosleep (&ts, &tsrem) < 0)
+ ts = tsrem;
+ tfd = open ((char *) api_name, O_RDWR);
+ if (tfd >= 0)
+ break;
+ }
+ vec_free (api_name);
+ if (tfd < 0)
+ {
+ clib_warning ("region init fail");
+ return -2;
+ }
+ close (tfd);
+ svm_region_init_chroot_uid_gid (am->root_path, getuid (), getgid ());
+ }
+
+ if (a->root_path != NULL)
+ {
+ a->name = "/vpe-api";
+ }
+ else
+ a->name = region_name;
+ a->size = am->api_size ? am->api_size : (16 << 20);
+ a->flags = SVM_FLAGS_MHEAP;
+ a->uid = am->api_uid;
+ a->gid = am->api_gid;
+ a->pvt_heap_size = am->api_pvt_heap_size;
+
+ vlib_rp = svm_region_find_or_create (a);
+
+ if (vlib_rp == 0)
+ return (-2);
+
+ pthread_mutex_lock (&vlib_rp->mutex);
+ /* Has someone else set up the shared-memory variable table? */
+ if (vlib_rp->user_ctx)
+ {
+ am->shmem_hdr = (void *) vlib_rp->user_ctx;
+ am->our_pid = getpid ();
+ if (is_vlib)
+ {
+ svm_queue_t *q;
+ uword old_msg;
+ /*
+ * application restart. Reset cached pids, API message
+ * rings, list of clients; otherwise, various things
+ * fail. (e.g. queue non-empty notification)
+ */
+
+ /* ghosts keep the region from disappearing properly */
+ svm_client_scan_this_region_nolock (vlib_rp);
+ am->shmem_hdr->application_restarts++;
+ q = am->shmem_hdr->vl_input_queue;
+ am->shmem_hdr->vl_pid = getpid ();
+ q->consumer_pid = am->shmem_hdr->vl_pid;
+ /* Drain the input queue, freeing msgs */
+ for (i = 0; i < 10; i++)
+ {
+ if (pthread_mutex_trylock (&q->mutex) == 0)
+ {
+ pthread_mutex_unlock (&q->mutex);
+ goto mutex_ok;
+ }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 10000 * 1000; /* 10 ms */
+ while (nanosleep (&ts, &tsrem) < 0)
+ ts = tsrem;
+ }
+ /* Mutex buggered, "fix" it */
+ clib_memset (&q->mutex, 0, sizeof (q->mutex));
+ clib_warning ("forcibly release main input queue mutex");
+
+ mutex_ok:
+ am->vlib_rp = vlib_rp;
+ while (svm_queue_sub (q, (u8 *) & old_msg, SVM_Q_NOWAIT, 0)
+ != -2 /* queue underflow */ )
+ {
+ vl_msg_api_free_nolock ((void *) old_msg);
+ am->shmem_hdr->restart_reclaims++;
+ }
+ pthread_mutex_unlock (&vlib_rp->mutex);
+ root_rp = svm_get_root_rp ();
+ ASSERT (root_rp);
+ /* Clean up the root region client list */
+ pthread_mutex_lock (&root_rp->mutex);
+ svm_client_scan_this_region_nolock (root_rp);
+ pthread_mutex_unlock (&root_rp->mutex);
+ }
+ else
+ {
+ pthread_mutex_unlock (&vlib_rp->mutex);
+ }
+ am->vlib_rp = vlib_rp;
+ vec_add1 (am->mapped_shmem_regions, vlib_rp);
+ return 0;
+ }
+ /* Clients simply have to wait... */
+ if (!is_vlib)
+ {
+ pthread_mutex_unlock (&vlib_rp->mutex);
+
+ /* Wait up to 100 seconds... */
+ for (i = 0; i < 10000; i++)
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 10000 * 1000; /* 10 ms */
+ while (nanosleep (&ts, &tsrem) < 0)
+ ts = tsrem;
+ if (vlib_rp->user_ctx)
+ goto ready;
+ }
+ /* Clean up and leave... */
+ svm_region_unmap (vlib_rp);
+ clib_warning ("region init fail");
+ return (-2);
+
+ ready:
+ am->shmem_hdr = (void *) vlib_rp->user_ctx;
+ am->our_pid = getpid ();
+ am->vlib_rp = vlib_rp;
+ vec_add1 (am->mapped_shmem_regions, vlib_rp);
+ return 0;
+ }
+
+ /* Nope, it's our problem... */
+ vl_init_shmem (vlib_rp, 0 /* default config */ , 1 /* is vlib */ ,
+ 0 /* is_private_region */ );
+
+ vec_add1 (am->mapped_shmem_regions, vlib_rp);
+ return 0;
+}
+
+void
+vl_register_mapped_shmem_region (svm_region_t * rp)
+{
+ api_main_t *am = vlibapi_get_main ();
+
+ vec_add1 (am->mapped_shmem_regions, rp);
+}
+
+static void
+vl_unmap_shmem_internal (u8 is_client)
+{
+ svm_region_t *rp;
+ int i;
+ api_main_t *am = vlibapi_get_main ();
+
+ if (!svm_get_root_rp ())
+ return;
+
+ for (i = 0; i < vec_len (am->mapped_shmem_regions); i++)
+ {
+ rp = am->mapped_shmem_regions[i];
+ is_client ? svm_region_unmap_client (rp) : svm_region_unmap (rp);
+ }
+
+ vec_free (am->mapped_shmem_regions);
+ am->shmem_hdr = 0;
+
+ is_client ? svm_region_exit_client () : svm_region_exit ();
+
+ vec_free (am->msg_data);
+}
+
+void
+vl_unmap_shmem (void)
+{
+ vl_unmap_shmem_internal (0);
+}
+
+void
+vl_unmap_shmem_client (void)
+{
+ vl_unmap_shmem_internal (1);
+}
+
+void
+vl_msg_api_send_shmem (svm_queue_t * q, u8 * elem)
+{
+ api_main_t *am = vlibapi_get_main ();
+ void *msg = (void *) *(uword *) elem;
+
+ if (am->tx_trace && am->tx_trace->enabled)
+ vl_msg_api_trace (am, am->tx_trace, msg);
+
+ /*
+ * Announce a probable binary API client bug:
+ * some client's input queue is stuffed.
+ * The situation may be recoverable, or not.
+ */
+ if (PREDICT_FALSE
+ (am->vl_clients /* vpp side */ && (q->cursize == q->maxsize)))
+ {
+ if (PREDICT_FALSE (am->elog_trace_api_messages))
+ {
+ ELOG_TYPE_DECLARE (e) =
+ {
+ .format = "api-client-queue-stuffed: %x%x",
+ .format_args = "i4i4",
+ };
+ struct
+ {
+ u32 hi, low;
+ } *ed;
+ ed = ELOG_DATA (am->elog_main, e);
+ ed->hi = (uword) q >> 32;
+ ed->low = (uword) q & 0xFFFFFFFF;
+ clib_warning ("WARNING: client input queue at %llx is stuffed...",
+ q);
+ }
+ }
+ VL_MSG_API_POISON (msg);
+ (void) svm_queue_add (q, elem, 0 /* nowait */ );
+}
+
+int
+vl_mem_api_can_send (svm_queue_t * q)
+{
+ return (q->cursize < q->maxsize);
+}
+
+void
+vl_msg_api_send_shmem_nolock (svm_queue_t * q, u8 * elem)
+{
+ api_main_t *am = vlibapi_get_main ();
+ void *msg = (void *) *(uword *) elem;
+
+ if (am->tx_trace && am->tx_trace->enabled)
+ vl_msg_api_trace (am, am->tx_trace, msg);
+
+ (void) svm_queue_add_nolock (q, elem);
+ VL_MSG_API_POISON (msg);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vlibapi/memory_shared.h b/src/vlibapi/memory_shared.h
new file mode 100644
index 00000000000..4c4773d060b
--- /dev/null
+++ b/src/vlibapi/memory_shared.h
@@ -0,0 +1,147 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2018 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 SRC_VLIBMEMORY_MEMORY_SHARED_H_
+#define SRC_VLIBMEMORY_MEMORY_SHARED_H_
+
+#include <vlibapi/api_common.h>
+#include <vppinfra/error.h>
+
+/* Allocated in shared memory */
+
+/*
+ * Ring-allocation scheme for client API messages
+ *
+ * Only one proc/thread has control of a given message buffer.
+ * To free a buffer allocated from one of these rings, we clear
+ * a field in the buffer (header), and leave.
+ *
+ * No locks, no hits, no errors...
+ */
+typedef struct ring_alloc_
+{
+ svm_queue_t *rp;
+ u16 size;
+ u16 nitems;
+ u32 hits;
+ u32 misses;
+} ring_alloc_t;
+
+typedef enum
+{
+ VL_API_VLIB_RING,
+ VL_API_CLIENT_RING,
+ VL_API_QUEUE
+} vl_api_shm_config_type_t;
+
+typedef struct vl_api_shm_elem_config_
+{
+ u8 type;
+ u8 _pad;
+ u16 count;
+ u32 size;
+} vl_api_shm_elem_config_t;
+
+STATIC_ASSERT (sizeof (vl_api_shm_elem_config_t) == 8,
+ "Size must be exactly 8 bytes");
+
+/*
+ * Initializers for the (shared-memory) rings
+ * _(size, n). Note: each msg has space for a header.
+ */
+#define foreach_vl_aring_size \
+_(64+sizeof(ring_alloc_t), 1024) \
+_(256+sizeof(ring_alloc_t), 128) \
+_(1024+sizeof(ring_alloc_t), 64)
+
+#define foreach_clnt_aring_size \
+ _(1024+sizeof(ring_alloc_t), 1024) \
+ _(2048+sizeof(ring_alloc_t), 128) \
+ _(4096+sizeof(ring_alloc_t), 8)
+
+typedef struct vl_shmem_hdr_
+{
+ int version;
+
+ /* getpid () for the VLIB client process */
+ volatile int vl_pid;
+
+ /* Client sends VLIB msgs here. */
+ svm_queue_t *vl_input_queue;
+
+ /* Vector of rings; one for each size. */
+
+ /* VLIB allocates buffers to send msgs to clients here. */
+ ring_alloc_t *vl_rings;
+
+ /* Clients allocate buffer to send msgs to VLIB here. */
+ ring_alloc_t *client_rings;
+
+ /* Number of detected application restarts */
+ u32 application_restarts;
+
+ /* Number of messages reclaimed during application restart */
+ u32 restart_reclaims;
+
+ /* Number of garbage-collected messages */
+ u32 garbage_collects;
+
+ /* Socket file index used to bootstrap shmem region */
+ u32 clib_file_index;
+} vl_shmem_hdr_t;
+
+#define VL_SHM_VERSION 2
+#define VL_API_EPOCH_MASK 0xFF
+#define VL_API_EPOCH_SHIFT 8
+
+void *vl_msg_api_alloc (int nbytes);
+void *vl_msg_api_alloc_zero (int nbytes);
+void *vl_msg_api_alloc_or_null (int nbytes);
+void *vl_msg_api_alloc_as_if_client (int nbytes);
+void *vl_msg_api_alloc_zero_as_if_client (int nbytes);
+void *vl_msg_api_alloc_as_if_client_or_null (int nbytes);
+void *vl_mem_api_alloc_as_if_client_w_reg (vl_api_registration_t * reg,
+ int nbytes);
+void vl_msg_api_free (void *a);
+void vl_msg_api_free_w_region (svm_region_t * vlib_rp, void *a);
+int vl_map_shmem (const char *region_name, int is_vlib);
+void vl_unmap_shmem (void);
+void vl_unmap_shmem_client (void);
+void vl_register_mapped_shmem_region (svm_region_t * rp);
+void vl_msg_api_send_shmem (svm_queue_t * q, u8 * elem);
+int vl_mem_api_can_send (svm_queue_t * q);
+void vl_set_memory_region_name (const char *name);
+void vl_set_memory_root_path (const char *root_path);
+void vl_set_memory_uid (int uid);
+void vl_set_memory_gid (int gid);
+void vl_set_global_memory_baseva (u64 baseva);
+void vl_set_global_memory_size (u64 size);
+void vl_set_api_memory_size (u64 size);
+void vl_set_global_pvt_heap_size (u64 size);
+void vl_set_api_pvt_heap_size (u64 size);
+void vl_init_shmem (svm_region_t * vlib_rp, vl_api_shm_elem_config_t * config,
+ int is_vlib, int is_private_region);
+
+#endif /* SRC_VLIBMEMORY_MEMORY_SHARED_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vlibapi/node_serialize.c b/src/vlibapi/node_serialize.c
index b50d79e2922..09b59247eab 100644
--- a/src/vlibapi/node_serialize.c
+++ b/src/vlibapi/node_serialize.c
@@ -176,7 +176,7 @@ vlib_node_unserialize (u8 * vector)
nstat_vms = unserialize_likely_small_unsigned_integer (sm);
vec_validate (nodes_by_thread, nstat_vms - 1);
- _vec_len (nodes_by_thread) = 0;
+ vec_set_len (nodes_by_thread, 0);
for (i = 0; i < nstat_vms; i++)
{
@@ -326,13 +326,11 @@ test_node_serialize_command_fn (vlib_main_t * vm,
return 0;
}
-/* *INDENT-OFF* */
VLIB_CLI_COMMAND (test_node_serialize_node, static) = {
.path = "test node serialize",
.short_help = "test node serialize [max-threads NN] nexts stats",
.function = test_node_serialize_command_fn,
};
-/* *INDENT-ON* */
#endif
/*