aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic')
-rw-r--r--platform/linux-generic/Makefile.am1
-rw-r--r--platform/linux-generic/include-abi/odp/api/abi/packet_io.h2
-rw-r--r--platform/linux-generic/include/odp_ethtool_stats.h6
-rw-r--r--platform/linux-generic/include/odp_ipsec_internal.h42
-rw-r--r--platform/linux-generic/include/odp_packet_io_internal.h10
-rw-r--r--platform/linux-generic/include/odp_packet_io_stats.h12
-rw-r--r--platform/linux-generic/include/odp_schedule_if.h1
-rw-r--r--platform/linux-generic/include/odp_sysfs_stats.h8
-rw-r--r--platform/linux-generic/m4/odp_dpdk.m413
-rw-r--r--platform/linux-generic/odp_classification.c2
-rw-r--r--platform/linux-generic/odp_fractional.c19
-rw-r--r--platform/linux-generic/odp_ipsec.c3
-rw-r--r--platform/linux-generic/odp_ipsec_sad.c131
-rw-r--r--platform/linux-generic/odp_packet_io.c285
-rw-r--r--platform/linux-generic/odp_schedule_basic.c270
-rw-r--r--platform/linux-generic/odp_schedule_if.c5
-rw-r--r--platform/linux-generic/odp_schedule_scalable.c17
-rw-r--r--platform/linux-generic/odp_schedule_sp.c21
-rw-r--r--platform/linux-generic/odp_timer.c27
-rw-r--r--platform/linux-generic/pktio/dpdk.c269
-rw-r--r--platform/linux-generic/pktio/dpdk_parse.c4
-rw-r--r--platform/linux-generic/pktio/loop.c33
-rw-r--r--platform/linux-generic/pktio/netmap.c25
-rw-r--r--platform/linux-generic/pktio/pcap.c5
-rw-r--r--platform/linux-generic/pktio/socket.c30
-rw-r--r--platform/linux-generic/pktio/socket_mmap.c30
-rw-r--r--platform/linux-generic/pktio/stats/ethtool_stats.c140
-rw-r--r--platform/linux-generic/pktio/stats/packet_io_stats.c93
-rw-r--r--platform/linux-generic/pktio/stats/sysfs_stats.c123
-rw-r--r--platform/linux-generic/test/example/ipsec_api/pktio_env6
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(&eth_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