aboutsummaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorMatias Elo <matias.elo@nokia.com>2022-06-29 16:36:22 +0300
committerMatias Elo <matias.elo@nokia.com>2023-01-18 10:12:09 +0200
commita735a7131bceadb87c25b553446e4829923bcc1c (patch)
tree06fb66a46a0d1b1251bbfe96ac7c43887a546011 /platform
parent8782c99a6cb53af57316e66271e0a1c6b951fa2b (diff)
linux-gen: event: add event validation support
Add support for runtime event validation (initially buffer endmark checking). Event validation can be enabled during configure with '--enable-event-validation' [warn/abort] or with --enabled-debug=full. When event validation is enabled, endmarks are checked in: - odp_buffer_free() / odp_buffer_free_multi() - odp_buffer_is_valid() - odp_event_free() / odp_event_free_multi() / odp_event_free_sp() - odp_event_is_valid() - odp_packet_free() / odp_packet_free_multi() / odp_packet_free_sp() - odp_packet_is_valid() Signed-off-by: Matias Elo <matias.elo@nokia.com> Reviewed-by: Tuomas Taipale <tuomas.taipale@nokia.com>
Diffstat (limited to 'platform')
-rw-r--r--platform/linux-generic/Makefile.am3
-rw-r--r--platform/linux-generic/include/odp/api/plat/event_validation_external.h93
-rw-r--r--platform/linux-generic/include/odp/api/plat/packet_inlines.h3
-rw-r--r--platform/linux-generic/include/odp/api/plat/pool_inline_types.h1
-rw-r--r--platform/linux-generic/include/odp_event_internal.h7
-rw-r--r--platform/linux-generic/include/odp_event_validation_internal.h52
-rw-r--r--platform/linux-generic/include/odp_init_internal.h3
-rw-r--r--platform/linux-generic/include/odp_pool_internal.h1
-rw-r--r--platform/linux-generic/m4/configure.m43
-rw-r--r--platform/linux-generic/m4/odp_event_validation.m423
-rw-r--r--platform/linux-generic/odp_event.c25
-rw-r--r--platform/linux-generic/odp_event_validation.c234
-rw-r--r--platform/linux-generic/odp_init.c16
-rw-r--r--platform/linux-generic/odp_packet.c20
-rw-r--r--platform/linux-generic/odp_pool.c31
15 files changed, 494 insertions, 21 deletions
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 7d312d0b7..43fcfa950 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -38,6 +38,7 @@ odpapiplatinclude_HEADERS = \
include/odp/api/plat/debug_inlines.h \
include/odp/api/plat/event_inlines.h \
include/odp/api/plat/event_inline_types.h \
+ include/odp/api/plat/event_validation_external.h \
include/odp/api/plat/event_vector_inline_types.h \
include/odp/api/plat/hash_inlines.h \
include/odp/api/plat/ipsec_inlines.h \
@@ -131,6 +132,7 @@ noinst_HEADERS = \
include/odp_debug_internal.h \
include/odp_errno_define.h \
include/odp_event_internal.h \
+ include/odp_event_validation_internal.h \
include/odp_fdserver_internal.h \
include/odp_forward_typedefs_internal.h \
include/odp_global_data.h \
@@ -207,6 +209,7 @@ __LIB__libodp_linux_la_SOURCES = \
odp_dma.c \
odp_errno.c \
odp_event.c \
+ odp_event_validation.c \
odp_fdserver.c \
odp_hash_crc_gen.c \
odp_impl.c \
diff --git a/platform/linux-generic/include/odp/api/plat/event_validation_external.h b/platform/linux-generic/include/odp/api/plat/event_validation_external.h
new file mode 100644
index 000000000..2d6c8613a
--- /dev/null
+++ b/platform/linux-generic/include/odp/api/plat/event_validation_external.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2023, Nokia
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * ODP event validation
+ *
+ * @warning These definitions are not part of ODP API, they are for
+ * implementation internal use only.
+ */
+
+#ifndef ODP_EVENT_VALIDATION_EXTERNAL_H_
+#define ODP_EVENT_VALIDATION_EXTERNAL_H_
+
+#include <odp/autoheader_external.h>
+
+#include <odp/api/buffer.h>
+#include <odp/api/event_types.h>
+#include <odp/api/hints.h>
+#include <odp/api/packet_types.h>
+
+/** @cond _ODP_HIDE_FROM_DOXYGEN_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Enumerations for identifying ODP API functions */
+typedef enum {
+ _ODP_EV_BUFFER_FREE = 0,
+ _ODP_EV_BUFFER_FREE_MULTI,
+ _ODP_EV_BUFFER_IS_VALID,
+ _ODP_EV_EVENT_FREE,
+ _ODP_EV_EVENT_FREE_MULTI,
+ _ODP_EV_EVENT_FREE_SP,
+ _ODP_EV_EVENT_IS_VALID,
+ _ODP_EV_PACKET_FREE,
+ _ODP_EV_PACKET_FREE_MULTI,
+ _ODP_EV_PACKET_FREE_SP,
+ _ODP_EV_PACKET_IS_VALID,
+ _ODP_EV_MAX
+} _odp_ev_id_t;
+
+/* Implementation internal event validation functions */
+#if _ODP_EVENT_VALIDATION
+
+int _odp_buffer_validate(odp_buffer_t buf, _odp_ev_id_t ev_id);
+
+int _odp_buffer_validate_multi(const odp_buffer_t buf[], int num, _odp_ev_id_t ev_id);
+
+int _odp_packet_validate(odp_packet_t pkt, _odp_ev_id_t ev_id);
+
+int _odp_packet_validate_multi(const odp_packet_t pkt[], int num, _odp_ev_id_t ev_id);
+
+#else
+
+static inline int _odp_buffer_validate(odp_buffer_t buf ODP_UNUSED, _odp_ev_id_t ev_id ODP_UNUSED)
+{
+ return 0;
+}
+
+static inline int _odp_buffer_validate_multi(const odp_buffer_t buf[] ODP_UNUSED,
+ int num ODP_UNUSED,
+ _odp_ev_id_t ev_id ODP_UNUSED)
+{
+ return 0;
+}
+
+static inline int _odp_packet_validate(odp_packet_t pkt ODP_UNUSED, _odp_ev_id_t ev_id ODP_UNUSED)
+{
+ return 0;
+}
+
+static inline int _odp_packet_validate_multi(const odp_packet_t pkt[] ODP_UNUSED,
+ int num ODP_UNUSED,
+ _odp_ev_id_t ev_id ODP_UNUSED)
+{
+ return 0;
+}
+
+#endif /* _ODP_EVENT_VALIDATION */
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @endcond */
+
+#endif
diff --git a/platform/linux-generic/include/odp/api/plat/packet_inlines.h b/platform/linux-generic/include/odp/api/plat/packet_inlines.h
index 01d47d837..93e95e21c 100644
--- a/platform/linux-generic/include/odp/api/plat/packet_inlines.h
+++ b/platform/linux-generic/include/odp/api/plat/packet_inlines.h
@@ -632,7 +632,8 @@ _ODP_INLINE uint32_t odp_packet_buf_size(odp_packet_buf_t pkt_buf)
odp_pool_t pool = _odp_pkt_get(pkt_buf, odp_pool_t, pool);
return _odp_pool_get(pool, uint32_t, ext_pkt_buf_size) -
- _odp_pool_get(pool, uint32_t, ext_head_offset);
+ _odp_pool_get(pool, uint32_t, ext_head_offset) -
+ _odp_pool_get(pool, uint32_t, trailer_size);
}
_ODP_INLINE void *odp_packet_buf_head(odp_packet_buf_t pkt_buf)
diff --git a/platform/linux-generic/include/odp/api/plat/pool_inline_types.h b/platform/linux-generic/include/odp/api/plat/pool_inline_types.h
index 02f59f982..fbff7eda7 100644
--- a/platform/linux-generic/include/odp/api/plat/pool_inline_types.h
+++ b/platform/linux-generic/include/odp/api/plat/pool_inline_types.h
@@ -30,6 +30,7 @@ typedef struct _odp_pool_inline_offset_t {
uint16_t index;
uint16_t seg_len;
uint16_t uarea_size;
+ uint16_t trailer_size;
uint16_t ext_head_offset;
uint16_t ext_pkt_buf_size;
diff --git a/platform/linux-generic/include/odp_event_internal.h b/platform/linux-generic/include/odp_event_internal.h
index 5a29e926e..4bc28d708 100644
--- a/platform/linux-generic/include/odp_event_internal.h
+++ b/platform/linux-generic/include/odp_event_internal.h
@@ -53,7 +53,7 @@ typedef struct _odp_event_hdr_t {
/* --- Mostly read only data --- */
- /* Initial buffer tail pointer */
+ /* Initial buffer tail pointer and endmark location (if enabled) */
uint8_t *buf_end;
/* Combined pool and event index */
@@ -85,6 +85,11 @@ static inline void _odp_event_type_set(odp_event_t event, int ev)
_odp_event_hdr(event)->event_type = ev;
}
+static inline uint64_t *_odp_event_endmark_get_ptr(odp_event_t event)
+{
+ return (uint64_t *)(uintptr_t)_odp_event_hdr(event)->buf_end;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/platform/linux-generic/include/odp_event_validation_internal.h b/platform/linux-generic/include/odp_event_validation_internal.h
new file mode 100644
index 000000000..f4ac16f31
--- /dev/null
+++ b/platform/linux-generic/include/odp_event_validation_internal.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2023, Nokia
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ODP_EVENT_VALIDATION_INTERNAL_H_
+#define ODP_EVENT_VALIDATION_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <odp/autoheader_external.h>
+
+#include <odp/api/event.h>
+#include <odp/api/hints.h>
+
+#include <odp/api/plat/event_validation_external.h>
+
+#include <odp_event_internal.h>
+
+#include <stdint.h>
+
+#if _ODP_EVENT_VALIDATION
+
+#define _ODP_EV_ENDMARK_VAL 0xDEADBEEFDEADBEEF
+#define _ODP_EV_ENDMARK_SIZE (sizeof(uint64_t))
+
+static inline void _odp_event_endmark_set(odp_event_t event)
+{
+ uint64_t *endmark_ptr;
+
+ endmark_ptr = _odp_event_endmark_get_ptr(event);
+ *endmark_ptr = _ODP_EV_ENDMARK_VAL;
+}
+
+#else
+
+#define _ODP_EV_ENDMARK_VAL 0
+#define _ODP_EV_ENDMARK_SIZE 0
+
+static inline void _odp_event_endmark_set(odp_event_t event ODP_UNUSED)
+{
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/platform/linux-generic/include/odp_init_internal.h b/platform/linux-generic/include/odp_init_internal.h
index 2a1039854..24e8346ad 100644
--- a/platform/linux-generic/include/odp_init_internal.h
+++ b/platform/linux-generic/include/odp_init_internal.h
@@ -33,6 +33,9 @@ int _odp_pool_init_local(void);
int _odp_pool_term_global(void);
int _odp_pool_term_local(void);
+int _odp_event_validation_init_global(void);
+int _odp_event_validation_term_global(void);
+
int _odp_queue_init_global(void);
int _odp_queue_term_global(void);
diff --git a/platform/linux-generic/include/odp_pool_internal.h b/platform/linux-generic/include/odp_pool_internal.h
index 1c5b51c3d..c8d2168f3 100644
--- a/platform/linux-generic/include/odp_pool_internal.h
+++ b/platform/linux-generic/include/odp_pool_internal.h
@@ -87,6 +87,7 @@ typedef struct pool_t {
uint32_t block_size;
uint32_t block_offset;
uint32_t num_populated;
+ uint32_t trailer_size;
uint8_t *base_addr;
uint8_t *max_addr;
uint8_t *uarea_base_addr;
diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
index 61d57634f..f018d2b24 100644
--- a/platform/linux-generic/m4/configure.m4
+++ b/platform/linux-generic/m4/configure.m4
@@ -7,6 +7,7 @@ ODP_ATOMIC
ODP_PTHREAD
ODP_TIMER
m4_include([platform/linux-generic/m4/odp_cpu.m4])
+m4_include([platform/linux-generic/m4/odp_event_validation.m4])
m4_include([platform/linux-generic/m4/odp_pcap.m4])
m4_include([platform/linux-generic/m4/odp_scheduler.m4])
@@ -30,6 +31,7 @@ m4_include([platform/linux-generic/m4/odp_pcapng.m4])
m4_include([platform/linux-generic/m4/odp_netmap.m4])
m4_include([platform/linux-generic/m4/odp_dpdk.m4])
m4_include([platform/linux-generic/m4/odp_xdp.m4])
+ODP_EVENT_VALIDATION
ODP_SCHEDULER
AS_VAR_APPEND([PLAT_DEP_LIBS], ["${ATOMIC_LIBS} ${AARCH64CRYPTO_LIBS} ${LIBCONFIG_LIBS} ${OPENSSL_LIBS} ${IPSEC_MB_LIBS} ${DPDK_LIBS_LT} ${LIBCLI_LIBS} ${LIBXDP_LIBS}"])
@@ -37,6 +39,7 @@ AS_VAR_APPEND([PLAT_DEP_LIBS], ["${ATOMIC_LIBS} ${AARCH64CRYPTO_LIBS} ${LIBCONFI
# Add text to the end of configure with platform specific settings.
# Make sure it's aligned same as other lines in configure.ac.
AS_VAR_APPEND([PLAT_CFG_TEXT], ["
+ event_validation: ${enable_event_validation}
openssl: ${with_openssl}
openssl_rand: ${openssl_rand}
crypto: ${with_crypto}
diff --git a/platform/linux-generic/m4/odp_event_validation.m4 b/platform/linux-generic/m4/odp_event_validation.m4
new file mode 100644
index 000000000..08bb8902e
--- /dev/null
+++ b/platform/linux-generic/m4/odp_event_validation.m4
@@ -0,0 +1,23 @@
+# ODP_EVENT_VALIDATION
+# --------------------
+# Select event validation level
+AC_DEFUN([ODP_EVENT_VALIDATION], [dnl
+AC_ARG_ENABLE([event-validation],
+ [AS_HELP_STRING([--enable-event-validation],
+ [enable event validation (warn/abort)
+ [default=disabled] (linux-generic)])],
+ [], [AS_IF([test "x$enable_debug" = "xfull"],
+ [enable_event_validation=yes], [enable_event_validation=no])])
+
+# Default to abort mode if validation is enabled
+AS_IF([test "x$enable_event_validation" = "xyes"],
+ [enable_event_validation="abort"])
+
+validation_level=0
+AS_IF([test "x$enable_event_validation" = "xwarn"], [validation_level=1])
+AS_IF([test "x$enable_event_validation" = "xyes" -o "x$enable_event_validation" = "xabort"],
+ [validation_level=2])
+
+AC_DEFINE_UNQUOTED([_ODP_EVENT_VALIDATION], [$validation_level],
+ [Define to 1 or 2 to enable event validation])
+]) # ODP_EVENT_VALIDATION
diff --git a/platform/linux-generic/odp_event.c b/platform/linux-generic/odp_event.c
index c4e0f2c9d..edf77e2dc 100644
--- a/platform/linux-generic/odp_event.c
+++ b/platform/linux-generic/odp_event.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2015-2018, Linaro Limited
- * Copyright (c) 2020-2022, Nokia
+ * Copyright (c) 2020-2023, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -18,6 +18,7 @@
#include <odp_debug_internal.h>
#include <odp_packet_internal.h>
#include <odp_event_internal.h>
+#include <odp_event_validation_internal.h>
#include <odp_event_vector_internal.h>
/* Inlined API functions */
@@ -41,13 +42,15 @@ _odp_event_inline_offset ODP_ALIGNED_CACHE = {
#include <odp/visibility_end.h>
-void odp_event_free(odp_event_t event)
+static inline void event_free(odp_event_t event, _odp_ev_id_t id)
{
switch (odp_event_type(event)) {
case ODP_EVENT_BUFFER:
+ _odp_buffer_validate(odp_buffer_from_event(event), id);
odp_buffer_free(odp_buffer_from_event(event));
break;
case ODP_EVENT_PACKET:
+ _odp_packet_validate(odp_packet_from_event(event), id);
odp_packet_free(odp_packet_from_event(event));
break;
case ODP_EVENT_PACKET_VECTOR:
@@ -75,17 +78,21 @@ void odp_event_free(odp_event_t event)
}
}
-void odp_event_free_multi(const odp_event_t event[], int num)
+void odp_event_free(odp_event_t event)
{
- int i;
+ event_free(event, _ODP_EV_EVENT_FREE);
+}
- for (i = 0; i < num; i++)
- odp_event_free(event[i]);
+void odp_event_free_multi(const odp_event_t event[], int num)
+{
+ for (int i = 0; i < num; i++)
+ event_free(event[i], _ODP_EV_EVENT_FREE_MULTI);
}
void odp_event_free_sp(const odp_event_t event[], int num)
{
- odp_event_free_multi(event, num);
+ for (int i = 0; i < num; i++)
+ event_free(event[i], _ODP_EV_EVENT_FREE_SP);
}
uint64_t odp_event_to_u64(odp_event_t hdl)
@@ -103,9 +110,9 @@ int odp_event_is_valid(odp_event_t event)
switch (odp_event_type(event)) {
case ODP_EVENT_BUFFER:
- /* Fall through */
+ return !_odp_buffer_validate(odp_buffer_from_event(event), _ODP_EV_EVENT_IS_VALID);
case ODP_EVENT_PACKET:
- /* Fall through */
+ return !_odp_packet_validate(odp_packet_from_event(event), _ODP_EV_EVENT_IS_VALID);
case ODP_EVENT_TIMEOUT:
/* Fall through */
#if ODP_DEPRECATED_API
diff --git a/platform/linux-generic/odp_event_validation.c b/platform/linux-generic/odp_event_validation.c
new file mode 100644
index 000000000..8dd8d7b8e
--- /dev/null
+++ b/platform/linux-generic/odp_event_validation.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 2023, Nokia
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <odp/api/atomic.h>
+#include <odp/api/buffer.h>
+#include <odp/api/debug.h>
+#include <odp/api/event.h>
+#include <odp/api/hints.h>
+#include <odp/api/packet.h>
+#include <odp/api/shared_memory.h>
+
+#include <odp_buffer_internal.h>
+#include <odp_debug_internal.h>
+#include <odp_event_internal.h>
+#include <odp_event_validation_internal.h>
+#include <odp_global_data.h>
+#include <odp_init_internal.h>
+#include <odp_libconfig_internal.h>
+#include <odp_macros_internal.h>
+#include <odp_print_internal.h>
+
+#include <inttypes.h>
+#include <string.h>
+
+#define EVENT_VALIDATION_NONE 0
+#define EVENT_VALIDATION_WARN 1
+#define EVENT_VALIDATION_ABORT 2
+
+#define EVENT_DATA_PRINT_MAX_LEN 128
+
+typedef struct {
+ odp_atomic_u64_t err_count[_ODP_EV_MAX];
+ odp_shm_t shm;
+
+} event_validation_global_t;
+
+typedef struct {
+ const char *str;
+} _odp_ev_info_t;
+
+static event_validation_global_t *_odp_ev_glb;
+
+#if _ODP_EVENT_VALIDATION
+
+/* Table for mapping function IDs to API function names */
+static const _odp_ev_info_t ev_info_tbl[] = {
+ [_ODP_EV_BUFFER_FREE] = {.str = "odp_buffer_free()"},
+ [_ODP_EV_BUFFER_FREE_MULTI] = {.str = "odp_buffer_free_multi()"},
+ [_ODP_EV_BUFFER_IS_VALID] = {.str = "odp_buffer_is_valid()"},
+ [_ODP_EV_EVENT_FREE] = {.str = "odp_event_free()"},
+ [_ODP_EV_EVENT_FREE_MULTI] = {.str = "odp_event_free_multi()"},
+ [_ODP_EV_EVENT_FREE_SP] = {.str = "odp_event_free()_sp"},
+ [_ODP_EV_EVENT_IS_VALID] = {.str = "odp_event_is_valid()"},
+ [_ODP_EV_PACKET_FREE] = {.str = "odp_packet_free()"},
+ [_ODP_EV_PACKET_FREE_MULTI] = {.str = "odp_packet_free_multi()"},
+ [_ODP_EV_PACKET_FREE_SP] = {.str = "odp_packet_free_sp()"},
+ [_ODP_EV_PACKET_IS_VALID] = {.str = "odp_packet_is_valid()"}
+};
+
+ODP_STATIC_ASSERT(_ODP_ARRAY_SIZE(ev_info_tbl) == _ODP_EV_MAX, "ev_info_tbl missing entries");
+
+static void print_event_data(odp_event_t event, odp_event_type_t type)
+{
+ const char *type_str;
+ const uint32_t bytes_per_row = 16;
+ uint32_t byte_len;
+ int num_rows, max_len, n;
+ int len = 0;
+ uint8_t *data;
+
+ if (type == ODP_EVENT_PACKET) {
+ odp_packet_t pkt = odp_packet_from_event(event);
+
+ data = odp_packet_data(pkt);
+ byte_len = odp_packet_seg_len(pkt);
+ type_str = "Packet";
+ } else {
+ odp_buffer_t buf = odp_buffer_from_event(event);
+
+ data = odp_buffer_addr(buf);
+ byte_len = odp_buffer_size(buf);
+ type_str = "Buffer";
+ }
+
+ if (byte_len > EVENT_DATA_PRINT_MAX_LEN)
+ byte_len = EVENT_DATA_PRINT_MAX_LEN;
+
+ num_rows = (byte_len + bytes_per_row - 1) / bytes_per_row;
+ max_len = 256 + (3 * byte_len) + (3 * num_rows);
+ n = max_len - 1;
+
+ char str[max_len];
+
+ len += _odp_snprint(&str[len], n - len, "%s %p data %p:\n", type_str, event, data);
+ while (byte_len) {
+ uint32_t row_len = byte_len > bytes_per_row ? bytes_per_row : byte_len;
+
+ len += _odp_snprint(&str[len], n - len, " ");
+
+ for (uint32_t i = 0; i < row_len; i++)
+ len += _odp_snprint(&str[len], n - len, " %02x", data[i]);
+
+ len += _odp_snprint(&str[len], n - len, "\n");
+
+ byte_len -= row_len;
+ data += row_len;
+ }
+
+ _ODP_PRINT("%s\n", str);
+}
+
+static inline int validate_event_endmark(odp_event_t event, _odp_ev_id_t id, odp_event_type_t type)
+{
+ uint64_t err_count;
+ uint64_t *endmark_ptr = _odp_event_endmark_get_ptr(event);
+
+ if (odp_likely(*endmark_ptr == _ODP_EV_ENDMARK_VAL))
+ return 0;
+
+ err_count = odp_atomic_fetch_inc_u64(&_odp_ev_glb->err_count[id]) + 1;
+
+ _ODP_ERR("Event %p endmark mismatch in %s: endmark=0x%" PRIx64 " (expected 0x%" PRIx64 ") "
+ "err_count=%" PRIu64 "\n", event, ev_info_tbl[id].str, *endmark_ptr,
+ _ODP_EV_ENDMARK_VAL, err_count);
+
+ print_event_data(event, type);
+
+ if (_ODP_EVENT_VALIDATION == EVENT_VALIDATION_ABORT)
+ _ODP_ABORT("Abort due to event %p endmark mismatch\n", event);
+
+ /* Fix endmark value */
+ _odp_event_endmark_set(event);
+
+ return -1;
+}
+
+static inline int buffer_validate(odp_buffer_t buf, _odp_ev_id_t id)
+{
+ return validate_event_endmark(odp_buffer_to_event(buf), id, ODP_EVENT_BUFFER);
+}
+
+static inline int packet_validate(odp_packet_t pkt, _odp_ev_id_t id)
+{
+ return validate_event_endmark(odp_packet_to_event(pkt), id, ODP_EVENT_PACKET);
+}
+
+/* Enable usage from API inline files */
+#include <odp/visibility_begin.h>
+
+int _odp_buffer_validate(odp_buffer_t buf, _odp_ev_id_t id)
+{
+ return buffer_validate(buf, id);
+}
+
+int _odp_buffer_validate_multi(const odp_buffer_t buf[], int num,
+ _odp_ev_id_t id)
+{
+ for (int i = 0; i < num; i++) {
+ if (odp_unlikely(buffer_validate(buf[i], id)))
+ return -1;
+ }
+ return 0;
+}
+
+int _odp_packet_validate(odp_packet_t pkt, _odp_ev_id_t id)
+{
+ return packet_validate(pkt, id);
+}
+
+int _odp_packet_validate_multi(const odp_packet_t pkt[], int num,
+ _odp_ev_id_t id)
+{
+ for (int i = 0; i < num; i++) {
+ if (odp_unlikely(packet_validate(pkt[i], id)))
+ return -1;
+ }
+ return 0;
+}
+
+#include <odp/visibility_end.h>
+
+#endif /* _ODP_EVENT_VALIDATION */
+
+int _odp_event_validation_init_global(void)
+{
+ odp_shm_t shm;
+
+ _ODP_PRINT("\nEvent validation mode: %s\n\n",
+ _ODP_EVENT_VALIDATION == EVENT_VALIDATION_NONE ? "none" :
+ _ODP_EVENT_VALIDATION == EVENT_VALIDATION_WARN ? "warn" : "abort");
+
+ if (_ODP_EVENT_VALIDATION == EVENT_VALIDATION_NONE)
+ return 0;
+
+ shm = odp_shm_reserve("_odp_event_validation_global",
+ sizeof(event_validation_global_t),
+ ODP_CACHE_LINE_SIZE, ODP_SHM_EXPORT);
+ if (shm == ODP_SHM_INVALID)
+ return -1;
+
+ _odp_ev_glb = odp_shm_addr(shm);
+ if (_odp_ev_glb == NULL)
+ return -1;
+
+ memset(_odp_ev_glb, 0, sizeof(event_validation_global_t));
+ _odp_ev_glb->shm = shm;
+
+ for (int i = 0; i < _ODP_EV_MAX; i++)
+ odp_atomic_init_u64(&_odp_ev_glb->err_count[i], 0);
+
+ return 0;
+}
+
+int _odp_event_validation_term_global(void)
+{
+ int ret;
+
+ if (_ODP_EVENT_VALIDATION == EVENT_VALIDATION_NONE)
+ return 0;
+
+ if (_odp_ev_glb == NULL)
+ return 0;
+
+ ret = odp_shm_free(_odp_ev_glb->shm);
+ if (ret) {
+ _ODP_ERR("SHM free failed: %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c
index 284b3e566..bd27641aa 100644
--- a/platform/linux-generic/odp_init.c
+++ b/platform/linux-generic/odp_init.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2013-2018, Linaro Limited
- * Copyright (c) 2021, Nokia
+ * Copyright (c) 2021-2023, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -35,6 +35,7 @@ enum init_stage {
HASH_INIT,
THREAD_INIT,
POOL_INIT,
+ EVENT_VALIDATION_INIT,
STASH_INIT,
QUEUE_INIT,
SCHED_INIT,
@@ -242,6 +243,13 @@ static int term_global(enum init_stage stage)
}
/* Fall through */
+ case EVENT_VALIDATION_INIT:
+ if (_odp_event_validation_term_global()) {
+ _ODP_ERR("ODP event validation term failed.\n");
+ rc = -1;
+ }
+ /* Fall through */
+
case POOL_INIT:
if (_odp_pool_term_global()) {
_ODP_ERR("ODP buffer pool term failed.\n");
@@ -412,6 +420,12 @@ int odp_init_global(odp_instance_t *instance,
}
stage = POOL_INIT;
+ if (_odp_event_validation_init_global()) {
+ _ODP_ERR("ODP event validation init failed.\n");
+ goto init_failed;
+ }
+ stage = EVENT_VALIDATION_INIT;
+
if (_odp_stash_init_global()) {
_ODP_ERR("ODP stash init failed.\n");
goto init_failed;
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 1ce475625..639a74e0c 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2013-2018, Linaro Limited
- * Copyright (c) 2019-2022, Nokia
+ * Copyright (c) 2019-2023, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -21,6 +21,7 @@
#include <odp_debug_internal.h>
#include <odp_errno_define.h>
#include <odp_event_internal.h>
+#include <odp_event_validation_internal.h>
#include <odp_macros_internal.h>
#include <odp_packet_internal.h>
#include <odp_packet_io_internal.h>
@@ -696,6 +697,8 @@ void odp_packet_free(odp_packet_t pkt)
odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt);
int num_seg = pkt_hdr->seg_count;
+ _odp_packet_validate(pkt, _ODP_EV_PACKET_FREE);
+
_ODP_ASSERT(segment_ref(pkt_hdr) > 0);
if (odp_likely(num_seg == 1))
@@ -704,12 +707,14 @@ void odp_packet_free(odp_packet_t pkt)
free_all_segments(pkt_hdr, num_seg);
}
-void odp_packet_free_multi(const odp_packet_t pkt[], int num)
+static inline void packet_free_multi_ev(const odp_packet_t pkt[], int num, _odp_ev_id_t id)
{
odp_packet_hdr_t *pkt_hdrs[num];
int i;
int num_freed = 0;
+ _odp_packet_validate_multi(pkt, num, id);
+
for (i = 0; i < num; i++) {
odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt[i]);
int num_seg = pkt_hdr->seg_count;
@@ -729,9 +734,14 @@ void odp_packet_free_multi(const odp_packet_t pkt[], int num)
packet_free_multi(pkt_hdrs, num - num_freed);
}
+void odp_packet_free_multi(const odp_packet_t pkt[], int num)
+{
+ packet_free_multi_ev(pkt, num, _ODP_EV_PACKET_FREE_MULTI);
+}
+
void odp_packet_free_sp(const odp_packet_t pkt[], int num)
{
- odp_packet_free_multi(pkt, num);
+ packet_free_multi_ev(pkt, num, _ODP_EV_PACKET_FREE_SP);
}
int odp_packet_reset(odp_packet_t pkt, uint32_t len)
@@ -1588,6 +1598,9 @@ int odp_packet_is_valid(odp_packet_t pkt)
if (odp_event_type(ev) != ODP_EVENT_PACKET)
return 0;
+ if (odp_unlikely(_odp_packet_validate(pkt, _ODP_EV_PACKET_IS_VALID)))
+ return 0;
+
switch (odp_event_subtype(ev)) {
case ODP_EVENT_PACKET_BASIC:
/* Fall through */
@@ -2344,6 +2357,7 @@ odp_packet_t odp_packet_reassemble(odp_pool_t pool_hdl, odp_packet_buf_t pkt_buf
tailroom = pool->ext_param.pkt.buf_size - sizeof(odp_packet_hdr_t);
tailroom -= pool->ext_param.pkt.app_header_size;
tailroom -= odp_packet_buf_data_len(pkt_buf[num - 1]);
+ tailroom -= pool->trailer_size;
pkt_hdr->seg_count = num;
pkt_hdr->frame_len = data_len;
diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c
index f414b0626..59c007ee2 100644
--- a/platform/linux-generic/odp_pool.c
+++ b/platform/linux-generic/odp_pool.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2013-2018, Linaro Limited
- * Copyright (c) 2019-2022, Nokia
+ * Copyright (c) 2019-2023, Nokia
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -7,6 +7,7 @@
#include <odp/api/align.h>
#include <odp/api/atomic.h>
+#include <odp/api/hints.h>
#include <odp/api/pool.h>
#include <odp/api/shared_memory.h>
#include <odp/api/system_info.h>
@@ -21,6 +22,8 @@
#include <odp_packet_internal.h>
#include <odp_config_internal.h>
#include <odp_debug_internal.h>
+#include <odp_event_internal.h>
+#include <odp_event_validation_internal.h>
#include <odp_macros_internal.h>
#include <odp_ring_ptr_internal.h>
#include <odp_global_data.h>
@@ -77,6 +80,7 @@ const _odp_pool_inline_offset_t _odp_pool_inline ODP_ALIGNED_CACHE = {
.index = offsetof(pool_t, pool_idx),
.seg_len = offsetof(pool_t, seg_len),
.uarea_size = offsetof(pool_t, param_uarea_size),
+ .trailer_size = offsetof(pool_t, trailer_size),
.ext_head_offset = offsetof(pool_t, ext_head_offset),
.ext_pkt_buf_size = offsetof(pool_t, ext_param.pkt.buf_size)
};
@@ -472,6 +476,7 @@ static void init_event_hdr(pool_t *pool, _odp_event_hdr_t *event_hdr, uint32_t e
if (type == ODP_POOL_BUFFER || type == ODP_POOL_PACKET) {
event_hdr->base_data = data_ptr;
event_hdr->buf_end = data_ptr + pool->seg_len + pool->tailroom;
+ _odp_event_endmark_set(_odp_event_from_hdr(event_hdr));
}
if (type == ODP_POOL_BUFFER) {
@@ -697,7 +702,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
uint32_t uarea_size, headroom, tailroom;
odp_shm_t shm;
uint32_t seg_len, align, num, hdr_size, block_size;
- uint32_t max_len, cache_size;
+ uint32_t max_len, cache_size, trailer_size;
uint32_t ring_size;
odp_pool_type_t type = params->type;
uint32_t shmflags = 0;
@@ -743,6 +748,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
tailroom = 0;
seg_len = 0;
max_len = 0;
+ trailer_size = 0;
uarea_size = 0;
cache_size = 0;
@@ -752,6 +758,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
seg_len = params->buf.size;
uarea_size = params->buf.uarea_size;
cache_size = params->buf.cache_size;
+ trailer_size = _ODP_EV_ENDMARK_SIZE;
break;
case ODP_POOL_PACKET:
@@ -763,6 +770,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
num = params->pkt.num;
seg_len = CONFIG_PACKET_MAX_SEG_LEN;
max_len = _odp_pool_glb->config.pkt_max_len;
+ trailer_size = _ODP_EV_ENDMARK_SIZE;
if (params->pkt.len &&
params->pkt.len < CONFIG_PACKET_MAX_SEG_LEN)
@@ -840,7 +848,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
uint32_t adj_size;
hdr_size = _ODP_ROUNDUP_CACHE_LINE(sizeof(odp_packet_hdr_t));
- block_size = hdr_size + align + headroom + seg_len + tailroom;
+ block_size = hdr_size + align + headroom + seg_len + tailroom + trailer_size;
adj_size = block_size;
if (pool->mem_src_ops && pool->mem_src_ops->adjust_size) {
@@ -871,7 +879,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
else
hdr_size = _ODP_ROUNDUP_CACHE_LINE(sizeof(odp_event_vector_hdr_t));
- block_size = _ODP_ROUNDUP_CACHE_LINE(hdr_size + align_pad + seg_len);
+ block_size = _ODP_ROUNDUP_CACHE_LINE(hdr_size + align_pad + seg_len + trailer_size);
}
/* Allocate extra memory for skipping packet buffers which cross huge
@@ -894,6 +902,7 @@ odp_pool_t _odp_pool_create(const char *name, const odp_pool_param_t *params,
pool->align = align;
pool->headroom = headroom;
pool->seg_len = seg_len;
+ pool->trailer_size = trailer_size;
pool->max_seg_len = headroom + seg_len + tailroom;
pool->max_len = max_len;
pool->tailroom = tailroom;
@@ -1419,11 +1428,15 @@ int odp_buffer_alloc_multi(odp_pool_t pool_hdl, odp_buffer_t buf[], int num)
void odp_buffer_free(odp_buffer_t buf)
{
+ _odp_buffer_validate(buf, _ODP_EV_BUFFER_FREE);
+
_odp_event_free_multi((_odp_event_hdr_t **)&buf, 1);
}
void odp_buffer_free_multi(const odp_buffer_t buf[], int num)
{
+ _odp_buffer_validate_multi(buf, num, _ODP_EV_BUFFER_FREE_MULTI);
+
_odp_event_free_multi((_odp_event_hdr_t **)(uintptr_t)buf, num);
}
@@ -1530,6 +1543,7 @@ void odp_pool_print(odp_pool_t pool_hdl)
_ODP_PRINT(" burst size %u\n", pool->burst_size);
_ODP_PRINT(" mem src %s\n",
pool->mem_src_ops ? pool->mem_src_ops->name : "(none)");
+ _ODP_PRINT(" event valid. %d\n", _ODP_EVENT_VALIDATION);
_ODP_PRINT("\n");
}
@@ -1727,6 +1741,9 @@ int odp_buffer_is_valid(odp_buffer_t buf)
if (odp_event_type(odp_buffer_to_event(buf)) != ODP_EVENT_BUFFER)
return 0;
+ if (odp_unlikely(_odp_buffer_validate(buf, _ODP_EV_BUFFER_IS_VALID)))
+ return 0;
+
return 1;
}
@@ -1753,7 +1770,7 @@ int odp_pool_ext_capability(odp_pool_type_t type, odp_pool_ext_capability_t *cap
capa->pkt.max_num_buf = _odp_pool_glb->config.pkt_max_num;
capa->pkt.max_buf_size = MAX_SIZE;
capa->pkt.odp_header_size = sizeof(odp_packet_hdr_t);
- capa->pkt.odp_trailer_size = 0;
+ capa->pkt.odp_trailer_size = _ODP_EV_ENDMARK_SIZE;
capa->pkt.min_mem_align = ODP_CACHE_LINE_SIZE;
capa->pkt.min_buf_align = ODP_CACHE_LINE_SIZE;
capa->pkt.min_head_align = MIN_HEAD_ALIGN;
@@ -1878,7 +1895,9 @@ odp_pool_t odp_pool_ext_create(const char *name, const odp_pool_ext_param_t *par
pool->num = num_buf;
pool->headroom = headroom;
pool->tailroom = 0;
- pool->seg_len = buf_size - head_offset - headroom - pool->tailroom;
+ pool->trailer_size = _ODP_EV_ENDMARK_SIZE;
+ pool->seg_len = buf_size - head_offset - headroom - pool->tailroom -
+ pool->trailer_size;
pool->max_seg_len = headroom + pool->seg_len + pool->tailroom;
pool->max_len = PKT_MAX_SEGS * pool->seg_len;
pool->ext_head_offset = head_offset;