diff options
author | Matias Elo <matias.elo@nokia.com> | 2022-06-29 16:36:22 +0300 |
---|---|---|
committer | Matias Elo <matias.elo@nokia.com> | 2023-01-18 10:12:09 +0200 |
commit | a735a7131bceadb87c25b553446e4829923bcc1c (patch) | |
tree | 06fb66a46a0d1b1251bbfe96ac7c43887a546011 /platform | |
parent | 8782c99a6cb53af57316e66271e0a1c6b951fa2b (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.am | 3 | ||||
-rw-r--r-- | platform/linux-generic/include/odp/api/plat/event_validation_external.h | 93 | ||||
-rw-r--r-- | platform/linux-generic/include/odp/api/plat/packet_inlines.h | 3 | ||||
-rw-r--r-- | platform/linux-generic/include/odp/api/plat/pool_inline_types.h | 1 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_event_internal.h | 7 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_event_validation_internal.h | 52 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_init_internal.h | 3 | ||||
-rw-r--r-- | platform/linux-generic/include/odp_pool_internal.h | 1 | ||||
-rw-r--r-- | platform/linux-generic/m4/configure.m4 | 3 | ||||
-rw-r--r-- | platform/linux-generic/m4/odp_event_validation.m4 | 23 | ||||
-rw-r--r-- | platform/linux-generic/odp_event.c | 25 | ||||
-rw-r--r-- | platform/linux-generic/odp_event_validation.c | 234 | ||||
-rw-r--r-- | platform/linux-generic/odp_init.c | 16 | ||||
-rw-r--r-- | platform/linux-generic/odp_packet.c | 20 | ||||
-rw-r--r-- | platform/linux-generic/odp_pool.c | 31 |
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; |