diff options
Diffstat (limited to 'platform/linux-generic')
30 files changed, 1440 insertions, 193 deletions
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index e654381e6..b6721dce4 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -174,6 +174,7 @@ __LIB__libodp_linux_la_SOURCES = \ odp_errno.c \ odp_event.c \ odp_fdserver.c \ + odp_fractional.c \ odp_hash_crc_gen.c \ odp_impl.c \ odp_init.c \ diff --git a/platform/linux-generic/include-abi/odp/api/abi/packet_io.h b/platform/linux-generic/include-abi/odp/api/abi/packet_io.h index 45f06912c..48a847c07 100644 --- a/platform/linux-generic/include-abi/odp/api/abi/packet_io.h +++ b/platform/linux-generic/include-abi/odp/api/abi/packet_io.h @@ -50,6 +50,8 @@ typedef struct odp_pktout_queue_t { #define ODP_PKTIN_NO_WAIT 0 #define ODP_PKTIN_WAIT UINT64_MAX +#define ODP_PKTIO_STATS_EXTRA_NAME_LEN 64 + /** * @} */ diff --git a/platform/linux-generic/include/odp_ethtool_stats.h b/platform/linux-generic/include/odp_ethtool_stats.h index a8783149d..2888d1c81 100644 --- a/platform/linux-generic/include/odp_ethtool_stats.h +++ b/platform/linux-generic/include/odp_ethtool_stats.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -19,6 +20,11 @@ extern "C" { */ int _odp_ethtool_stats_get_fd(int fd, const char *name, odp_pktio_stats_t *stats); +int _odp_ethtool_extra_stat_info(int fd, const char *name, odp_pktio_extra_stat_info_t info[], + int num); +int _odp_ethtool_extra_stats(int fd, const char *name, uint64_t stats[], int num); +int _odp_ethtool_extra_stat_counter(int fd, const char *name, uint32_t id, uint64_t *stat); + #ifdef __cplusplus } #endif diff --git a/platform/linux-generic/include/odp_ipsec_internal.h b/platform/linux-generic/include/odp_ipsec_internal.h index 96153007f..66d85d119 100644 --- a/platform/linux-generic/include/odp_ipsec_internal.h +++ b/platform/linux-generic/include/odp_ipsec_internal.h @@ -84,8 +84,27 @@ int _odp_ipsec_status_send(odp_queue_t queue, #define IPSEC_MAX_SALT_LEN 4 /**< Maximum salt length in bytes */ -/* 32 is minimum required by the standard. We do not support more */ -#define IPSEC_ANTIREPLAY_WS 32 +/* The minimum supported AR window size */ +#define IPSEC_AR_WIN_SIZE_MIN 32 + +/* The maximum supported AR window size */ +#define IPSEC_AR_WIN_SIZE_MAX 4096 + +/* For a 64-bit bucket size */ +#define IPSEC_AR_WIN_BUCKET_BITS 6 +#define IPSEC_AR_WIN_BUCKET_SIZE (1 << IPSEC_AR_WIN_BUCKET_BITS) +#define IPSEC_AR_WIN_BITLOC_MASK (IPSEC_AR_WIN_BUCKET_SIZE - 1) + +/* + * We need one extra bucket in addition to the buckets that contain + * part of the window. + */ +#define IPSEC_AR_WIN_NUM_BUCKETS(window_size) \ + (((window_size) - 1) / IPSEC_AR_WIN_BUCKET_SIZE + 2) + +/* Maximum number of buckets */ +#define IPSEC_AR_WIN_BUCKET_MAX \ + IPSEC_AR_WIN_NUM_BUCKETS(IPSEC_AR_WIN_SIZE_MAX) struct ipsec_sa_s { odp_atomic_u32_t state ODP_ALIGNED_CACHE; @@ -101,7 +120,14 @@ struct ipsec_sa_s { union { struct { - odp_atomic_u64_t antireplay; + /* AR window lock */ + odp_spinlock_t lock; + + /* AR window top sequence number */ + odp_atomic_u64_t wintop_seq; + + /* AR window bucket array */ + uint64_t bucket_arr[IPSEC_AR_WIN_BUCKET_MAX]; } in; struct { @@ -162,6 +188,16 @@ struct ipsec_sa_s { union { struct { odp_ipsec_ip_version_t lookup_ver; + + /* Anti-replay window management. */ + struct { + /* Number of buckets for AR window */ + uint16_t num_buckets; + + /* AR window size */ + uint32_t win_size; + } ar; + union { odp_u32be_t lookup_dst_ipv4; uint8_t lookup_dst_ipv6[_ODP_IPV6ADDR_LEN]; diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index c5a51d11d..95444a6c8 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -1,5 +1,5 @@ /* Copyright (c) 2013-2018, Linaro Limited - * Copyright (c) 2019-2020, Nokia + * Copyright (c) 2019-2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -196,6 +196,14 @@ typedef struct pktio_if_ops { int (*stop)(pktio_entry_t *pktio_entry); int (*stats)(pktio_entry_t *pktio_entry, odp_pktio_stats_t *stats); int (*stats_reset)(pktio_entry_t *pktio_entry); + int (*pktin_queue_stats)(pktio_entry_t *pktio_entry, uint32_t index, + odp_pktin_queue_stats_t *pktin_stats); + int (*pktout_queue_stats)(pktio_entry_t *pktio_entry, uint32_t index, + odp_pktout_queue_stats_t *pktout_stats); + int (*extra_stat_info)(pktio_entry_t *pktio_entry, odp_pktio_extra_stat_info_t info[], + int num); + int (*extra_stats)(pktio_entry_t *pktio_entry, uint64_t stats[], int num); + int (*extra_stat_counter)(pktio_entry_t *pktio_entry, uint32_t id, uint64_t *stat); uint64_t (*pktio_ts_res)(pktio_entry_t *pktio_entry); odp_time_t (*pktio_ts_from_ns)(pktio_entry_t *pktio_entry, uint64_t ns); odp_time_t (*pktio_time)(pktio_entry_t *pktio_entry, odp_time_t *global_ts); diff --git a/platform/linux-generic/include/odp_packet_io_stats.h b/platform/linux-generic/include/odp_packet_io_stats.h index 22e3b5041..c1b37fb29 100644 --- a/platform/linux-generic/include/odp_packet_io_stats.h +++ b/platform/linux-generic/include/odp_packet_io_stats.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -22,6 +23,17 @@ int _odp_sock_stats_fd(pktio_entry_t *pktio_entry, int fd); int _odp_sock_stats_reset_fd(pktio_entry_t *pktio_entry, int fd); +void _odp_sock_stats_capa(pktio_entry_t *pktio_entry, + odp_pktio_capability_t *capa); + +int _odp_sock_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num, + int fd); +int _odp_sock_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], int num, + int fd); +int _odp_sock_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat, int fd); + pktio_stats_type_t _odp_sock_stats_type_fd(pktio_entry_t *pktio_entry, int fd); #ifdef __cplusplus diff --git a/platform/linux-generic/include/odp_schedule_if.h b/platform/linux-generic/include/odp_schedule_if.h index db0f5c264..d3202543d 100644 --- a/platform/linux-generic/include/odp_schedule_if.h +++ b/platform/linux-generic/include/odp_schedule_if.h @@ -126,6 +126,7 @@ typedef struct { uint32_t lock_index); void (*schedule_order_lock_start)(uint32_t lock_index); void (*schedule_order_lock_wait)(uint32_t lock_index); + void (*schedule_print)(void); } schedule_api_t; diff --git a/platform/linux-generic/include/odp_sysfs_stats.h b/platform/linux-generic/include/odp_sysfs_stats.h index 4bcd2b7ff..0adb67c84 100644 --- a/platform/linux-generic/include/odp_sysfs_stats.h +++ b/platform/linux-generic/include/odp_sysfs_stats.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -17,6 +18,13 @@ extern "C" { int _odp_sysfs_stats(pktio_entry_t *pktio_entry, odp_pktio_stats_t *stats); +int _odp_sysfs_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num); +int _odp_sysfs_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], + int num); +int _odp_sysfs_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat); + #ifdef __cplusplus } #endif diff --git a/platform/linux-generic/m4/odp_dpdk.m4 b/platform/linux-generic/m4/odp_dpdk.m4 index 2bbe9a947..f61c38a8e 100644 --- a/platform/linux-generic/m4/odp_dpdk.m4 +++ b/platform/linux-generic/m4/odp_dpdk.m4 @@ -16,6 +16,17 @@ AC_ARG_WITH([dpdk-path], pktio_dpdk_support=yes],[]) ########################################################################## +# Use shared DPDK library +########################################################################## +dpdk_shared=no +AC_ARG_ENABLE([dpdk-shared], + [AS_HELP_STRING([--enable-dpdk-shared], + [use shared DPDK library [default=disabled] (linux-generic)])], + [if test x$enableval = xyes; then + dpdk_shared=yes + fi]) + +########################################################################## # Enable zero-copy DPDK pktio ########################################################################## zero_copy=0 @@ -34,7 +45,7 @@ AC_ARG_ENABLE([dpdk-zero-copy], ########################################################################## if test x$pktio_dpdk_support = xyes then - ODP_DPDK([$DPDK_PATH], [], [], + ODP_DPDK([$DPDK_PATH], [$dpdk_shared], [], [AC_MSG_FAILURE([can't find DPDK])]) case "${host}" in diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c index 9b31f99a8..bc31d01eb 100644 --- a/platform/linux-generic/odp_classification.c +++ b/platform/linux-generic/odp_classification.c @@ -461,7 +461,7 @@ uint32_t odp_cls_cos_queues(odp_cos_t cos_id, odp_queue_t queue[], for (i = 0; i < num_queues; i++) queue[i] = queue_grp_tbl->s.queue[tbl_index + i]; - return num_queues; + return cos->s.num_queue; } int odp_cos_drop_set(odp_cos_t cos_id, odp_cls_drop_t drop_policy) diff --git a/platform/linux-generic/odp_fractional.c b/platform/linux-generic/odp_fractional.c new file mode 100644 index 000000000..c98f3a4b2 --- /dev/null +++ b/platform/linux-generic/odp_fractional.c @@ -0,0 +1,19 @@ +/* Copyright (c) 2021, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp/api/std_types.h> + +double odp_fract_u64_to_dbl(const odp_fract_u64_t *fract) +{ + double fraction; + + if (fract->numer == 0) + fraction = 0.0; + else + fraction = (double)fract->numer / fract->denom; + + return fract->integer + fraction; +} diff --git a/platform/linux-generic/odp_ipsec.c b/platform/linux-generic/odp_ipsec.c index ed19392c9..15590523c 100644 --- a/platform/linux-generic/odp_ipsec.c +++ b/platform/linux-generic/odp_ipsec.c @@ -158,7 +158,7 @@ int odp_ipsec_capability(odp_ipsec_capability_t *capa) capa->max_num_sa = _odp_ipsec_max_num_sa(); - capa->max_antireplay_ws = IPSEC_ANTIREPLAY_WS; + capa->max_antireplay_ws = IPSEC_AR_WIN_SIZE_MAX; rc = set_ipsec_crypto_capa(capa); if (rc < 0) @@ -261,6 +261,7 @@ void odp_ipsec_config_init(odp_ipsec_config_t *config) config->inbound.default_queue = ODP_QUEUE_INVALID; config->inbound.lookup.min_spi = 0; config->inbound.lookup.max_spi = UINT32_MAX; + config->inbound.reassembly.max_num_frags = 2; config->stats_en = false; } diff --git a/platform/linux-generic/odp_ipsec_sad.c b/platform/linux-generic/odp_ipsec_sad.c index d0367bf63..407192dcf 100644 --- a/platform/linux-generic/odp_ipsec_sad.c +++ b/platform/linux-generic/odp_ipsec_sad.c @@ -21,6 +21,7 @@ #include <odp/api/plat/cpu_inlines.h> #include <string.h> +#include <inttypes.h> /* * SA state consists of state value in the high order bits of ipsec_sa_t::state @@ -446,6 +447,37 @@ static uint32_t esp_block_len_to_mask(uint32_t block_len) return block_len - 1; } +/* AR window management initialization */ +static int ipsec_antireplay_init(ipsec_sa_t *ipsec_sa, + const odp_ipsec_sa_param_t *param) +{ + uint16_t num_bkts = 0; + + if (param->inbound.antireplay_ws > IPSEC_AR_WIN_SIZE_MAX) { + ODP_ERR("Anti-replay window size %" PRIu32 " is not supported.\n", + param->inbound.antireplay_ws); + return -1; + } + + ipsec_sa->antireplay = (param->inbound.antireplay_ws != 0); + if (!ipsec_sa->antireplay) + return 0; + + ipsec_sa->in.ar.win_size = param->inbound.antireplay_ws; + /* Window size should be at least IPSEC_AR_WIN_SIZE_MIN */ + if (ipsec_sa->in.ar.win_size < IPSEC_AR_WIN_SIZE_MIN) + ipsec_sa->in.ar.win_size = IPSEC_AR_WIN_SIZE_MIN; + + num_bkts = IPSEC_AR_WIN_NUM_BUCKETS(ipsec_sa->in.ar.win_size); + ipsec_sa->in.ar.num_buckets = num_bkts; + odp_atomic_init_u64(&ipsec_sa->hot.in.wintop_seq, 0); + memset(ipsec_sa->hot.in.bucket_arr, 0, sizeof(uint64_t) * num_bkts); + + odp_spinlock_init(&ipsec_sa->hot.in.lock); + + return 0; +} + odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param) { ipsec_sa_t *ipsec_sa; @@ -488,10 +520,8 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const odp_ipsec_sa_param_t *param) sizeof(ipsec_sa->in.lookup_dst_ipv6)); } - if (param->inbound.antireplay_ws > IPSEC_ANTIREPLAY_WS) + if (ipsec_antireplay_init(ipsec_sa, param)) goto error; - ipsec_sa->antireplay = (param->inbound.antireplay_ws != 0); - odp_atomic_init_u64(&ipsec_sa->hot.in.antireplay, 0); } else { ipsec_sa->lookup_mode = ODP_IPSEC_LOOKUP_DISABLED; odp_atomic_init_u64(&ipsec_sa->hot.out.seq, 1); @@ -909,10 +939,9 @@ int _odp_ipsec_sa_lifetime_update(ipsec_sa_t *ipsec_sa, uint32_t len, static uint64_t ipsec_sa_antireplay_max_seq(ipsec_sa_t *ipsec_sa) { - uint64_t state, max_seq; + uint64_t max_seq = 0; - state = odp_atomic_load_u64(&ipsec_sa->hot.in.antireplay); - max_seq = state & 0xffffffff; + max_seq = odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq) & 0xffffffff; return max_seq; } @@ -921,9 +950,8 @@ int _odp_ipsec_sa_replay_precheck(ipsec_sa_t *ipsec_sa, uint32_t seq, odp_ipsec_op_status_t *status) { /* Try to be as quick as possible, we will discard packets later */ - if (ipsec_sa->antireplay && - seq + IPSEC_ANTIREPLAY_WS <= - (odp_atomic_load_u64(&ipsec_sa->hot.in.antireplay) & 0xffffffff)) { + if (ipsec_sa->antireplay && ((seq + ipsec_sa->in.ar.win_size) <= + (odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq) & 0xffffffff))) { status->error.antireplay = 1; return -1; } @@ -931,22 +959,73 @@ int _odp_ipsec_sa_replay_precheck(ipsec_sa_t *ipsec_sa, uint32_t seq, return 0; } -int _odp_ipsec_sa_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq, - odp_ipsec_op_status_t *status) +static inline int ipsec_wslarge_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq, + odp_ipsec_op_status_t *status) { - int cas = 0; - uint64_t state, new_state; + uint32_t bucket, wintop_bucket, new_bucket; + uint32_t bkt_diff, bkt_cnt, top_seq; + uint64_t bit = 0; + + odp_spinlock_lock(&ipsec_sa->hot.in.lock); - state = odp_atomic_load_u64(&ipsec_sa->hot.in.antireplay); + top_seq = odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq); + if ((seq + ipsec_sa->in.ar.win_size) <= top_seq) + goto ar_err; + + bucket = (seq >> IPSEC_AR_WIN_BUCKET_BITS); + + /* Check if the seq is within the range */ + if (seq > top_seq) { + wintop_bucket = top_seq >> IPSEC_AR_WIN_BUCKET_BITS; + bkt_diff = bucket - wintop_bucket; + + /* Seq is way after the range of AR window size */ + if (bkt_diff > ipsec_sa->in.ar.num_buckets) + bkt_diff = ipsec_sa->in.ar.num_buckets; + + for (bkt_cnt = 0; bkt_cnt < bkt_diff; bkt_cnt++) { + new_bucket = (bkt_cnt + wintop_bucket + 1) % + ipsec_sa->in.ar.num_buckets; + ipsec_sa->hot.in.bucket_arr[new_bucket] = 0; + } + /* AR window top sequence number */ + odp_atomic_store_u64(&ipsec_sa->hot.in.wintop_seq, seq); + } + + bucket %= ipsec_sa->in.ar.num_buckets; + bit = (uint64_t)1 << (seq & IPSEC_AR_WIN_BITLOC_MASK); + + /* Already seen the packet, discard it */ + if (ipsec_sa->hot.in.bucket_arr[bucket] & bit) + goto ar_err; + + /* Packet is new, mark it as seen */ + ipsec_sa->hot.in.bucket_arr[bucket] |= bit; + odp_spinlock_unlock(&ipsec_sa->hot.in.lock); + + return 0; +ar_err: + status->error.antireplay = 1; + odp_spinlock_unlock(&ipsec_sa->hot.in.lock); + return -1; +} + +static inline int ipsec_ws32_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq, + odp_ipsec_op_status_t *status) +{ + uint64_t state, new_state; + int cas = 0; + + state = odp_atomic_load_u64(&ipsec_sa->hot.in.wintop_seq); while (0 == cas) { uint32_t max_seq = state & 0xffffffff; uint32_t mask = state >> 32; - if (seq + IPSEC_ANTIREPLAY_WS <= max_seq) { + if (seq + IPSEC_AR_WIN_SIZE_MIN <= max_seq) { status->error.antireplay = 1; return -1; - } else if (seq >= max_seq + IPSEC_ANTIREPLAY_WS) { + } else if (seq >= max_seq + IPSEC_AR_WIN_SIZE_MIN) { mask = 1; max_seq = seq; } else if (seq > max_seq) { @@ -961,14 +1040,26 @@ int _odp_ipsec_sa_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq, } new_state = (((uint64_t)mask) << 32) | max_seq; - - cas = odp_atomic_cas_acq_rel_u64(&ipsec_sa->hot.in.antireplay, + cas = odp_atomic_cas_acq_rel_u64(&ipsec_sa->hot.in.wintop_seq, &state, new_state); } - return 0; } +int _odp_ipsec_sa_replay_update(ipsec_sa_t *ipsec_sa, uint32_t seq, + odp_ipsec_op_status_t *status) +{ + int ret; + + /* Window update for ws equal to 32 */ + if (ipsec_sa->in.ar.win_size == IPSEC_AR_WIN_SIZE_MIN) + ret = ipsec_ws32_replay_update(ipsec_sa, seq, status); + else + ret = ipsec_wslarge_replay_update(ipsec_sa, seq, status); + + return ret; +} + uint16_t _odp_ipsec_sa_alloc_ipv4_id(ipsec_sa_t *ipsec_sa) { (void)ipsec_sa; @@ -1084,7 +1175,7 @@ static void ipsec_in_sa_info(ipsec_sa_t *ipsec_sa, odp_ipsec_sa_info_t *sa_info) sa_info->param.inbound.lookup_param.dst_addr = dst; if (ipsec_sa->antireplay) { - sa_info->inbound.antireplay_ws = IPSEC_ANTIREPLAY_WS; + sa_info->inbound.antireplay_ws = ipsec_sa->in.ar.win_size; sa_info->inbound.antireplay_window_top = ipsec_sa_antireplay_max_seq(ipsec_sa); } diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index 694b0a741..39cbd72f6 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -315,6 +315,10 @@ static odp_pktio_t setup_pktio_entry(const char *name, odp_pool_t pool, return ODP_PKTIO_INVALID; } + snprintf(pktio_entry->s.name, + sizeof(pktio_entry->s.name), "%s", if_name); + snprintf(pktio_entry->s.full_name, + sizeof(pktio_entry->s.full_name), "%s", name); pktio_entry->s.pool = pool; memcpy(&pktio_entry->s.param, param, sizeof(odp_pktio_param_t)); pktio_entry->s.handle = hdl; @@ -347,10 +351,6 @@ static odp_pktio_t setup_pktio_entry(const char *name, odp_pool_t pool, return ODP_PKTIO_INVALID; } - snprintf(pktio_entry->s.name, - sizeof(pktio_entry->s.name), "%s", if_name); - snprintf(pktio_entry->s.full_name, - sizeof(pktio_entry->s.full_name), "%s", name); pktio_entry->s.state = PKTIO_STATE_OPENED; pktio_entry->s.ops = _odp_pktio_if_ops[pktio_if]; unlock_entry(pktio_entry); @@ -1534,6 +1534,7 @@ void odp_pktio_config_init(odp_pktio_config_t *config) memset(config, 0, sizeof(odp_pktio_config_t)); config->parser.layer = ODP_PROTO_LAYER_ALL; + config->reassembly.max_num_frags = 2; } int odp_pktio_info(odp_pktio_t hdl, odp_pktio_info_t *info) @@ -1901,6 +1902,277 @@ int odp_pktio_stats_reset(odp_pktio_t pktio) return ret; } +int odp_pktin_queue_stats(odp_pktin_queue_t queue, + odp_pktin_queue_stats_t *stats) +{ + pktio_entry_t *entry; + odp_pktin_mode_t mode; + int ret = -1; + + entry = get_pktio_entry(queue.pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)queue.pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("pktio entry already freed\n"); + return -1; + } + + mode = entry->s.param.in_mode; + if (odp_unlikely(mode != ODP_PKTIN_MODE_DIRECT)) { + unlock_entry(entry); + ODP_ERR("invalid packet input mode: %d\n", mode); + return -1; + } + + if (entry->s.ops->pktin_queue_stats) + ret = entry->s.ops->pktin_queue_stats(entry, queue.index, stats); + + unlock_entry(entry); + + return ret; +} + +int odp_pktin_event_queue_stats(odp_pktio_t pktio, odp_queue_t queue, + odp_pktin_queue_stats_t *stats) +{ + pktio_entry_t *entry; + odp_pktin_mode_t mode; + odp_pktin_queue_t pktin_queue; + int ret = -1; + + entry = get_pktio_entry(pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("pktio entry already freed\n"); + return -1; + } + + mode = entry->s.param.in_mode; + if (odp_unlikely(mode != ODP_PKTIN_MODE_SCHED && mode != ODP_PKTIN_MODE_QUEUE)) { + unlock_entry(entry); + ODP_ERR("invalid packet input mode: %d\n", mode); + return -1; + } + + pktin_queue = _odp_queue_fn->get_pktin(queue); + + if (entry->s.ops->pktin_queue_stats) + ret = entry->s.ops->pktin_queue_stats(entry, pktin_queue.index, stats); + + unlock_entry(entry); + + return ret; +} + +int odp_pktout_queue_stats(odp_pktout_queue_t queue, + odp_pktout_queue_stats_t *stats) +{ + pktio_entry_t *entry; + odp_pktout_mode_t mode; + int ret = -1; + + entry = get_pktio_entry(queue.pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)queue.pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("pktio entry already freed\n"); + return -1; + } + + mode = entry->s.param.out_mode; + if (odp_unlikely(mode != ODP_PKTOUT_MODE_DIRECT)) { + unlock_entry(entry); + ODP_ERR("invalid packet output mode: %d\n", mode); + return -1; + } + + if (entry->s.ops->pktout_queue_stats) + ret = entry->s.ops->pktout_queue_stats(entry, queue.index, stats); + + unlock_entry(entry); + + return ret; +} + +int odp_pktout_event_queue_stats(odp_pktio_t pktio, odp_queue_t queue, + odp_pktout_queue_stats_t *stats) +{ + pktio_entry_t *entry; + odp_pktout_mode_t mode; + odp_pktout_queue_t pktout_queue; + int ret = -1; + + entry = get_pktio_entry(pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("pktio entry already freed\n"); + return -1; + } + + mode = entry->s.param.out_mode; + if (odp_unlikely(mode != ODP_PKTOUT_MODE_QUEUE)) { + unlock_entry(entry); + ODP_ERR("invalid packet output mode: %d\n", mode); + return -1; + } + + pktout_queue = _odp_queue_fn->get_pktout(queue); + + if (entry->s.ops->pktout_queue_stats) + ret = entry->s.ops->pktout_queue_stats(entry, pktout_queue.index, stats); + + unlock_entry(entry); + + return ret; +} + +int odp_pktio_extra_stat_info(odp_pktio_t pktio, + odp_pktio_extra_stat_info_t info[], int num) +{ + pktio_entry_t *entry; + int ret = 0; + + entry = get_pktio_entry(pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("already freed pktio\n"); + return -1; + } + + if (entry->s.ops->extra_stat_info) + ret = entry->s.ops->extra_stat_info(entry, info, num); + + unlock_entry(entry); + + return ret; +} + +int odp_pktio_extra_stats(odp_pktio_t pktio, uint64_t stats[], int num) +{ + pktio_entry_t *entry; + int ret = 0; + + entry = get_pktio_entry(pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("already freed pktio\n"); + return -1; + } + + if (entry->s.ops->extra_stats) + ret = entry->s.ops->extra_stats(entry, stats, num); + + unlock_entry(entry); + + return ret; +} + +int odp_pktio_extra_stat_counter(odp_pktio_t pktio, uint32_t id, uint64_t *stat) +{ + pktio_entry_t *entry; + int ret = -1; + + entry = get_pktio_entry(pktio); + if (entry == NULL) { + ODP_ERR("pktio entry %" PRIuPTR " does not exist\n", (uintptr_t)pktio); + return -1; + } + + lock_entry(entry); + + if (odp_unlikely(is_free(entry))) { + unlock_entry(entry); + ODP_ERR("already freed pktio\n"); + return -1; + } + + if (entry->s.ops->extra_stat_counter) + ret = entry->s.ops->extra_stat_counter(entry, id, stat); + + unlock_entry(entry); + + return ret; +} + +void odp_pktio_extra_stats_print(odp_pktio_t pktio) +{ + int num_info, num_stats, i; + + num_info = odp_pktio_extra_stat_info(pktio, NULL, 0); + if (num_info <= 0) + return; + + num_stats = odp_pktio_extra_stats(pktio, NULL, 0); + if (num_stats <= 0) + return; + + if (num_info != num_stats) { + ODP_ERR("extra statistics info counts not matching\n"); + return; + } + + odp_pktio_extra_stat_info_t stats_info[num_stats]; + uint64_t extra_stats[num_stats]; + + num_info = odp_pktio_extra_stat_info(pktio, stats_info, num_stats); + if (num_info <= 0) + return; + + num_stats = odp_pktio_extra_stats(pktio, extra_stats, num_stats); + if (num_stats <= 0) + return; + + if (num_info != num_stats) { + ODP_ERR("extra statistics info counts not matching\n"); + return; + } + + printf("Pktio extra statistics\n----------------------\n"); + for (i = 0; i < num_stats; i++) + ODP_PRINT(" %s=%" PRIu64 "\n", stats_info[i].name, extra_stats[i]); + ODP_PRINT("\n"); +} + int odp_pktin_queue_config(odp_pktio_t pktio, const odp_pktin_queue_param_t *param) { @@ -2037,14 +2309,13 @@ int odp_pktin_queue_config(odp_pktio_t pktio, return -1; } - if (mode == ODP_PKTIN_MODE_QUEUE) { - _odp_queue_fn->set_pktin(queue, pktio, i); + _odp_queue_fn->set_pktin(queue, pktio, i); + if (mode == ODP_PKTIN_MODE_QUEUE) _odp_queue_fn->set_enq_deq_fn(queue, NULL, NULL, pktin_dequeue, pktin_deq_multi); - } entry->s.in_queue[i].queue = queue; diff --git a/platform/linux-generic/odp_schedule_basic.c b/platform/linux-generic/odp_schedule_basic.c index 3c3810dfc..5d328b84c 100644 --- a/platform/linux-generic/odp_schedule_basic.c +++ b/platform/linux-generic/odp_schedule_basic.c @@ -190,10 +190,10 @@ typedef struct { uint16_t max_spread; uint32_t ring_mask; - prio_q_mask_t prio_q_mask[NUM_PRIO]; odp_spinlock_t mask_lock; odp_atomic_u32_t grp_epoch; odp_shm_t shm; + prio_q_mask_t prio_q_mask[NUM_SCHED_GRPS][NUM_PRIO]; struct { uint8_t grp; @@ -210,7 +210,7 @@ typedef struct { /* Scheduler priority queues */ prio_queue_t prio_q[NUM_SCHED_GRPS][NUM_PRIO][MAX_SPREAD]; - uint32_t prio_q_count[NUM_PRIO][MAX_SPREAD]; + uint32_t prio_q_count[NUM_SCHED_GRPS][NUM_PRIO][MAX_SPREAD]; odp_thrmask_t mask_all; odp_spinlock_t grp_lock; @@ -218,7 +218,8 @@ typedef struct { struct { char name[ODP_SCHED_GROUP_NAME_LEN]; odp_thrmask_t mask; - int allocated; + uint16_t spread_thrs[MAX_SPREAD]; + uint8_t allocated; } sched_grp[NUM_SCHED_GRPS]; struct { @@ -467,6 +468,13 @@ static int schedule_init_global(void) sched->sched_grp[ODP_SCHED_GROUP_ALL].allocated = 1; sched->sched_grp[ODP_SCHED_GROUP_WORKER].allocated = 1; sched->sched_grp[ODP_SCHED_GROUP_CONTROL].allocated = 1; + strncpy(sched->sched_grp[ODP_SCHED_GROUP_ALL].name, "__SCHED_GROUP_ALL", + ODP_SCHED_GROUP_NAME_LEN - 1); + strncpy(sched->sched_grp[ODP_SCHED_GROUP_WORKER].name, "__SCHED_GROUP_WORKER", + ODP_SCHED_GROUP_NAME_LEN - 1); + strncpy(sched->sched_grp[ODP_SCHED_GROUP_CONTROL].name, "__SCHED_GROUP_CONTROL", + ODP_SCHED_GROUP_NAME_LEN - 1); + odp_thrmask_setall(&sched->mask_all); @@ -589,6 +597,7 @@ static int schedule_create_queue(uint32_t queue_index, const odp_schedule_param_t *sched_param) { int i; + int grp = sched_param->group; int prio = prio_level_from_api(sched_param->prio); uint8_t spread = spread_index(queue_index); @@ -597,22 +606,19 @@ static int schedule_create_queue(uint32_t queue_index, return -1; } - if (sched_param->group < 0 || sched_param->group >= NUM_SCHED_GRPS) { - ODP_ERR("Bad schedule group\n"); + if (grp < 0 || grp >= NUM_SCHED_GRPS) { + ODP_ERR("Bad schedule group %i\n", grp); return -1; } - if (sched_param->group == ODP_SCHED_GROUP_ALL && - !sched->config_if.group_enable.all) { + if (grp == ODP_SCHED_GROUP_ALL && !sched->config_if.group_enable.all) { ODP_ERR("Trying to use disabled ODP_SCHED_GROUP_ALL\n"); return -1; } - if (sched_param->group == ODP_SCHED_GROUP_CONTROL && - !sched->config_if.group_enable.control) { + if (grp == ODP_SCHED_GROUP_CONTROL && !sched->config_if.group_enable.control) { ODP_ERR("Trying to use disabled ODP_SCHED_GROUP_CONTROL\n"); return -1; } - if (sched_param->group == ODP_SCHED_GROUP_WORKER && - !sched->config_if.group_enable.worker) { + if (grp == ODP_SCHED_GROUP_WORKER && !sched->config_if.group_enable.worker) { ODP_ERR("Trying to use disabled ODP_SCHED_GROUP_WORKER\n"); return -1; } @@ -620,12 +626,12 @@ static int schedule_create_queue(uint32_t queue_index, odp_spinlock_lock(&sched->mask_lock); /* update scheduler prio queue usage status */ - sched->prio_q_mask[prio] |= 1 << spread; - sched->prio_q_count[prio][spread]++; + sched->prio_q_mask[grp][prio] |= 1 << spread; + sched->prio_q_count[grp][prio][spread]++; odp_spinlock_unlock(&sched->mask_lock); - sched->queue[queue_index].grp = sched_param->group; + sched->queue[queue_index].grp = grp; sched->queue[queue_index].prio = prio; sched->queue[queue_index].spread = spread; sched->queue[queue_index].sync = sched_param->sync; @@ -650,16 +656,17 @@ static inline uint8_t sched_sync_type(uint32_t queue_index) static void schedule_destroy_queue(uint32_t queue_index) { + int grp = sched->queue[queue_index].grp; int prio = sched->queue[queue_index].prio; uint8_t spread = spread_index(queue_index); odp_spinlock_lock(&sched->mask_lock); /* Clear mask bit when last queue is removed*/ - sched->prio_q_count[prio][spread]--; + sched->prio_q_count[grp][prio][spread]--; - if (sched->prio_q_count[prio][spread] == 0) - sched->prio_q_mask[prio] &= (uint8_t)(~(1 << spread)); + if (sched->prio_q_count[grp][prio][spread] == 0) + sched->prio_q_mask[grp][prio] &= (uint8_t)(~(1 << spread)); odp_spinlock_unlock(&sched->mask_lock); @@ -1014,11 +1021,9 @@ static inline int poll_pktin(uint32_t qi, int direct_recv, } static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[], - unsigned int max_num, int grp, int first) + unsigned int max_num, int grp, int first_spr) { - int prio, i; - int ret; - int id; + int prio, spr, i, ret; uint32_t qi; uint16_t burst_def; int num_spread = sched->config.num_spread; @@ -1026,13 +1031,13 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[], /* Schedule events */ for (prio = 0; prio < NUM_PRIO; prio++) { - if (sched->prio_q_mask[prio] == 0) + if (sched->prio_q_mask[grp][prio] == 0) continue; burst_def = sched->config.burst_default[prio]; - /* Select the first ring based on weights */ - id = first; + /* Select the first spread based on weights */ + spr = first_spr; for (i = 0; i < num_spread;) { int num; @@ -1044,24 +1049,24 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[], int stashed = 1; odp_event_t *ev_tbl = sched_local.stash.ev; - if (id >= num_spread) - id = 0; + if (spr >= num_spread) + spr = 0; /* No queues created for this priority queue */ - if (odp_unlikely((sched->prio_q_mask[prio] & (1 << id)) + if (odp_unlikely((sched->prio_q_mask[grp][prio] & (1 << spr)) == 0)) { i++; - id++; + spr++; continue; } /* Get queue index from the priority queue */ - ring = &sched->prio_q[grp][prio][id].ring; + ring = &sched->prio_q[grp][prio][spr].ring; if (ring_u32_deq(ring, ring_mask, &qi) == 0) { /* Priority queue empty */ i++; - id++; + spr++; continue; } @@ -1180,9 +1185,7 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[], static inline int do_schedule(odp_queue_t *out_queue, odp_event_t out_ev[], unsigned int max_num) { - int i, num_grp; - int ret; - int first, grp_id; + int i, num_grp, ret, spr, grp_id; uint16_t spread_round, grp_round; uint32_t epoch; @@ -1214,7 +1217,7 @@ static inline int do_schedule(odp_queue_t *out_queue, odp_event_t out_ev[], else sched_local.spread_round = spread_round + 1; - first = sched_local.spread_tbl[spread_round]; + spr = sched_local.spread_tbl[spread_round]; epoch = odp_atomic_load_acq_u32(&sched->grp_epoch); num_grp = sched_local.num_grp; @@ -1231,7 +1234,7 @@ static inline int do_schedule(odp_queue_t *out_queue, odp_event_t out_ev[], int grp; grp = sched_local.grp[grp_id]; - ret = do_schedule_grp(out_queue, out_ev, max_num, grp, first); + ret = do_schedule_grp(out_queue, out_ev, max_num, grp, spr); if (odp_likely(ret)) return ret; @@ -1488,52 +1491,106 @@ static odp_schedule_group_t schedule_group_lookup(const char *name) return group; } -static int schedule_group_join(odp_schedule_group_t group, - const odp_thrmask_t *mask) +static int schedule_group_join(odp_schedule_group_t group, const odp_thrmask_t *mask) { - int ret; + int i, count, thr; + uint8_t spread; + odp_thrmask_t new_mask; - odp_spinlock_lock(&sched->grp_lock); + if (group >= NUM_SCHED_GRPS || group < SCHED_GROUP_NAMED) { + ODP_ERR("Bad group %i\n", group); + return -1; + } - if (group < NUM_SCHED_GRPS && group >= SCHED_GROUP_NAMED && - sched->sched_grp[group].allocated) { - odp_thrmask_t new_mask; + count = odp_thrmask_count(mask); + if (count <= 0) { + ODP_ERR("No threads in the mask\n"); + return -1; + } - odp_thrmask_or(&new_mask, &sched->sched_grp[group].mask, mask); - grp_update_mask(group, &new_mask); + int thr_tbl[count]; - ret = 0; - } else { - ret = -1; + thr = odp_thrmask_first(mask); + for (i = 0; i < count; i++) { + if (thr < 0) { + ODP_ERR("No more threads in the mask\n"); + return -1; + } + + thr_tbl[i] = thr; + thr = odp_thrmask_next(mask, thr); + } + + odp_spinlock_lock(&sched->grp_lock); + + if (sched->sched_grp[group].allocated == 0) { + odp_spinlock_unlock(&sched->grp_lock); + ODP_ERR("Bad group status\n"); + return -1; } + for (i = 0; i < count; i++) { + spread = spread_index(thr_tbl[i]); + sched->sched_grp[group].spread_thrs[spread]++; + } + + odp_thrmask_or(&new_mask, &sched->sched_grp[group].mask, mask); + grp_update_mask(group, &new_mask); + odp_spinlock_unlock(&sched->grp_lock); - return ret; + return 0; } -static int schedule_group_leave(odp_schedule_group_t group, - const odp_thrmask_t *mask) +static int schedule_group_leave(odp_schedule_group_t group, const odp_thrmask_t *mask) { + int i, count, thr; + uint8_t spread; odp_thrmask_t new_mask; - int ret; + + if (group >= NUM_SCHED_GRPS || group < SCHED_GROUP_NAMED) { + ODP_ERR("Bad group %i\n", group); + return -1; + } + + count = odp_thrmask_count(mask); + if (count <= 0) { + ODP_ERR("No threads in the mask\n"); + return -1; + } + + int thr_tbl[count]; + + thr = odp_thrmask_first(mask); + for (i = 0; i < count; i++) { + if (thr < 0) { + ODP_ERR("No more threads in the mask\n"); + return -1; + } + + thr_tbl[i] = thr; + thr = odp_thrmask_next(mask, thr); + } odp_thrmask_xor(&new_mask, mask, &sched->mask_all); odp_spinlock_lock(&sched->grp_lock); - if (group < NUM_SCHED_GRPS && group >= SCHED_GROUP_NAMED && - sched->sched_grp[group].allocated) { - odp_thrmask_and(&new_mask, &sched->sched_grp[group].mask, - &new_mask); - grp_update_mask(group, &new_mask); + if (sched->sched_grp[group].allocated == 0) { + odp_spinlock_unlock(&sched->grp_lock); + ODP_ERR("Bad group status\n"); + return -1; + } - ret = 0; - } else { - ret = -1; + for (i = 0; i < count; i++) { + spread = spread_index(thr_tbl[i]); + sched->sched_grp[group].spread_thrs[spread]--; } + odp_thrmask_and(&new_mask, &sched->sched_grp[group].mask, &new_mask); + grp_update_mask(group, &new_mask); + odp_spinlock_unlock(&sched->grp_lock); - return ret; + return 0; } static int schedule_group_thrmask(odp_schedule_group_t group, @@ -1543,8 +1600,7 @@ static int schedule_group_thrmask(odp_schedule_group_t group, odp_spinlock_lock(&sched->grp_lock); - if (group < NUM_SCHED_GRPS && group >= SCHED_GROUP_NAMED && - sched->sched_grp[group].allocated) { + if (group < NUM_SCHED_GRPS && sched->sched_grp[group].allocated) { *thrmask = sched->sched_grp[group].mask; ret = 0; } else { @@ -1562,8 +1618,7 @@ static int schedule_group_info(odp_schedule_group_t group, odp_spinlock_lock(&sched->grp_lock); - if (group < NUM_SCHED_GRPS && group >= SCHED_GROUP_NAMED && - sched->sched_grp[group].allocated) { + if (group < NUM_SCHED_GRPS && sched->sched_grp[group].allocated) { info->name = sched->sched_grp[group].name; info->thrmask = sched->sched_grp[group].mask; ret = 0; @@ -1579,6 +1634,7 @@ static int schedule_thr_add(odp_schedule_group_t group, int thr) { odp_thrmask_t mask; odp_thrmask_t new_mask; + uint8_t spread = spread_index(thr); if (group < 0 || group >= SCHED_GROUP_NAMED) return -1; @@ -1594,6 +1650,7 @@ static int schedule_thr_add(odp_schedule_group_t group, int thr) } odp_thrmask_or(&new_mask, &sched->sched_grp[group].mask, &mask); + sched->sched_grp[group].spread_thrs[spread]++; grp_update_mask(group, &new_mask); odp_spinlock_unlock(&sched->grp_lock); @@ -1605,6 +1662,7 @@ static int schedule_thr_rem(odp_schedule_group_t group, int thr) { odp_thrmask_t mask; odp_thrmask_t new_mask; + uint8_t spread = spread_index(thr); if (group < 0 || group >= SCHED_GROUP_NAMED) return -1; @@ -1621,6 +1679,7 @@ static int schedule_thr_rem(odp_schedule_group_t group, int thr) } odp_thrmask_and(&new_mask, &sched->sched_grp[group].mask, &new_mask); + sched->sched_grp[group].spread_thrs[spread]--; grp_update_mask(group, &new_mask); odp_spinlock_unlock(&sched->grp_lock); @@ -1657,6 +1716,82 @@ static int schedule_capability(odp_schedule_capability_t *capa) return 0; } +static void schedule_print(void) +{ + int spr, prio, grp; + uint32_t num_queues, num_active; + ring_u32_t *ring; + odp_schedule_capability_t capa; + int num_spread = sched->config.num_spread; + + (void)schedule_capability(&capa); + + ODP_PRINT("\nScheduler debug info\n"); + ODP_PRINT("--------------------\n"); + ODP_PRINT(" scheduler: basic\n"); + ODP_PRINT(" max groups: %u\n", capa.max_groups); + ODP_PRINT(" max priorities: %u\n", capa.max_prios); + ODP_PRINT(" num spread: %i\n", num_spread); + ODP_PRINT(" prefer ratio: %u\n", sched->config.prefer_ratio); + ODP_PRINT("\n"); + + ODP_PRINT(" Number of active event queues:\n"); + ODP_PRINT(" spread\n"); + ODP_PRINT(" "); + + for (spr = 0; spr < num_spread; spr++) + ODP_PRINT(" %7i", spr); + + ODP_PRINT("\n"); + + for (prio = 0; prio < NUM_PRIO; prio++) { + ODP_PRINT(" prio %i", prio); + + for (grp = 0; grp < NUM_SCHED_GRPS; grp++) + if (sched->prio_q_mask[grp][prio]) + break; + + if (grp == NUM_SCHED_GRPS) { + ODP_PRINT(":-\n"); + continue; + } + + ODP_PRINT("\n"); + + for (grp = 0; grp < NUM_SCHED_GRPS; grp++) { + if (sched->sched_grp[grp].allocated == 0) + continue; + + ODP_PRINT(" group %i:", grp); + + for (spr = 0; spr < num_spread; spr++) { + num_queues = sched->prio_q_count[grp][prio][spr]; + ring = &sched->prio_q[grp][prio][spr].ring; + num_active = ring_u32_len(ring); + ODP_PRINT(" %3u/%3u", num_active, num_queues); + } + ODP_PRINT("\n"); + } + } + + ODP_PRINT("\n Number of threads:\n"); + ODP_PRINT(" spread\n"); + + for (grp = 0; grp < NUM_SCHED_GRPS; grp++) { + if (sched->sched_grp[grp].allocated == 0) + continue; + + ODP_PRINT(" group %i:", grp); + + for (spr = 0; spr < num_spread; spr++) + ODP_PRINT(" %u", sched->sched_grp[grp].spread_thrs[spr]); + + ODP_PRINT("\n"); + } + + ODP_PRINT("\n"); +} + /* Fill in scheduler interface */ const schedule_fn_t _odp_schedule_basic_fn = { .pktio_start = schedule_pktio_start, @@ -1705,7 +1840,8 @@ const schedule_api_t _odp_schedule_basic_api = { .schedule_group_info = schedule_group_info, .schedule_order_lock = schedule_order_lock, .schedule_order_unlock = schedule_order_unlock, - .schedule_order_unlock_lock = schedule_order_unlock_lock, - .schedule_order_lock_start = schedule_order_lock_start, - .schedule_order_lock_wait = schedule_order_lock_wait + .schedule_order_unlock_lock = schedule_order_unlock_lock, + .schedule_order_lock_start = schedule_order_lock_start, + .schedule_order_lock_wait = schedule_order_lock_wait, + .schedule_print = schedule_print }; diff --git a/platform/linux-generic/odp_schedule_if.c b/platform/linux-generic/odp_schedule_if.c index 01359543c..24307ab90 100644 --- a/platform/linux-generic/odp_schedule_if.c +++ b/platform/linux-generic/odp_schedule_if.c @@ -201,6 +201,11 @@ void odp_schedule_order_lock_wait(uint32_t lock_index) _odp_sched_api->schedule_order_lock_wait(lock_index); } +void odp_schedule_print(void) +{ + _odp_sched_api->schedule_print(); +} + int _odp_schedule_init_global(void) { const char *sched = getenv("ODP_SCHEDULER"); diff --git a/platform/linux-generic/odp_schedule_scalable.c b/platform/linux-generic/odp_schedule_scalable.c index c9991c3f3..18e738330 100644 --- a/platform/linux-generic/odp_schedule_scalable.c +++ b/platform/linux-generic/odp_schedule_scalable.c @@ -2175,6 +2175,20 @@ static int schedule_capability(odp_schedule_capability_t *capa) return 0; } +static void schedule_print(void) +{ + odp_schedule_capability_t capa; + + (void)schedule_capability(&capa); + + ODP_PRINT("\nScheduler debug info\n"); + ODP_PRINT("--------------------\n"); + ODP_PRINT(" scheduler: scalable\n"); + ODP_PRINT(" max groups: %u\n", capa.max_groups); + ODP_PRINT(" max priorities: %u\n", capa.max_prios); + ODP_PRINT("\n"); +} + const schedule_fn_t _odp_schedule_scalable_fn = { .pktio_start = pktio_start, .thr_add = thr_add, @@ -2222,5 +2236,6 @@ const schedule_api_t _odp_schedule_scalable_api = { .schedule_order_unlock = schedule_order_unlock, .schedule_order_unlock_lock = schedule_order_unlock_lock, .schedule_order_lock_start = schedule_order_lock_start, - .schedule_order_lock_wait = schedule_order_lock_wait + .schedule_order_lock_wait = schedule_order_lock_wait, + .schedule_print = schedule_print }; diff --git a/platform/linux-generic/odp_schedule_sp.c b/platform/linux-generic/odp_schedule_sp.c index a401ba884..c4f8344f1 100644 --- a/platform/linux-generic/odp_schedule_sp.c +++ b/platform/linux-generic/odp_schedule_sp.c @@ -1039,6 +1039,20 @@ static int schedule_capability(odp_schedule_capability_t *capa) return 0; } +static void schedule_print(void) +{ + odp_schedule_capability_t capa; + + (void)schedule_capability(&capa); + + ODP_PRINT("\nScheduler debug info\n"); + ODP_PRINT("--------------------\n"); + ODP_PRINT(" scheduler: sp\n"); + ODP_PRINT(" max groups: %u\n", capa.max_groups); + ODP_PRINT(" max priorities: %u\n", capa.max_prios); + ODP_PRINT("\n"); +} + static void get_config(schedule_config_t *config) { *config = sched_global->config_if; @@ -1092,7 +1106,8 @@ const schedule_api_t _odp_schedule_sp_api = { .schedule_group_info = schedule_group_info, .schedule_order_lock = schedule_order_lock, .schedule_order_unlock = schedule_order_unlock, - .schedule_order_unlock_lock = schedule_order_unlock_lock, - .schedule_order_lock_start = schedule_order_lock_start, - .schedule_order_lock_wait = schedule_order_lock_wait + .schedule_order_unlock_lock = schedule_order_unlock_lock, + .schedule_order_lock_start = schedule_order_lock_start, + .schedule_order_lock_wait = schedule_order_lock_wait, + .schedule_print = schedule_print }; diff --git a/platform/linux-generic/odp_timer.c b/platform/linux-generic/odp_timer.c index f75fbd522..e5b42a83b 100644 --- a/platform/linux-generic/odp_timer.c +++ b/platform/linux-generic/odp_timer.c @@ -1332,15 +1332,28 @@ uint64_t odp_timer_current_tick(odp_timer_pool_t tpid) return current_nsec(tp); } -int odp_timer_pool_info(odp_timer_pool_t tpid, - odp_timer_pool_info_t *buf) +int odp_timer_pool_info(odp_timer_pool_t tpid, odp_timer_pool_info_t *tp_info) { - timer_pool_t *tp = timer_pool_from_hdl(tpid); + timer_pool_t *tp; + + if (odp_unlikely(tpid == ODP_TIMER_POOL_INVALID)) { + ODP_ERR("Invalid timer pool.\n"); + return -1; + } + + tp = timer_pool_from_hdl(tpid); + + memset(tp_info, 0, sizeof(odp_timer_pool_info_t)); + tp_info->param = tp->param; + tp_info->cur_timers = tp->num_alloc; + tp_info->hwm_timers = odp_atomic_load_u32(&tp->high_wm); + tp_info->name = tp->name; + + /* One API timer tick is one nsec. Leave source clock information to zero + * as there is no direct link between a source clock signal and a timer tick. */ + tp_info->tick_info.freq.integer = ODP_TIME_SEC_IN_NS; + tp_info->tick_info.nsec.integer = 1; - buf->param = tp->param; - buf->cur_timers = tp->num_alloc; - buf->hwm_timers = odp_atomic_load_u32(&tp->high_wm); - buf->name = tp->name; return 0; } diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index 5d5fead16..4841402aa 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -138,7 +138,8 @@ typedef struct ODP_ALIGNED_CACHE { struct rte_mempool *pkt_pool; /**< DPDK packet pool */ uint32_t data_room; /**< maximum packet length */ unsigned int min_rx_burst; /**< minimum RX burst size */ - odp_pktin_hash_proto_t hash; /**< Packet input hash protocol */ + /** RSS configuration */ + struct rte_eth_rss_conf rss_conf; /* Supported RTE_PTYPE_XXX flags in a mask */ uint32_t supported_ptypes; uint16_t mtu; /**< maximum transmission unit */ @@ -1131,7 +1132,7 @@ static int dpdk_vdev_promisc_mode_set(uint16_t port_id, int enable) return mode; } -static void rss_conf_to_hash_proto(struct rte_eth_rss_conf *rss_conf, +static void hash_proto_to_rss_conf(struct rte_eth_rss_conf *rss_conf, const odp_pktin_hash_proto_t *hash_proto) { if (hash_proto->proto.ipv4_udp) @@ -1154,34 +1155,19 @@ static void rss_conf_to_hash_proto(struct rte_eth_rss_conf *rss_conf, rss_conf->rss_key = NULL; } -static int dpdk_setup_eth_dev(pktio_entry_t *pktio_entry, - const struct rte_eth_dev_info *dev_info) +static int dpdk_setup_eth_dev(pktio_entry_t *pktio_entry) { int ret; pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); - struct rte_eth_rss_conf rss_conf; struct rte_eth_conf eth_conf; - uint64_t rss_hf_capa = dev_info->flow_type_rss_offloads; uint64_t rx_offloads = 0; uint64_t tx_offloads = 0; - memset(&rss_conf, 0, sizeof(struct rte_eth_rss_conf)); - - /* Always set some hash functions to enable DPDK RSS hash calculation. - * Hash capability has been checked in pktin config. */ - if (pkt_dpdk->hash.all_bits == 0) - rss_conf.rss_hf = ETH_RSS_IP | ETH_RSS_TCP | ETH_RSS_UDP; - else - rss_conf_to_hash_proto(&rss_conf, &pkt_dpdk->hash); - - /* Filter out unsupported flags */ - rss_conf.rss_hf &= rss_hf_capa; - memset(ð_conf, 0, sizeof(eth_conf)); eth_conf.rxmode.mq_mode = ETH_MQ_RX_RSS; eth_conf.txmode.mq_mode = ETH_MQ_TX_NONE; - eth_conf.rx_adv_conf.rss_conf = rss_conf; + eth_conf.rx_adv_conf.rss_conf = pkt_dpdk->rss_conf; /* Setup RX checksum offloads */ if (pktio_entry->s.config.pktin.bit.ipv4_chksum) @@ -1423,59 +1409,57 @@ static int dpdk_pktio_term(void) return 0; } -static int check_hash_proto(pktio_entry_t *pktio_entry, - const odp_pktin_queue_param_t *p) +static void prepare_rss_conf(pktio_entry_t *pktio_entry, + const odp_pktin_queue_param_t *p) { struct rte_eth_dev_info dev_info; uint64_t rss_hf_capa; pkt_dpdk_t *pkt_dpdk = pkt_priv(pktio_entry); uint16_t port_id = pkt_dpdk->port_id; + memset(&pkt_dpdk->rss_conf, 0, sizeof(struct rte_eth_rss_conf)); + + if (!p->hash_enable) + return; + rte_eth_dev_info_get(port_id, &dev_info); rss_hf_capa = dev_info.flow_type_rss_offloads; + /* Print debug info about unsupported hash protocols */ if (p->hash_proto.proto.ipv4 && - ((rss_hf_capa & ETH_RSS_IPV4) == 0)) { - ODP_ERR("hash_proto.ipv4 not supported\n"); - return -1; - } + ((rss_hf_capa & ETH_RSS_IPV4) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv4 not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv4_udp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_UDP) == 0)) { - ODP_ERR("hash_proto.ipv4_udp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_UDP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv4_udp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv4_tcp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_TCP) == 0)) { - ODP_ERR("hash_proto.ipv4_tcp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV4_TCP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv4_tcp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv6 && - ((rss_hf_capa & ETH_RSS_IPV6) == 0)) { - ODP_ERR("hash_proto.ipv6 not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_IPV6) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv6 not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv6_udp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_UDP) == 0)) { - ODP_ERR("hash_proto.ipv6_udp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_UDP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv6_udp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); if (p->hash_proto.proto.ipv6_tcp && - ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_TCP) == 0)) { - ODP_ERR("hash_proto.ipv6_tcp not supported. " - "rss_hf_capa 0x%" PRIx64 "\n", rss_hf_capa); - return -1; - } + ((rss_hf_capa & ETH_RSS_NONFRAG_IPV6_TCP) == 0)) + ODP_PRINT("DPDK: hash_proto.ipv6_tcp not supported (rss_hf_capa 0x%" PRIx64 ")\n", + rss_hf_capa); - return 0; + hash_proto_to_rss_conf(&pkt_dpdk->rss_conf, &p->hash_proto); + + /* Filter out unsupported hash functions */ + pkt_dpdk->rss_conf.rss_hf &= rss_hf_capa; } static int dpdk_input_queues_config(pktio_entry_t *pktio_entry, @@ -1484,8 +1468,7 @@ static int dpdk_input_queues_config(pktio_entry_t *pktio_entry, odp_pktin_mode_t mode = pktio_entry->s.param.in_mode; uint8_t lockless; - if (p->hash_enable && check_hash_proto(pktio_entry, p)) - return -1; + prepare_rss_conf(pktio_entry, p); /** * Scheduler synchronizes input queue polls. Only single thread @@ -1496,9 +1479,6 @@ static int dpdk_input_queues_config(pktio_entry_t *pktio_entry, else lockless = 0; - if (p->hash_enable && p->num_queues > 1) - pkt_priv(pktio_entry)->hash = p->hash_proto; - pkt_priv(pktio_entry)->lockless_rx = lockless; return 0; @@ -1633,6 +1613,21 @@ static int dpdk_init_capability(pktio_entry_t *pktio_entry, capa->config.pktout.bit.tcp_chksum; capa->config.pktout.bit.ts_ena = 1; + capa->stats.pktio.counter.in_octets = 1; + capa->stats.pktio.counter.in_packets = 1; + capa->stats.pktio.counter.in_discards = 1; + capa->stats.pktio.counter.in_errors = 1; + capa->stats.pktio.counter.out_octets = 1; + capa->stats.pktio.counter.out_packets = 1; + capa->stats.pktio.counter.out_errors = 1; + + capa->stats.pktin_queue.counter.octets = 1; + capa->stats.pktin_queue.counter.packets = 1; + capa->stats.pktin_queue.counter.errors = 1; + + capa->stats.pktout_queue.counter.octets = 1; + capa->stats.pktout_queue.counter.packets = 1; + return 0; } @@ -1811,6 +1806,17 @@ static int dpdk_setup_eth_tx(pktio_entry_t *pktio_entry, } } + /* Set per queue statistics mappings. Not supported by all PMDs, so + * ignore the return value. */ + for (i = 0; i < pktio_entry->s.num_out_queue && i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { + ret = rte_eth_dev_set_tx_queue_stats_mapping(port_id, i, i); + if (ret) { + ODP_DBG("Mapping per TX queue statistics not supported: %d\n", ret); + break; + } + } + ODP_DBG("Mapped %" PRIu32 "/%d TX counters\n", i, RTE_ETHDEV_QUEUE_STAT_CNTRS); + return 0; } @@ -1839,6 +1845,17 @@ static int dpdk_setup_eth_rx(const pktio_entry_t *pktio_entry, } } + /* Set per queue statistics mappings. Not supported by all PMDs, so + * ignore the return value. */ + for (i = 0; i < pktio_entry->s.num_in_queue && i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { + ret = rte_eth_dev_set_rx_queue_stats_mapping(port_id, i, i); + if (ret) { + ODP_DBG("Mapping per RX queue statistics not supported: %d\n", ret); + break; + } + } + ODP_DBG("Mapped %" PRIu32 "/%d RX counters\n", i, RTE_ETHDEV_QUEUE_STAT_CNTRS); + return 0; } @@ -1901,7 +1918,7 @@ static int dpdk_start(pktio_entry_t *pktio_entry) rte_eth_dev_info_get(port_id, &dev_info); /* Setup device */ - if (dpdk_setup_eth_dev(pktio_entry, &dev_info)) { + if (dpdk_setup_eth_dev(pktio_entry)) { ODP_ERR("Failed to configure device\n"); return -1; } @@ -2225,7 +2242,138 @@ static int dpdk_stats(pktio_entry_t *pktio_entry, odp_pktio_stats_t *stats) static int dpdk_stats_reset(pktio_entry_t *pktio_entry) { - rte_eth_stats_reset(pkt_priv(pktio_entry)->port_id); + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + + (void)rte_eth_stats_reset(port_id); + (void)rte_eth_xstats_reset(port_id); + return 0; +} + +static int dpdk_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num) +{ + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int num_stats, ret, i; + + num_stats = rte_eth_xstats_get_names(port_id, NULL, 0); + if (num_stats < 0) { + ODP_ERR("rte_eth_xstats_get_names() failed: %d\n", num_stats); + return num_stats; + } else if (info == NULL || num == 0 || num_stats == 0) { + return num_stats; + } + + struct rte_eth_xstat_name xstats_names[num_stats]; + + ret = rte_eth_xstats_get_names(port_id, xstats_names, num_stats); + if (ret < 0 || ret > num_stats) { + ODP_ERR("rte_eth_xstats_get_names() failed: %d\n", ret); + return -1; + } + num_stats = ret; + + for (i = 0; i < num && i < num_stats; i++) + strncpy(info[i].name, xstats_names[i].name, + ODP_PKTIO_STATS_EXTRA_NAME_LEN - 1); + + return num_stats; +} + +static int dpdk_extra_stats(pktio_entry_t *pktio_entry, + uint64_t stats[], int num) +{ + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + int num_stats, ret, i; + + num_stats = rte_eth_xstats_get(port_id, NULL, 0); + if (num_stats < 0) { + ODP_ERR("rte_eth_xstats_get() failed: %d\n", num_stats); + return num_stats; + } else if (stats == NULL || num == 0 || num_stats == 0) { + return num_stats; + } + + struct rte_eth_xstat xstats[num_stats]; + + ret = rte_eth_xstats_get(port_id, xstats, num_stats); + if (ret < 0 || ret > num_stats) { + ODP_ERR("rte_eth_xstats_get() failed: %d\n", ret); + return -1; + } + num_stats = ret; + + for (i = 0; i < num && i < num_stats; i++) + stats[i] = xstats[i].value; + + return num_stats; +} + +static int dpdk_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat) +{ + uint16_t port_id = pkt_priv(pktio_entry)->port_id; + uint64_t xstat_id = id; + int ret; + + ret = rte_eth_xstats_get_by_id(port_id, &xstat_id, stat, 1); + if (ret != 1) { + ODP_ERR("rte_eth_xstats_get_by_id() failed: %d\n", ret); + return -1; + } + + return 0; +} + +static int dpdk_pktin_stats(pktio_entry_t *pktio_entry, uint32_t index, + odp_pktin_queue_stats_t *pktin_stats) +{ + struct rte_eth_stats rte_stats; + int ret; + + if (odp_unlikely(index > RTE_ETHDEV_QUEUE_STAT_CNTRS - 1)) { + ODP_ERR("DPDK supports max %d per queue counters\n", + RTE_ETHDEV_QUEUE_STAT_CNTRS); + return -1; + } + + ret = rte_eth_stats_get(pkt_priv(pktio_entry)->port_id, &rte_stats); + if (odp_unlikely(ret)) { + ODP_ERR("Failed to read DPDK pktio stats: %d\n", ret); + return -1; + } + + memset(pktin_stats, 0, sizeof(odp_pktin_queue_stats_t)); + + pktin_stats->packets = rte_stats.q_ipackets[index]; + pktin_stats->octets = rte_stats.q_ibytes[index]; + pktin_stats->errors = rte_stats.q_errors[index]; + + return 0; +} + +static int dpdk_pktout_stats(pktio_entry_t *pktio_entry, uint32_t index, + odp_pktout_queue_stats_t *pktout_stats) +{ + struct rte_eth_stats rte_stats; + int ret; + + if (odp_unlikely(index > RTE_ETHDEV_QUEUE_STAT_CNTRS - 1)) { + ODP_ERR("DPDK supports max %d per queue counters\n", + RTE_ETHDEV_QUEUE_STAT_CNTRS); + return -1; + } + + ret = rte_eth_stats_get(pkt_priv(pktio_entry)->port_id, &rte_stats); + if (odp_unlikely(ret)) { + ODP_ERR("Failed to read DPDK pktio stats: %d\n", ret); + return -1; + } + + memset(pktout_stats, 0, sizeof(odp_pktout_queue_stats_t)); + + pktout_stats->packets = rte_stats.q_opackets[index]; + pktout_stats->octets = rte_stats.q_obytes[index]; + return 0; } @@ -2240,6 +2388,11 @@ const pktio_if_ops_t _odp_dpdk_pktio_ops = { .stop = dpdk_stop, .stats = dpdk_stats, .stats_reset = dpdk_stats_reset, + .pktin_queue_stats = dpdk_pktin_stats, + .pktout_queue_stats = dpdk_pktout_stats, + .extra_stat_info = dpdk_extra_stat_info, + .extra_stats = dpdk_extra_stats, + .extra_stat_counter = dpdk_extra_stat_counter, .recv = dpdk_recv, .send = dpdk_send, .link_status = dpdk_link_status, diff --git a/platform/linux-generic/pktio/dpdk_parse.c b/platform/linux-generic/pktio/dpdk_parse.c index 2b41b14a2..f593f4b11 100644 --- a/platform/linux-generic/pktio/dpdk_parse.c +++ b/platform/linux-generic/pktio/dpdk_parse.c @@ -8,6 +8,8 @@ #ifdef _ODP_PKTIO_DPDK +#include <odp_posix_extensions.h> + #include <odp_packet_io_internal.h> #include <odp_packet_dpdk.h> #include <odp/api/byteorder.h> @@ -98,7 +100,7 @@ static inline uint16_t dpdk_parse_eth(packet_parser_t *prs, goto error; } ethtype = odp_be_to_cpu_16(*((const uint16_t *)(uintptr_t) - (parseptr + 6))); + (*parseptr + 6))); *offset += 8; *parseptr += 8; } diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c index dd321511a..437977771 100644 --- a/platform/linux-generic/pktio/loop.c +++ b/platform/linux-generic/pktio/loop.c @@ -458,6 +458,16 @@ static int loopback_init_capability(pktio_entry_t *pktio_entry) capa->config.pktout.bit.sctp_chksum_ena = capa->config.pktout.bit.sctp_chksum; + capa->stats.pktio.counter.in_octets = 1; + capa->stats.pktio.counter.in_packets = 1; + capa->stats.pktio.counter.in_errors = 1; + capa->stats.pktio.counter.out_octets = 1; + capa->stats.pktio.counter.out_packets = 1; + capa->stats.pktin_queue.counter.octets = 1; + capa->stats.pktin_queue.counter.packets = 1; + capa->stats.pktin_queue.counter.errors = 1; + capa->stats.pktout_queue.counter.octets = 1; + capa->stats.pktout_queue.counter.packets = 1; return 0; } @@ -493,6 +503,27 @@ static int loopback_stats_reset(pktio_entry_t *pktio_entry ODP_UNUSED) return 0; } +static int loopback_pktin_stats(pktio_entry_t *pktio_entry, + uint32_t index ODP_UNUSED, + odp_pktin_queue_stats_t *pktin_stats) +{ + memset(pktin_stats, 0, sizeof(odp_pktin_queue_stats_t)); + pktin_stats->octets = pktio_entry->s.stats.in_octets; + pktin_stats->packets = pktio_entry->s.stats.in_packets; + pktin_stats->errors = pktio_entry->s.stats.in_errors; + return 0; +} + +static int loopback_pktout_stats(pktio_entry_t *pktio_entry, + uint32_t index ODP_UNUSED, + odp_pktout_queue_stats_t *pktout_stats) +{ + memset(pktout_stats, 0, sizeof(odp_pktout_queue_stats_t)); + pktout_stats->octets = pktio_entry->s.stats.out_octets; + pktout_stats->packets = pktio_entry->s.stats.out_packets; + return 0; +} + static int loop_init_global(void) { ODP_PRINT("PKTIO: initialized loop interface.\n"); @@ -511,6 +542,8 @@ const pktio_if_ops_t _odp_loopback_pktio_ops = { .stop = NULL, .stats = loopback_stats, .stats_reset = loopback_stats_reset, + .pktin_queue_stats = loopback_pktin_stats, + .pktout_queue_stats = loopback_pktout_stats, .recv = loopback_recv, .send = loopback_send, .maxlen_get = loopback_mtu_get, diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c index 544503aa3..18d9b3a33 100644 --- a/platform/linux-generic/pktio/netmap.c +++ b/platform/linux-generic/pktio/netmap.c @@ -637,6 +637,7 @@ static int netmap_open(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry, pktio_entry->s.stats_type = STATS_UNSUPPORTED; } else { pktio_entry->s.stats_type = STATS_ETHTOOL; + _odp_sock_stats_capa(pktio_entry, &pktio_entry->s.capa); } (void)netmap_stats_reset(pktio_entry); @@ -1249,6 +1250,27 @@ static int netmap_stats_reset(pktio_entry_t *pktio_entry) pkt_priv(pktio_entry)->sockfd); } +static int netmap_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num) +{ + return _odp_sock_extra_stat_info(pktio_entry, info, num, + pkt_priv(pktio_entry)->sockfd); +} + +static int netmap_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], + int num) +{ + return _odp_sock_extra_stats(pktio_entry, stats, num, + pkt_priv(pktio_entry)->sockfd); +} + +static int netmap_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat) +{ + return _odp_sock_extra_stat_counter(pktio_entry, id, stat, + pkt_priv(pktio_entry)->sockfd); +} + static void netmap_print(pktio_entry_t *pktio_entry) { odp_pktin_hash_proto_t hash_proto; @@ -1287,6 +1309,9 @@ const pktio_if_ops_t _odp_netmap_pktio_ops = { .link_info = netmap_link_info, .stats = netmap_stats, .stats_reset = netmap_stats_reset, + .extra_stat_info = netmap_extra_stat_info, + .extra_stats = netmap_extra_stats, + .extra_stat_counter = netmap_extra_stat_counter, .maxlen_get = netmap_mtu_get, .maxlen_set = netmap_mtu_set, .promisc_mode_set = netmap_promisc_mode_set, diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c index d4858903b..bf4c87c02 100644 --- a/platform/linux-generic/pktio/pcap.c +++ b/platform/linux-generic/pktio/pcap.c @@ -431,6 +431,11 @@ static int pcapif_capability(pktio_entry_t *pktio_entry ODP_UNUSED, capa->config.pktout.bit.ts_ena = 1; + capa->stats.pktio.counter.in_octets = 1; + capa->stats.pktio.counter.in_packets = 1; + capa->stats.pktio.counter.out_octets = 1; + capa->stats.pktio.counter.out_packets = 1; + return 0; } diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c index eb4390e46..291ee543f 100644 --- a/platform/linux-generic/pktio/socket.c +++ b/platform/linux-generic/pktio/socket.c @@ -526,7 +526,7 @@ static int sock_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t *inf return _odp_link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info); } -static int sock_capability(pktio_entry_t *pktio_entry ODP_UNUSED, +static int sock_capability(pktio_entry_t *pktio_entry, odp_pktio_capability_t *capa) { pkt_sock_t *pkt_sock = pkt_priv(pktio_entry); @@ -550,6 +550,9 @@ static int sock_capability(pktio_entry_t *pktio_entry ODP_UNUSED, capa->config.pktout.bit.ts_ena = 1; + /* Fill statistics capabilities */ + _odp_sock_stats_capa(pktio_entry, capa); + return 0; } @@ -575,6 +578,28 @@ static int sock_stats_reset(pktio_entry_t *pktio_entry) return _odp_sock_stats_reset_fd(pktio_entry, pkt_priv(pktio_entry)->sockfd); } +static int sock_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], + int num) +{ + return _odp_sock_extra_stat_info(pktio_entry, info, num, + pkt_priv(pktio_entry)->sockfd); +} + +static int sock_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], + int num) +{ + return _odp_sock_extra_stats(pktio_entry, stats, num, + pkt_priv(pktio_entry)->sockfd); +} + +static int sock_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat) +{ + return _odp_sock_extra_stat_counter(pktio_entry, id, stat, + pkt_priv(pktio_entry)->sockfd); +} + static int sock_init_global(void) { if (getenv("ODP_PKTIO_DISABLE_SOCKET_MMSG")) { @@ -600,6 +625,9 @@ const pktio_if_ops_t _odp_sock_mmsg_pktio_ops = { .stop = NULL, .stats = sock_stats, .stats_reset = sock_stats_reset, + .extra_stat_info = sock_extra_stat_info, + .extra_stats = sock_extra_stats, + .extra_stat_counter = sock_extra_stat_counter, .recv = sock_mmsg_recv, .recv_tmo = sock_recv_tmo, .recv_mq_tmo = sock_recv_mq_tmo, diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c index 532f392fa..93984af4f 100644 --- a/platform/linux-generic/pktio/socket_mmap.c +++ b/platform/linux-generic/pktio/socket_mmap.c @@ -841,7 +841,7 @@ static int sock_mmap_link_info(pktio_entry_t *pktio_entry, odp_pktio_link_info_t return _odp_link_info_fd(pkt_priv(pktio_entry)->sockfd, pktio_entry->s.name, info); } -static int sock_mmap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, +static int sock_mmap_capability(pktio_entry_t *pktio_entry, odp_pktio_capability_t *capa) { pkt_sock_mmap_t *const pkt_sock = pkt_priv(pktio_entry); @@ -865,6 +865,9 @@ static int sock_mmap_capability(pktio_entry_t *pktio_entry ODP_UNUSED, capa->config.pktout.bit.ts_ena = 1; + /* Fill statistics capabilities */ + _odp_sock_stats_capa(pktio_entry, capa); + return 0; } @@ -893,6 +896,28 @@ static int sock_mmap_stats_reset(pktio_entry_t *pktio_entry) pkt_priv(pktio_entry)->sockfd); } +static int sock_mmap_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], + int num) +{ + return _odp_sock_extra_stat_info(pktio_entry, info, num, + pkt_priv(pktio_entry)->sockfd); +} + +static int sock_mmap_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], + int num) +{ + return _odp_sock_extra_stats(pktio_entry, stats, num, + pkt_priv(pktio_entry)->sockfd); +} + +static int sock_mmap_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat) +{ + return _odp_sock_extra_stat_counter(pktio_entry, id, stat, + pkt_priv(pktio_entry)->sockfd); +} + static int sock_mmap_init_global(void) { if (getenv("ODP_PKTIO_DISABLE_SOCKET_MMAP")) { @@ -918,6 +943,9 @@ const pktio_if_ops_t _odp_sock_mmap_pktio_ops = { .stop = NULL, .stats = sock_mmap_stats, .stats_reset = sock_mmap_stats_reset, + .extra_stat_info = sock_mmap_extra_stat_info, + .extra_stats = sock_mmap_extra_stats, + .extra_stat_counter = sock_mmap_extra_stat_counter, .recv = sock_mmap_recv, .recv_tmo = sock_mmap_recv_tmo, .recv_mq_tmo = sock_mmap_recv_mq_tmo, diff --git a/platform/linux-generic/pktio/stats/ethtool_stats.c b/platform/linux-generic/pktio/stats/ethtool_stats.c index e4f99e331..d8b6a7976 100644 --- a/platform/linux-generic/pktio/stats/ethtool_stats.c +++ b/platform/linux-generic/pktio/stats/ethtool_stats.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -83,15 +84,21 @@ static struct ethtool_gstrings *get_stringset(int fd, struct ifreq *ifr) return strings; } -static int ethtool_stats(int fd, struct ifreq *ifr, odp_pktio_stats_t *stats) +static int ethtool_stats_get(int fd, const char *name, + struct ethtool_gstrings **strings_out, + struct ethtool_stats **estats_out, + unsigned int *nstats_out) { struct ethtool_gstrings *strings; struct ethtool_stats *estats; - unsigned int n_stats, i; + struct ifreq ifr; + unsigned int n_stats; int err; - int cnts; - strings = get_stringset(fd, ifr); + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name); + + strings = get_stringset(fd, &ifr); if (!strings) return -1; @@ -111,8 +118,8 @@ static int ethtool_stats(int fd, struct ifreq *ifr, odp_pktio_stats_t *stats) estats->cmd = ETHTOOL_GSTATS; estats->n_stats = n_stats; - ifr->ifr_data = (void *)estats; - err = ioctl(fd, SIOCETHTOOL, ifr); + ifr.ifr_data = (void *)estats; + err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { _odp_errno = errno; free(strings); @@ -120,36 +127,83 @@ static int ethtool_stats(int fd, struct ifreq *ifr, odp_pktio_stats_t *stats) return -1; } - cnts = 0; + if (strings_out) + *strings_out = strings; + else + free(strings); + + if (estats_out) + *estats_out = estats; + else + free(estats); + + if (nstats_out) + *nstats_out = n_stats; + + return 0; +} + +int _odp_ethtool_stats_get_fd(int fd, const char *name, odp_pktio_stats_t *stats) +{ + struct ethtool_gstrings *strings; + struct ethtool_stats *estats; + unsigned int i, n_stats; + int cnts = 0; + + if (ethtool_stats_get(fd, name, &strings, &estats, &n_stats)) + return -1; + for (i = 0; i < n_stats; i++) { char *cnt = (char *)&strings->data[i * ETH_GSTRING_LEN]; uint64_t val = estats->data[i]; - if (!strcmp(cnt, "rx_octets")) { + if (!strcmp(cnt, "rx_octets") || + !strcmp(cnt, "rx_bytes")) { stats->in_octets = val; cnts++; } else if (!strcmp(cnt, "rx_packets")) { stats->in_packets = val; cnts++; - } else if (!strcmp(cnt, "rx_ucast_packets")) { + } else if (!strcmp(cnt, "rx_ucast_packets") || + !strcmp(cnt, "rx_unicast")) { stats->in_ucast_pkts = val; cnts++; - } else if (!strcmp(cnt, "rx_discards")) { + } else if (!strcmp(cnt, "rx_broadcast") || + !strcmp(cnt, "rx_bcast_packets")) { + stats->in_bcast_pkts = val; + cnts++; + } else if (!strcmp(cnt, "rx_multicast") || + !strcmp(cnt, "rx_mcast_packets")) { + stats->in_mcast_pkts = val; + cnts++; + } else if (!strcmp(cnt, "rx_discards") || + !strcmp(cnt, "rx_dropped")) { stats->in_discards = val; cnts++; } else if (!strcmp(cnt, "rx_errors")) { stats->in_errors = val; cnts++; - } else if (!strcmp(cnt, "tx_octets")) { + } else if (!strcmp(cnt, "tx_octets") || + !strcmp(cnt, "tx_bytes")) { stats->out_octets = val; cnts++; } else if (!strcmp(cnt, "tx_packets")) { stats->out_packets = val; cnts++; - } else if (!strcmp(cnt, "tx_ucast_packets")) { + } else if (!strcmp(cnt, "tx_ucast_packets") || + !strcmp(cnt, "tx_unicast")) { stats->out_ucast_pkts = val; cnts++; - } else if (!strcmp(cnt, "tx_discards")) { + } else if (!strcmp(cnt, "tx_broadcast") || + !strcmp(cnt, "tx_bcast_packets")) { + stats->out_bcast_pkts = val; + cnts++; + } else if (!strcmp(cnt, "tx_multicast") || + !strcmp(cnt, "tx_mcast_packets")) { + stats->out_mcast_pkts = val; + cnts++; + } else if (!strcmp(cnt, "tx_discards") || + !strcmp(cnt, "tx_dropped")) { stats->out_discards = val; cnts++; } else if (!strcmp(cnt, "tx_errors")) { @@ -164,18 +218,66 @@ static int ethtool_stats(int fd, struct ifreq *ifr, odp_pktio_stats_t *stats) /* Ethtool strings came from kernel driver. Name of that * strings is not universal. Current function needs to be updated * if your driver has different names for counters */ - if (cnts < 8) + if (cnts < 14) return -1; return 0; } -int _odp_ethtool_stats_get_fd(int fd, const char *name, odp_pktio_stats_t *stats) +int _odp_ethtool_extra_stat_info(int fd, const char *name, + odp_pktio_extra_stat_info_t info[], int num) { - struct ifreq ifr; + struct ethtool_gstrings *strings; + unsigned int i, n_stats; - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name); + if (ethtool_stats_get(fd, name, &strings, NULL, &n_stats)) + return -1; + + for (i = 0; i < n_stats && i < (unsigned int)num; i++) { + char *cnt = (char *)&strings->data[i * ETH_GSTRING_LEN]; + + strncpy(info[i].name, cnt, ODP_PKTIO_STATS_EXTRA_NAME_LEN - 1); + } + + free(strings); + + return n_stats; +} + +int _odp_ethtool_extra_stats(int fd, const char *name, uint64_t stats[], int num) +{ + struct ethtool_stats *estats; + unsigned int i, n_stats; + + if (ethtool_stats_get(fd, name, NULL, &estats, &n_stats)) + return -1; + + for (i = 0; i < n_stats && i < (unsigned int)num; i++) + stats[i] = estats->data[i]; + + free(estats); + + return n_stats; +} + +int _odp_ethtool_extra_stat_counter(int fd, const char *name, uint32_t id, + uint64_t *stat) +{ + struct ethtool_stats *estats; + unsigned int n_stats; + int ret = 0; + + if (ethtool_stats_get(fd, name, NULL, &estats, &n_stats)) + return -1; + + if (id >= n_stats) { + ODP_ERR("Invalid counter id\n"); + ret = -1; + } else { + *stat = estats->data[id]; + } + + free(estats); - return ethtool_stats(fd, &ifr, stats); + return ret; } diff --git a/platform/linux-generic/pktio/stats/packet_io_stats.c b/platform/linux-generic/pktio/stats/packet_io_stats.c index e8d4d9a62..3dd0d8be9 100644 --- a/platform/linux-generic/pktio/stats/packet_io_stats.c +++ b/platform/linux-generic/pktio/stats/packet_io_stats.c @@ -1,4 +1,5 @@ /* Copyright (c) 2014-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -66,6 +67,10 @@ int _odp_sock_stats_fd(pktio_entry_t *pktio_entry, pktio_entry->s.stats.in_packets; stats->in_ucast_pkts = cur_stats.in_ucast_pkts - pktio_entry->s.stats.in_ucast_pkts; + stats->in_bcast_pkts = cur_stats.in_bcast_pkts - + pktio_entry->s.stats.in_bcast_pkts; + stats->in_mcast_pkts = cur_stats.in_mcast_pkts - + pktio_entry->s.stats.in_mcast_pkts; stats->in_discards = cur_stats.in_discards - pktio_entry->s.stats.in_discards; stats->in_errors = cur_stats.in_errors - @@ -80,6 +85,10 @@ int _odp_sock_stats_fd(pktio_entry_t *pktio_entry, pktio_entry->s.stats.out_packets; stats->out_ucast_pkts = cur_stats.out_ucast_pkts - pktio_entry->s.stats.out_ucast_pkts; + stats->out_bcast_pkts = cur_stats.out_bcast_pkts - + pktio_entry->s.stats.out_bcast_pkts; + stats->out_mcast_pkts = cur_stats.out_mcast_pkts - + pktio_entry->s.stats.out_mcast_pkts; stats->out_discards = cur_stats.out_discards - pktio_entry->s.stats.out_discards; stats->out_errors = cur_stats.out_errors - @@ -88,6 +97,53 @@ int _odp_sock_stats_fd(pktio_entry_t *pktio_entry, return ret; } +int _odp_sock_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num, + int fd) +{ + if (pktio_entry->s.stats_type == STATS_UNSUPPORTED) + return 0; + + if (pktio_entry->s.stats_type == STATS_ETHTOOL) + return _odp_ethtool_extra_stat_info(fd, pktio_entry->s.name, + info, num); + else if (pktio_entry->s.stats_type == STATS_SYSFS) + return _odp_sysfs_extra_stat_info(pktio_entry, info, num); + + return 0; +} + +int _odp_sock_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], int num, + int fd) +{ + if (pktio_entry->s.stats_type == STATS_UNSUPPORTED) + return 0; + + if (pktio_entry->s.stats_type == STATS_ETHTOOL) + return _odp_ethtool_extra_stats(fd, pktio_entry->s.name, + stats, num); + else if (pktio_entry->s.stats_type == STATS_SYSFS) + return _odp_sysfs_extra_stats(pktio_entry, stats, num); + + return 0; +} + +int _odp_sock_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat, int fd) +{ + if (pktio_entry->s.stats_type == STATS_UNSUPPORTED) + return -1; + + if (pktio_entry->s.stats_type == STATS_ETHTOOL) { + return _odp_ethtool_extra_stat_counter(fd, pktio_entry->s.name, + id, stat); + } else if (pktio_entry->s.stats_type == STATS_SYSFS) { + return _odp_sysfs_extra_stat_counter(pktio_entry, id, stat); + } + + return 0; +} + pktio_stats_type_t _odp_sock_stats_type_fd(pktio_entry_t *pktio_entry, int fd) { odp_pktio_stats_t cur_stats; @@ -100,3 +156,40 @@ pktio_stats_type_t _odp_sock_stats_type_fd(pktio_entry_t *pktio_entry, int fd) return STATS_UNSUPPORTED; } + +void _odp_sock_stats_capa(pktio_entry_t *pktio_entry, + odp_pktio_capability_t *capa) +{ + capa->stats.pktio.all_counters = 0; + capa->stats.pktin_queue.all_counters = 0; + capa->stats.pktout_queue.all_counters = 0; + + if (pktio_entry->s.stats_type == STATS_SYSFS) { + capa->stats.pktio.counter.in_octets = 1; + capa->stats.pktio.counter.in_packets = 1; + capa->stats.pktio.counter.in_ucast_pkts = 1; + capa->stats.pktio.counter.in_mcast_pkts = 1; + capa->stats.pktio.counter.in_discards = 1; + capa->stats.pktio.counter.in_errors = 1; + capa->stats.pktio.counter.out_octets = 1; + capa->stats.pktio.counter.out_packets = 1; + capa->stats.pktio.counter.out_ucast_pkts = 1; + capa->stats.pktio.counter.out_discards = 1; + capa->stats.pktio.counter.out_errors = 1; + } else if (pktio_entry->s.stats_type == STATS_ETHTOOL) { + capa->stats.pktio.counter.in_octets = 1; + capa->stats.pktio.counter.in_packets = 1; + capa->stats.pktio.counter.in_ucast_pkts = 1; + capa->stats.pktio.counter.in_bcast_pkts = 1; + capa->stats.pktio.counter.in_mcast_pkts = 1; + capa->stats.pktio.counter.in_discards = 1; + capa->stats.pktio.counter.in_errors = 1; + capa->stats.pktio.counter.out_octets = 1; + capa->stats.pktio.counter.out_packets = 1; + capa->stats.pktio.counter.out_ucast_pkts = 1; + capa->stats.pktio.counter.out_bcast_pkts = 1; + capa->stats.pktio.counter.out_mcast_pkts = 1; + capa->stats.pktio.counter.out_discards = 1; + capa->stats.pktio.counter.out_errors = 1; + } +} diff --git a/platform/linux-generic/pktio/stats/sysfs_stats.c b/platform/linux-generic/pktio/stats/sysfs_stats.c index 1150f9d72..21620013e 100644 --- a/platform/linux-generic/pktio/stats/sysfs_stats.c +++ b/platform/linux-generic/pktio/stats/sysfs_stats.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2018, Linaro Limited + * Copyright (c) 2021, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -7,9 +8,13 @@ #include <odp_api.h> #include <odp_sysfs_stats.h> #include <odp_errno_define.h> +#include <dirent.h> #include <errno.h> #include <string.h> #include <inttypes.h> +#include <linux/limits.h> + +#define SYSFS_DIR "/sys/class/net/%s/statistics" static int sysfs_get_val(const char *fname, uint64_t *val) { @@ -57,7 +62,10 @@ int _odp_sysfs_stats(pktio_entry_t *pktio_entry, sprintf(fname, "/sys/class/net/%s/statistics/rx_packets", dev); ret -= sysfs_get_val(fname, &stats->in_ucast_pkts); - sprintf(fname, "/sys/class/net/%s/statistics/rx_droppped", dev); + sprintf(fname, "/sys/class/net/%s/statistics/multicast", dev); + ret -= sysfs_get_val(fname, &stats->in_mcast_pkts); + + sprintf(fname, "/sys/class/net/%s/statistics/rx_dropped", dev); ret -= sysfs_get_val(fname, &stats->in_discards); sprintf(fname, "/sys/class/net/%s/statistics/rx_errors", dev); @@ -80,3 +88,116 @@ int _odp_sysfs_stats(pktio_entry_t *pktio_entry, return ret; } + +int _odp_sysfs_extra_stat_info(pktio_entry_t *pktio_entry, + odp_pktio_extra_stat_info_t info[], int num) +{ + struct dirent *e; + DIR *dir; + char sysfs_dir[PATH_MAX]; + int counters = 0; + + snprintf(sysfs_dir, PATH_MAX, SYSFS_DIR, pktio_entry->s.name); + dir = opendir(sysfs_dir); + if (!dir) { + ODP_ERR("Failed to open sysfs dir: %s\n", sysfs_dir); + return -1; + } + + while ((e = readdir(dir)) != NULL) { + /* Skip . and .. */ + if (strncmp(e->d_name, ".", 1) == 0) + continue; + + if (info && counters < num) + snprintf(info[counters].name, + ODP_PKTIO_STATS_EXTRA_NAME_LEN, "%s", + e->d_name); + counters++; + } + (void)closedir(dir); + + return counters; +} + +int _odp_sysfs_extra_stats(pktio_entry_t *pktio_entry, uint64_t stats[], + int num) +{ + struct dirent *e; + DIR *dir; + char sysfs_dir[PATH_MAX]; + char file_path[PATH_MAX]; + int counters = 0; + + snprintf(sysfs_dir, PATH_MAX, SYSFS_DIR, pktio_entry->s.name); + dir = opendir(sysfs_dir); + if (!dir) { + ODP_ERR("Failed to open dir: %s\n", sysfs_dir); + return -1; + } + + while ((e = readdir(dir)) != NULL) { + uint64_t val; + + /* Skip . and .. */ + if (strncmp(e->d_name, ".", 1) == 0) + continue; + + snprintf(file_path, PATH_MAX, "%s/%s", sysfs_dir, e->d_name); + if (sysfs_get_val(file_path, &val)) { + ODP_ERR("Failed to read file: %s/n", file_path); + counters = -1; + break; + } + + if (stats && counters < num) + stats[counters] = val; + + counters++; + } + (void)closedir(dir); + + return counters; +} + +int _odp_sysfs_extra_stat_counter(pktio_entry_t *pktio_entry, uint32_t id, + uint64_t *stat) +{ + struct dirent *e; + DIR *dir; + char sysfs_dir[PATH_MAX]; + char file_path[PATH_MAX]; + uint32_t counters = 0; + int ret = -1; + + snprintf(sysfs_dir, PATH_MAX, SYSFS_DIR, pktio_entry->s.name); + dir = opendir(sysfs_dir); + if (!dir) { + ODP_ERR("Failed to open dir: %s\n", sysfs_dir); + return -1; + } + + while ((e = readdir(dir)) != NULL) { + /* Skip . and .. */ + if (strncmp(e->d_name, ".", 1) == 0) + continue; + + if (counters == id) { + uint64_t val; + + snprintf(file_path, PATH_MAX, "%s/%s", + sysfs_dir, e->d_name); + if (sysfs_get_val(file_path, &val)) { + ODP_ERR("Failed to read file: %s/n", file_path); + } else { + *stat = val; + ret = 0; + } + break; + } + counters++; + } + (void)closedir(dir); + + return ret; +} diff --git a/platform/linux-generic/test/example/ipsec_api/pktio_env b/platform/linux-generic/test/example/ipsec_api/pktio_env index a16002326..abf6b5ce3 100644 --- a/platform/linux-generic/test/example/ipsec_api/pktio_env +++ b/platform/linux-generic/test/example/ipsec_api/pktio_env @@ -35,6 +35,12 @@ if [ -n "$WITH_OPENSSL" ] && [ ${WITH_OPENSSL} -eq 0 ]; then exit 77 fi +# Skip live and router mode tests. +if [ ${IPSEC_APP_MODE} -eq 1 ] || [ ${IPSEC_APP_MODE} -eq 2 ]; then + echo "IPsec Live / Router mode test. Skipping." + exit 77 +fi + IF0=p7p1 IF1=p8p1 |