xref: /dpdk/lib/pdump/rte_pdump.c (revision 53caecb8445b3dce4cb7bae235ad6023a828577c)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2016-2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <rte_memcpy.h>
699a2dd95SBruce Richardson #include <rte_mbuf.h>
799a2dd95SBruce Richardson #include <rte_ethdev.h>
899a2dd95SBruce Richardson #include <rte_lcore.h>
999a2dd95SBruce Richardson #include <rte_log.h>
1010f726efSStephen Hemminger #include <rte_memzone.h>
1199a2dd95SBruce Richardson #include <rte_errno.h>
1299a2dd95SBruce Richardson #include <rte_string_fns.h>
1310f726efSStephen Hemminger #include <rte_pcapng.h>
1499a2dd95SBruce Richardson 
1599a2dd95SBruce Richardson #include "rte_pdump.h"
1699a2dd95SBruce Richardson 
17eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(pdump_logtype, NOTICE);
1899a2dd95SBruce Richardson 
1999a2dd95SBruce Richardson /* Macro for printing using RTE_LOG */
2099a2dd95SBruce Richardson #define PDUMP_LOG(level, fmt, args...)				\
2199a2dd95SBruce Richardson 	rte_log(RTE_LOG_ ## level, pdump_logtype, "%s(): " fmt,	\
2299a2dd95SBruce Richardson 		__func__, ## args)
2399a2dd95SBruce Richardson 
2499a2dd95SBruce Richardson /* Used for the multi-process communication */
2599a2dd95SBruce Richardson #define PDUMP_MP	"mp_pdump"
2699a2dd95SBruce Richardson 
2799a2dd95SBruce Richardson enum pdump_operation {
2899a2dd95SBruce Richardson 	DISABLE = 1,
2999a2dd95SBruce Richardson 	ENABLE = 2
3099a2dd95SBruce Richardson };
3199a2dd95SBruce Richardson 
3210f726efSStephen Hemminger /* Internal version number in request */
3399a2dd95SBruce Richardson enum pdump_version {
3410f726efSStephen Hemminger 	V1 = 1,		    /* no filtering or snap */
3510f726efSStephen Hemminger 	V2 = 2,
3699a2dd95SBruce Richardson };
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson struct pdump_request {
3999a2dd95SBruce Richardson 	uint16_t ver;
4099a2dd95SBruce Richardson 	uint16_t op;
4199a2dd95SBruce Richardson 	uint32_t flags;
4299a2dd95SBruce Richardson 	char device[RTE_DEV_NAME_MAX_LEN];
4399a2dd95SBruce Richardson 	uint16_t queue;
4499a2dd95SBruce Richardson 	struct rte_ring *ring;
4599a2dd95SBruce Richardson 	struct rte_mempool *mp;
4610f726efSStephen Hemminger 
4710f726efSStephen Hemminger 	const struct rte_bpf_prm *prm;
4810f726efSStephen Hemminger 	uint32_t snaplen;
4999a2dd95SBruce Richardson };
5099a2dd95SBruce Richardson 
5199a2dd95SBruce Richardson struct pdump_response {
5299a2dd95SBruce Richardson 	uint16_t ver;
5399a2dd95SBruce Richardson 	uint16_t res_op;
5499a2dd95SBruce Richardson 	int32_t err_value;
5599a2dd95SBruce Richardson };
5699a2dd95SBruce Richardson 
5799a2dd95SBruce Richardson static struct pdump_rxtx_cbs {
5899a2dd95SBruce Richardson 	struct rte_ring *ring;
5999a2dd95SBruce Richardson 	struct rte_mempool *mp;
6099a2dd95SBruce Richardson 	const struct rte_eth_rxtx_callback *cb;
6110f726efSStephen Hemminger 	const struct rte_bpf *filter;
6210f726efSStephen Hemminger 	enum pdump_version ver;
6310f726efSStephen Hemminger 	uint32_t snaplen;
6499a2dd95SBruce Richardson } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
6599a2dd95SBruce Richardson tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
6699a2dd95SBruce Richardson 
6799a2dd95SBruce Richardson 
6810f726efSStephen Hemminger /*
6910f726efSStephen Hemminger  * The packet capture statistics keep track of packets
7010f726efSStephen Hemminger  * accepted, filtered and dropped. These are per-queue
7110f726efSStephen Hemminger  * and in memory between primary and secondary processes.
7210f726efSStephen Hemminger  */
7310f726efSStephen Hemminger static const char MZ_RTE_PDUMP_STATS[] = "rte_pdump_stats";
7410f726efSStephen Hemminger static struct {
7510f726efSStephen Hemminger 	struct rte_pdump_stats rx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
7610f726efSStephen Hemminger 	struct rte_pdump_stats tx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
77*53caecb8SKonstantin Ananyev 	const struct rte_memzone *mz;
7810f726efSStephen Hemminger } *pdump_stats;
7910f726efSStephen Hemminger 
8010f726efSStephen Hemminger /* Create a clone of mbuf to be placed into ring. */
8110f726efSStephen Hemminger static void
8210f726efSStephen Hemminger pdump_copy(uint16_t port_id, uint16_t queue,
8310f726efSStephen Hemminger 	   enum rte_pcapng_direction direction,
8410f726efSStephen Hemminger 	   struct rte_mbuf **pkts, uint16_t nb_pkts,
8510f726efSStephen Hemminger 	   const struct pdump_rxtx_cbs *cbs,
8610f726efSStephen Hemminger 	   struct rte_pdump_stats *stats)
8799a2dd95SBruce Richardson {
8899a2dd95SBruce Richardson 	unsigned int i;
8999a2dd95SBruce Richardson 	int ring_enq;
9099a2dd95SBruce Richardson 	uint16_t d_pkts = 0;
9199a2dd95SBruce Richardson 	struct rte_mbuf *dup_bufs[nb_pkts];
9210f726efSStephen Hemminger 	uint64_t ts;
9399a2dd95SBruce Richardson 	struct rte_ring *ring;
9499a2dd95SBruce Richardson 	struct rte_mempool *mp;
9599a2dd95SBruce Richardson 	struct rte_mbuf *p;
9610f726efSStephen Hemminger 	uint64_t rcs[nb_pkts];
9799a2dd95SBruce Richardson 
9810f726efSStephen Hemminger 	if (cbs->filter)
9910f726efSStephen Hemminger 		rte_bpf_exec_burst(cbs->filter, (void **)pkts, rcs, nb_pkts);
10010f726efSStephen Hemminger 
10110f726efSStephen Hemminger 	ts = rte_get_tsc_cycles();
10299a2dd95SBruce Richardson 	ring = cbs->ring;
10399a2dd95SBruce Richardson 	mp = cbs->mp;
10499a2dd95SBruce Richardson 	for (i = 0; i < nb_pkts; i++) {
10510f726efSStephen Hemminger 		/*
10610f726efSStephen Hemminger 		 * This uses same BPF return value convention as socket filter
10710f726efSStephen Hemminger 		 * and pcap_offline_filter.
10810f726efSStephen Hemminger 		 * if program returns zero
10910f726efSStephen Hemminger 		 * then packet doesn't match the filter (will be ignored).
11010f726efSStephen Hemminger 		 */
11110f726efSStephen Hemminger 		if (cbs->filter && rcs[i] == 0) {
11210f726efSStephen Hemminger 			__atomic_fetch_add(&stats->filtered,
11310f726efSStephen Hemminger 					   1, __ATOMIC_RELAXED);
11410f726efSStephen Hemminger 			continue;
11510f726efSStephen Hemminger 		}
11610f726efSStephen Hemminger 
11710f726efSStephen Hemminger 		/*
11810f726efSStephen Hemminger 		 * If using pcapng then want to wrap packets
11910f726efSStephen Hemminger 		 * otherwise a simple copy.
12010f726efSStephen Hemminger 		 */
12110f726efSStephen Hemminger 		if (cbs->ver == V2)
12210f726efSStephen Hemminger 			p = rte_pcapng_copy(port_id, queue,
12310f726efSStephen Hemminger 					    pkts[i], mp, cbs->snaplen,
12410f726efSStephen Hemminger 					    ts, direction);
12510f726efSStephen Hemminger 		else
12610f726efSStephen Hemminger 			p = rte_pktmbuf_copy(pkts[i], mp, 0, cbs->snaplen);
12710f726efSStephen Hemminger 
12810f726efSStephen Hemminger 		if (unlikely(p == NULL))
12910f726efSStephen Hemminger 			__atomic_fetch_add(&stats->nombuf, 1, __ATOMIC_RELAXED);
13010f726efSStephen Hemminger 		else
13199a2dd95SBruce Richardson 			dup_bufs[d_pkts++] = p;
13299a2dd95SBruce Richardson 	}
13399a2dd95SBruce Richardson 
13410f726efSStephen Hemminger 	__atomic_fetch_add(&stats->accepted, d_pkts, __ATOMIC_RELAXED);
13510f726efSStephen Hemminger 
13699a2dd95SBruce Richardson 	ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL);
13799a2dd95SBruce Richardson 	if (unlikely(ring_enq < d_pkts)) {
13899a2dd95SBruce Richardson 		unsigned int drops = d_pkts - ring_enq;
13999a2dd95SBruce Richardson 
14010f726efSStephen Hemminger 		__atomic_fetch_add(&stats->ringfull, drops, __ATOMIC_RELAXED);
14199a2dd95SBruce Richardson 		rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops);
14299a2dd95SBruce Richardson 	}
14399a2dd95SBruce Richardson }
14499a2dd95SBruce Richardson 
14599a2dd95SBruce Richardson static uint16_t
14610f726efSStephen Hemminger pdump_rx(uint16_t port, uint16_t queue,
14799a2dd95SBruce Richardson 	struct rte_mbuf **pkts, uint16_t nb_pkts,
14810f726efSStephen Hemminger 	uint16_t max_pkts __rte_unused, void *user_params)
14999a2dd95SBruce Richardson {
15010f726efSStephen Hemminger 	const struct pdump_rxtx_cbs *cbs = user_params;
15110f726efSStephen Hemminger 	struct rte_pdump_stats *stats = &pdump_stats->rx[port][queue];
15210f726efSStephen Hemminger 
15310f726efSStephen Hemminger 	pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_IN,
15410f726efSStephen Hemminger 		   pkts, nb_pkts, cbs, stats);
15599a2dd95SBruce Richardson 	return nb_pkts;
15699a2dd95SBruce Richardson }
15799a2dd95SBruce Richardson 
15899a2dd95SBruce Richardson static uint16_t
15910f726efSStephen Hemminger pdump_tx(uint16_t port, uint16_t queue,
16099a2dd95SBruce Richardson 		struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
16199a2dd95SBruce Richardson {
16210f726efSStephen Hemminger 	const struct pdump_rxtx_cbs *cbs = user_params;
16310f726efSStephen Hemminger 	struct rte_pdump_stats *stats = &pdump_stats->tx[port][queue];
16410f726efSStephen Hemminger 
16510f726efSStephen Hemminger 	pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_OUT,
16610f726efSStephen Hemminger 		   pkts, nb_pkts, cbs, stats);
16799a2dd95SBruce Richardson 	return nb_pkts;
16899a2dd95SBruce Richardson }
16999a2dd95SBruce Richardson 
17099a2dd95SBruce Richardson static int
17110f726efSStephen Hemminger pdump_register_rx_callbacks(enum pdump_version ver,
17210f726efSStephen Hemminger 			    uint16_t end_q, uint16_t port, uint16_t queue,
17399a2dd95SBruce Richardson 			    struct rte_ring *ring, struct rte_mempool *mp,
17410f726efSStephen Hemminger 			    struct rte_bpf *filter,
17510f726efSStephen Hemminger 			    uint16_t operation, uint32_t snaplen)
17699a2dd95SBruce Richardson {
17799a2dd95SBruce Richardson 	uint16_t qid;
17899a2dd95SBruce Richardson 
17999a2dd95SBruce Richardson 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
18099a2dd95SBruce Richardson 	for (; qid < end_q; qid++) {
18110f726efSStephen Hemminger 		struct pdump_rxtx_cbs *cbs = &rx_cbs[port][qid];
18210f726efSStephen Hemminger 
18310f726efSStephen Hemminger 		if (operation == ENABLE) {
18499a2dd95SBruce Richardson 			if (cbs->cb) {
18599a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
18699a2dd95SBruce Richardson 					"rx callback for port=%d queue=%d, already exists\n",
18799a2dd95SBruce Richardson 					port, qid);
18899a2dd95SBruce Richardson 				return -EEXIST;
18999a2dd95SBruce Richardson 			}
19010f726efSStephen Hemminger 			cbs->ver = ver;
19199a2dd95SBruce Richardson 			cbs->ring = ring;
19299a2dd95SBruce Richardson 			cbs->mp = mp;
19310f726efSStephen Hemminger 			cbs->snaplen = snaplen;
19410f726efSStephen Hemminger 			cbs->filter = filter;
19510f726efSStephen Hemminger 
19699a2dd95SBruce Richardson 			cbs->cb = rte_eth_add_first_rx_callback(port, qid,
19799a2dd95SBruce Richardson 								pdump_rx, cbs);
19899a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
19999a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
20099a2dd95SBruce Richardson 					"failed to add rx callback, errno=%d\n",
20199a2dd95SBruce Richardson 					rte_errno);
20299a2dd95SBruce Richardson 				return rte_errno;
20399a2dd95SBruce Richardson 			}
20410f726efSStephen Hemminger 		} else if (operation == DISABLE) {
20599a2dd95SBruce Richardson 			int ret;
20699a2dd95SBruce Richardson 
20799a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
20899a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
20999a2dd95SBruce Richardson 					"no existing rx callback for port=%d queue=%d\n",
21099a2dd95SBruce Richardson 					port, qid);
21199a2dd95SBruce Richardson 				return -EINVAL;
21299a2dd95SBruce Richardson 			}
21399a2dd95SBruce Richardson 			ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
21499a2dd95SBruce Richardson 			if (ret < 0) {
21599a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
21699a2dd95SBruce Richardson 					"failed to remove rx callback, errno=%d\n",
21799a2dd95SBruce Richardson 					-ret);
21899a2dd95SBruce Richardson 				return ret;
21999a2dd95SBruce Richardson 			}
22099a2dd95SBruce Richardson 			cbs->cb = NULL;
22199a2dd95SBruce Richardson 		}
22299a2dd95SBruce Richardson 	}
22399a2dd95SBruce Richardson 
22499a2dd95SBruce Richardson 	return 0;
22599a2dd95SBruce Richardson }
22699a2dd95SBruce Richardson 
22799a2dd95SBruce Richardson static int
22810f726efSStephen Hemminger pdump_register_tx_callbacks(enum pdump_version ver,
22910f726efSStephen Hemminger 			    uint16_t end_q, uint16_t port, uint16_t queue,
23099a2dd95SBruce Richardson 			    struct rte_ring *ring, struct rte_mempool *mp,
23110f726efSStephen Hemminger 			    struct rte_bpf *filter,
23210f726efSStephen Hemminger 			    uint16_t operation, uint32_t snaplen)
23399a2dd95SBruce Richardson {
23499a2dd95SBruce Richardson 
23599a2dd95SBruce Richardson 	uint16_t qid;
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
23899a2dd95SBruce Richardson 	for (; qid < end_q; qid++) {
23910f726efSStephen Hemminger 		struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid];
24010f726efSStephen Hemminger 
24110f726efSStephen Hemminger 		if (operation == ENABLE) {
24299a2dd95SBruce Richardson 			if (cbs->cb) {
24399a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
24499a2dd95SBruce Richardson 					"tx callback for port=%d queue=%d, already exists\n",
24599a2dd95SBruce Richardson 					port, qid);
24699a2dd95SBruce Richardson 				return -EEXIST;
24799a2dd95SBruce Richardson 			}
24810f726efSStephen Hemminger 			cbs->ver = ver;
24999a2dd95SBruce Richardson 			cbs->ring = ring;
25099a2dd95SBruce Richardson 			cbs->mp = mp;
25110f726efSStephen Hemminger 			cbs->snaplen = snaplen;
25210f726efSStephen Hemminger 			cbs->filter = filter;
25310f726efSStephen Hemminger 
25499a2dd95SBruce Richardson 			cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
25599a2dd95SBruce Richardson 								cbs);
25699a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
25799a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
25899a2dd95SBruce Richardson 					"failed to add tx callback, errno=%d\n",
25999a2dd95SBruce Richardson 					rte_errno);
26099a2dd95SBruce Richardson 				return rte_errno;
26199a2dd95SBruce Richardson 			}
26210f726efSStephen Hemminger 		} else if (operation == DISABLE) {
26399a2dd95SBruce Richardson 			int ret;
26499a2dd95SBruce Richardson 
26599a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
26699a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
26799a2dd95SBruce Richardson 					"no existing tx callback for port=%d queue=%d\n",
26899a2dd95SBruce Richardson 					port, qid);
26999a2dd95SBruce Richardson 				return -EINVAL;
27099a2dd95SBruce Richardson 			}
27199a2dd95SBruce Richardson 			ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
27299a2dd95SBruce Richardson 			if (ret < 0) {
27399a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
27499a2dd95SBruce Richardson 					"failed to remove tx callback, errno=%d\n",
27599a2dd95SBruce Richardson 					-ret);
27699a2dd95SBruce Richardson 				return ret;
27799a2dd95SBruce Richardson 			}
27899a2dd95SBruce Richardson 			cbs->cb = NULL;
27999a2dd95SBruce Richardson 		}
28099a2dd95SBruce Richardson 	}
28199a2dd95SBruce Richardson 
28299a2dd95SBruce Richardson 	return 0;
28399a2dd95SBruce Richardson }
28499a2dd95SBruce Richardson 
28599a2dd95SBruce Richardson static int
28699a2dd95SBruce Richardson set_pdump_rxtx_cbs(const struct pdump_request *p)
28799a2dd95SBruce Richardson {
28899a2dd95SBruce Richardson 	uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
28999a2dd95SBruce Richardson 	uint16_t port;
29099a2dd95SBruce Richardson 	int ret = 0;
29110f726efSStephen Hemminger 	struct rte_bpf *filter = NULL;
29299a2dd95SBruce Richardson 	uint32_t flags;
29399a2dd95SBruce Richardson 	uint16_t operation;
29499a2dd95SBruce Richardson 	struct rte_ring *ring;
29599a2dd95SBruce Richardson 	struct rte_mempool *mp;
29699a2dd95SBruce Richardson 
29710f726efSStephen Hemminger 	/* Check for possible DPDK version mismatch */
29810f726efSStephen Hemminger 	if (!(p->ver == V1 || p->ver == V2)) {
29910f726efSStephen Hemminger 		PDUMP_LOG(ERR,
30010f726efSStephen Hemminger 			  "incorrect client version %u\n", p->ver);
30110f726efSStephen Hemminger 		return -EINVAL;
30210f726efSStephen Hemminger 	}
30310f726efSStephen Hemminger 
30410f726efSStephen Hemminger 	if (p->prm) {
30510f726efSStephen Hemminger 		if (p->prm->prog_arg.type != RTE_BPF_ARG_PTR_MBUF) {
30610f726efSStephen Hemminger 			PDUMP_LOG(ERR,
30710f726efSStephen Hemminger 				  "invalid BPF program type: %u\n",
30810f726efSStephen Hemminger 				  p->prm->prog_arg.type);
30910f726efSStephen Hemminger 			return -EINVAL;
31010f726efSStephen Hemminger 		}
31110f726efSStephen Hemminger 
31210f726efSStephen Hemminger 		filter = rte_bpf_load(p->prm);
31310f726efSStephen Hemminger 		if (filter == NULL) {
31410f726efSStephen Hemminger 			PDUMP_LOG(ERR, "cannot load BPF filter: %s\n",
31510f726efSStephen Hemminger 				  rte_strerror(rte_errno));
31610f726efSStephen Hemminger 			return -rte_errno;
31710f726efSStephen Hemminger 		}
31810f726efSStephen Hemminger 	}
31910f726efSStephen Hemminger 
32099a2dd95SBruce Richardson 	flags = p->flags;
32199a2dd95SBruce Richardson 	operation = p->op;
32210f726efSStephen Hemminger 	queue = p->queue;
32310f726efSStephen Hemminger 	ring = p->ring;
32410f726efSStephen Hemminger 	mp = p->mp;
32510f726efSStephen Hemminger 
32610f726efSStephen Hemminger 	ret = rte_eth_dev_get_port_by_name(p->device, &port);
32799a2dd95SBruce Richardson 	if (ret < 0) {
32899a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
32999a2dd95SBruce Richardson 			  "failed to get port id for device id=%s\n",
33010f726efSStephen Hemminger 			  p->device);
33199a2dd95SBruce Richardson 		return -EINVAL;
33299a2dd95SBruce Richardson 	}
33399a2dd95SBruce Richardson 
33499a2dd95SBruce Richardson 	/* validation if packet capture is for all queues */
33599a2dd95SBruce Richardson 	if (queue == RTE_PDUMP_ALL_QUEUES) {
33699a2dd95SBruce Richardson 		struct rte_eth_dev_info dev_info;
33799a2dd95SBruce Richardson 
33899a2dd95SBruce Richardson 		ret = rte_eth_dev_info_get(port, &dev_info);
33999a2dd95SBruce Richardson 		if (ret != 0) {
34099a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
34199a2dd95SBruce Richardson 				"Error during getting device (port %u) info: %s\n",
34299a2dd95SBruce Richardson 				port, strerror(-ret));
34399a2dd95SBruce Richardson 			return ret;
34499a2dd95SBruce Richardson 		}
34599a2dd95SBruce Richardson 
34699a2dd95SBruce Richardson 		nb_rx_q = dev_info.nb_rx_queues;
34799a2dd95SBruce Richardson 		nb_tx_q = dev_info.nb_tx_queues;
34899a2dd95SBruce Richardson 		if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
34999a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
35099a2dd95SBruce Richardson 				"number of rx queues cannot be 0\n");
35199a2dd95SBruce Richardson 			return -EINVAL;
35299a2dd95SBruce Richardson 		}
35399a2dd95SBruce Richardson 		if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
35499a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
35599a2dd95SBruce Richardson 				"number of tx queues cannot be 0\n");
35699a2dd95SBruce Richardson 			return -EINVAL;
35799a2dd95SBruce Richardson 		}
35899a2dd95SBruce Richardson 		if ((nb_tx_q == 0 || nb_rx_q == 0) &&
35999a2dd95SBruce Richardson 			flags == RTE_PDUMP_FLAG_RXTX) {
36099a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
36199a2dd95SBruce Richardson 				"both tx&rx queues must be non zero\n");
36299a2dd95SBruce Richardson 			return -EINVAL;
36399a2dd95SBruce Richardson 		}
36499a2dd95SBruce Richardson 	}
36599a2dd95SBruce Richardson 
36699a2dd95SBruce Richardson 	/* register RX callback */
36799a2dd95SBruce Richardson 	if (flags & RTE_PDUMP_FLAG_RX) {
36899a2dd95SBruce Richardson 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
36910f726efSStephen Hemminger 		ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue,
37010f726efSStephen Hemminger 						  ring, mp, filter,
37110f726efSStephen Hemminger 						  operation, p->snaplen);
37299a2dd95SBruce Richardson 		if (ret < 0)
37399a2dd95SBruce Richardson 			return ret;
37499a2dd95SBruce Richardson 	}
37599a2dd95SBruce Richardson 
37699a2dd95SBruce Richardson 	/* register TX callback */
37799a2dd95SBruce Richardson 	if (flags & RTE_PDUMP_FLAG_TX) {
37899a2dd95SBruce Richardson 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
37910f726efSStephen Hemminger 		ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue,
38010f726efSStephen Hemminger 						  ring, mp, filter,
38110f726efSStephen Hemminger 						  operation, p->snaplen);
38299a2dd95SBruce Richardson 		if (ret < 0)
38399a2dd95SBruce Richardson 			return ret;
38499a2dd95SBruce Richardson 	}
38599a2dd95SBruce Richardson 
38699a2dd95SBruce Richardson 	return ret;
38799a2dd95SBruce Richardson }
38899a2dd95SBruce Richardson 
38999a2dd95SBruce Richardson static int
39099a2dd95SBruce Richardson pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
39199a2dd95SBruce Richardson {
39299a2dd95SBruce Richardson 	struct rte_mp_msg mp_resp;
39399a2dd95SBruce Richardson 	const struct pdump_request *cli_req;
39499a2dd95SBruce Richardson 	struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
39599a2dd95SBruce Richardson 
39699a2dd95SBruce Richardson 	/* recv client requests */
39799a2dd95SBruce Richardson 	if (mp_msg->len_param != sizeof(*cli_req)) {
39899a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "failed to recv from client\n");
39999a2dd95SBruce Richardson 		resp->err_value = -EINVAL;
40099a2dd95SBruce Richardson 	} else {
40199a2dd95SBruce Richardson 		cli_req = (const struct pdump_request *)mp_msg->param;
40299a2dd95SBruce Richardson 		resp->ver = cli_req->ver;
40399a2dd95SBruce Richardson 		resp->res_op = cli_req->op;
40499a2dd95SBruce Richardson 		resp->err_value = set_pdump_rxtx_cbs(cli_req);
40599a2dd95SBruce Richardson 	}
40699a2dd95SBruce Richardson 
40710f726efSStephen Hemminger 	rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
40899a2dd95SBruce Richardson 	mp_resp.len_param = sizeof(*resp);
40999a2dd95SBruce Richardson 	mp_resp.num_fds = 0;
41099a2dd95SBruce Richardson 	if (rte_mp_reply(&mp_resp, peer) < 0) {
41199a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "failed to send to client:%s\n",
41299a2dd95SBruce Richardson 			  strerror(rte_errno));
41399a2dd95SBruce Richardson 		return -1;
41499a2dd95SBruce Richardson 	}
41599a2dd95SBruce Richardson 
41699a2dd95SBruce Richardson 	return 0;
41799a2dd95SBruce Richardson }
41899a2dd95SBruce Richardson 
41999a2dd95SBruce Richardson int
42099a2dd95SBruce Richardson rte_pdump_init(void)
42199a2dd95SBruce Richardson {
42210f726efSStephen Hemminger 	const struct rte_memzone *mz;
42399a2dd95SBruce Richardson 	int ret;
42499a2dd95SBruce Richardson 
42510f726efSStephen Hemminger 	mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
42610f726efSStephen Hemminger 				 rte_socket_id(), 0);
42710f726efSStephen Hemminger 	if (mz == NULL) {
42810f726efSStephen Hemminger 		PDUMP_LOG(ERR, "cannot allocate pdump statistics\n");
42910f726efSStephen Hemminger 		rte_errno = ENOMEM;
43010f726efSStephen Hemminger 		return -1;
43110f726efSStephen Hemminger 	}
43210f726efSStephen Hemminger 	pdump_stats = mz->addr;
433*53caecb8SKonstantin Ananyev 	pdump_stats->mz = mz;
43410f726efSStephen Hemminger 
43599a2dd95SBruce Richardson 	ret = rte_mp_action_register(PDUMP_MP, pdump_server);
43699a2dd95SBruce Richardson 	if (ret && rte_errno != ENOTSUP)
43799a2dd95SBruce Richardson 		return -1;
43899a2dd95SBruce Richardson 	return 0;
43999a2dd95SBruce Richardson }
44099a2dd95SBruce Richardson 
44199a2dd95SBruce Richardson int
44299a2dd95SBruce Richardson rte_pdump_uninit(void)
44399a2dd95SBruce Richardson {
44499a2dd95SBruce Richardson 	rte_mp_action_unregister(PDUMP_MP);
44599a2dd95SBruce Richardson 
446*53caecb8SKonstantin Ananyev 	if (pdump_stats != NULL) {
447*53caecb8SKonstantin Ananyev 		rte_memzone_free(pdump_stats->mz);
448*53caecb8SKonstantin Ananyev 		pdump_stats = NULL;
449*53caecb8SKonstantin Ananyev 	}
450*53caecb8SKonstantin Ananyev 
45199a2dd95SBruce Richardson 	return 0;
45299a2dd95SBruce Richardson }
45399a2dd95SBruce Richardson 
45499a2dd95SBruce Richardson static int
45599a2dd95SBruce Richardson pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
45699a2dd95SBruce Richardson {
45799a2dd95SBruce Richardson 	if (ring == NULL || mp == NULL) {
45899a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "NULL ring or mempool\n");
45999a2dd95SBruce Richardson 		rte_errno = EINVAL;
46099a2dd95SBruce Richardson 		return -1;
46199a2dd95SBruce Richardson 	}
462c47d7b90SAndrew Rybchenko 	if (mp->flags & RTE_MEMPOOL_F_SP_PUT ||
463c47d7b90SAndrew Rybchenko 	    mp->flags & RTE_MEMPOOL_F_SC_GET) {
46499a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
46599a2dd95SBruce Richardson 			  "mempool with SP or SC set not valid for pdump,"
46699a2dd95SBruce Richardson 			  "must have MP and MC set\n");
46799a2dd95SBruce Richardson 		rte_errno = EINVAL;
46899a2dd95SBruce Richardson 		return -1;
46999a2dd95SBruce Richardson 	}
47099a2dd95SBruce Richardson 	if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
47199a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
47299a2dd95SBruce Richardson 			  "ring with SP or SC set is not valid for pdump,"
47399a2dd95SBruce Richardson 			  "must have MP and MC set\n");
47499a2dd95SBruce Richardson 		rte_errno = EINVAL;
47599a2dd95SBruce Richardson 		return -1;
47699a2dd95SBruce Richardson 	}
47799a2dd95SBruce Richardson 
47899a2dd95SBruce Richardson 	return 0;
47999a2dd95SBruce Richardson }
48099a2dd95SBruce Richardson 
48199a2dd95SBruce Richardson static int
48299a2dd95SBruce Richardson pdump_validate_flags(uint32_t flags)
48399a2dd95SBruce Richardson {
48410f726efSStephen Hemminger 	if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) {
48599a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
48699a2dd95SBruce Richardson 			"invalid flags, should be either rx/tx/rxtx\n");
48799a2dd95SBruce Richardson 		rte_errno = EINVAL;
48899a2dd95SBruce Richardson 		return -1;
48999a2dd95SBruce Richardson 	}
49099a2dd95SBruce Richardson 
49110f726efSStephen Hemminger 	/* mask off the flags we know about */
49210f726efSStephen Hemminger 	if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) {
49310f726efSStephen Hemminger 		PDUMP_LOG(ERR,
49410f726efSStephen Hemminger 			  "unknown flags: %#x\n", flags);
49510f726efSStephen Hemminger 		rte_errno = ENOTSUP;
49610f726efSStephen Hemminger 		return -1;
49710f726efSStephen Hemminger 	}
49810f726efSStephen Hemminger 
49999a2dd95SBruce Richardson 	return 0;
50099a2dd95SBruce Richardson }
50199a2dd95SBruce Richardson 
50299a2dd95SBruce Richardson static int
50399a2dd95SBruce Richardson pdump_validate_port(uint16_t port, char *name)
50499a2dd95SBruce Richardson {
50599a2dd95SBruce Richardson 	int ret = 0;
50699a2dd95SBruce Richardson 
50799a2dd95SBruce Richardson 	if (port >= RTE_MAX_ETHPORTS) {
50899a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "Invalid port id %u\n", port);
50999a2dd95SBruce Richardson 		rte_errno = EINVAL;
51099a2dd95SBruce Richardson 		return -1;
51199a2dd95SBruce Richardson 	}
51299a2dd95SBruce Richardson 
51399a2dd95SBruce Richardson 	ret = rte_eth_dev_get_name_by_port(port, name);
51499a2dd95SBruce Richardson 	if (ret < 0) {
51599a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "port %u to name mapping failed\n",
51699a2dd95SBruce Richardson 			  port);
51799a2dd95SBruce Richardson 		rte_errno = EINVAL;
51899a2dd95SBruce Richardson 		return -1;
51999a2dd95SBruce Richardson 	}
52099a2dd95SBruce Richardson 
52199a2dd95SBruce Richardson 	return 0;
52299a2dd95SBruce Richardson }
52399a2dd95SBruce Richardson 
52499a2dd95SBruce Richardson static int
52510f726efSStephen Hemminger pdump_prepare_client_request(const char *device, uint16_t queue,
52610f726efSStephen Hemminger 			     uint32_t flags, uint32_t snaplen,
52799a2dd95SBruce Richardson 			     uint16_t operation,
52899a2dd95SBruce Richardson 			     struct rte_ring *ring,
52999a2dd95SBruce Richardson 			     struct rte_mempool *mp,
53010f726efSStephen Hemminger 			     const struct rte_bpf_prm *prm)
53199a2dd95SBruce Richardson {
53299a2dd95SBruce Richardson 	int ret = -1;
53399a2dd95SBruce Richardson 	struct rte_mp_msg mp_req, *mp_rep;
53499a2dd95SBruce Richardson 	struct rte_mp_reply mp_reply;
53599a2dd95SBruce Richardson 	struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
53699a2dd95SBruce Richardson 	struct pdump_request *req = (struct pdump_request *)mp_req.param;
53799a2dd95SBruce Richardson 	struct pdump_response *resp;
53899a2dd95SBruce Richardson 
53910f726efSStephen Hemminger 	memset(req, 0, sizeof(*req));
54010f726efSStephen Hemminger 
54110f726efSStephen Hemminger 	req->ver = (flags & RTE_PDUMP_FLAG_PCAPNG) ? V2 : V1;
54210f726efSStephen Hemminger 	req->flags = flags & RTE_PDUMP_FLAG_RXTX;
54399a2dd95SBruce Richardson 	req->op = operation;
54410f726efSStephen Hemminger 	req->queue = queue;
54510f726efSStephen Hemminger 	rte_strscpy(req->device, device, sizeof(req->device));
54610f726efSStephen Hemminger 
54799a2dd95SBruce Richardson 	if ((operation & ENABLE) != 0) {
54810f726efSStephen Hemminger 		req->ring = ring;
54910f726efSStephen Hemminger 		req->mp = mp;
55010f726efSStephen Hemminger 		req->prm = prm;
55110f726efSStephen Hemminger 		req->snaplen = snaplen;
55299a2dd95SBruce Richardson 	}
55399a2dd95SBruce Richardson 
55410f726efSStephen Hemminger 	rte_strscpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
55599a2dd95SBruce Richardson 	mp_req.len_param = sizeof(*req);
55699a2dd95SBruce Richardson 	mp_req.num_fds = 0;
55799a2dd95SBruce Richardson 	if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
55899a2dd95SBruce Richardson 		mp_rep = &mp_reply.msgs[0];
55999a2dd95SBruce Richardson 		resp = (struct pdump_response *)mp_rep->param;
56099a2dd95SBruce Richardson 		rte_errno = resp->err_value;
56199a2dd95SBruce Richardson 		if (!resp->err_value)
56299a2dd95SBruce Richardson 			ret = 0;
56399a2dd95SBruce Richardson 		free(mp_reply.msgs);
56499a2dd95SBruce Richardson 	}
56599a2dd95SBruce Richardson 
56699a2dd95SBruce Richardson 	if (ret < 0)
56799a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
56899a2dd95SBruce Richardson 			"client request for pdump enable/disable failed\n");
56999a2dd95SBruce Richardson 	return ret;
57099a2dd95SBruce Richardson }
57199a2dd95SBruce Richardson 
57210f726efSStephen Hemminger /*
57310f726efSStephen Hemminger  * There are two versions of this function, because although original API
57410f726efSStephen Hemminger  * left place holder for future filter, it never checked the value.
57510f726efSStephen Hemminger  * Therefore the API can't depend on application passing a non
57610f726efSStephen Hemminger  * bogus value.
57710f726efSStephen Hemminger  */
57810f726efSStephen Hemminger static int
57910f726efSStephen Hemminger pdump_enable(uint16_t port, uint16_t queue,
58010f726efSStephen Hemminger 	     uint32_t flags, uint32_t snaplen,
58110f726efSStephen Hemminger 	     struct rte_ring *ring, struct rte_mempool *mp,
58210f726efSStephen Hemminger 	     const struct rte_bpf_prm *prm)
58399a2dd95SBruce Richardson {
58499a2dd95SBruce Richardson 	int ret;
58599a2dd95SBruce Richardson 	char name[RTE_DEV_NAME_MAX_LEN];
58699a2dd95SBruce Richardson 
58799a2dd95SBruce Richardson 	ret = pdump_validate_port(port, name);
58899a2dd95SBruce Richardson 	if (ret < 0)
58999a2dd95SBruce Richardson 		return ret;
59099a2dd95SBruce Richardson 	ret = pdump_validate_ring_mp(ring, mp);
59199a2dd95SBruce Richardson 	if (ret < 0)
59299a2dd95SBruce Richardson 		return ret;
59399a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
59499a2dd95SBruce Richardson 	if (ret < 0)
59599a2dd95SBruce Richardson 		return ret;
59699a2dd95SBruce Richardson 
59710f726efSStephen Hemminger 	if (snaplen == 0)
59810f726efSStephen Hemminger 		snaplen = UINT32_MAX;
59999a2dd95SBruce Richardson 
60010f726efSStephen Hemminger 	return pdump_prepare_client_request(name, queue, flags, snaplen,
60110f726efSStephen Hemminger 					    ENABLE, ring, mp, prm);
60299a2dd95SBruce Richardson }
60399a2dd95SBruce Richardson 
60499a2dd95SBruce Richardson int
60510f726efSStephen Hemminger rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
60699a2dd95SBruce Richardson 		 struct rte_ring *ring,
60799a2dd95SBruce Richardson 		 struct rte_mempool *mp,
60810f726efSStephen Hemminger 		 void *filter __rte_unused)
60999a2dd95SBruce Richardson {
61010f726efSStephen Hemminger 	return pdump_enable(port, queue, flags, 0,
61110f726efSStephen Hemminger 			    ring, mp, NULL);
61210f726efSStephen Hemminger }
61310f726efSStephen Hemminger 
61410f726efSStephen Hemminger int
61510f726efSStephen Hemminger rte_pdump_enable_bpf(uint16_t port, uint16_t queue,
61610f726efSStephen Hemminger 		     uint32_t flags, uint32_t snaplen,
61710f726efSStephen Hemminger 		     struct rte_ring *ring,
61810f726efSStephen Hemminger 		     struct rte_mempool *mp,
61910f726efSStephen Hemminger 		     const struct rte_bpf_prm *prm)
62010f726efSStephen Hemminger {
62110f726efSStephen Hemminger 	return pdump_enable(port, queue, flags, snaplen,
62210f726efSStephen Hemminger 			    ring, mp, prm);
62310f726efSStephen Hemminger }
62410f726efSStephen Hemminger 
62510f726efSStephen Hemminger static int
62610f726efSStephen Hemminger pdump_enable_by_deviceid(const char *device_id, uint16_t queue,
62710f726efSStephen Hemminger 			 uint32_t flags, uint32_t snaplen,
62810f726efSStephen Hemminger 			 struct rte_ring *ring,
62910f726efSStephen Hemminger 			 struct rte_mempool *mp,
63010f726efSStephen Hemminger 			 const struct rte_bpf_prm *prm)
63110f726efSStephen Hemminger {
63210f726efSStephen Hemminger 	int ret;
63399a2dd95SBruce Richardson 
63499a2dd95SBruce Richardson 	ret = pdump_validate_ring_mp(ring, mp);
63599a2dd95SBruce Richardson 	if (ret < 0)
63699a2dd95SBruce Richardson 		return ret;
63799a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
63899a2dd95SBruce Richardson 	if (ret < 0)
63999a2dd95SBruce Richardson 		return ret;
64099a2dd95SBruce Richardson 
641b2be63b5SStephen Hemminger 	if (snaplen == 0)
642b2be63b5SStephen Hemminger 		snaplen = UINT32_MAX;
643b2be63b5SStephen Hemminger 
64410f726efSStephen Hemminger 	return pdump_prepare_client_request(device_id, queue, flags, snaplen,
64510f726efSStephen Hemminger 					    ENABLE, ring, mp, prm);
64610f726efSStephen Hemminger }
64799a2dd95SBruce Richardson 
64810f726efSStephen Hemminger int
64910f726efSStephen Hemminger rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
65010f726efSStephen Hemminger 			     uint32_t flags,
65110f726efSStephen Hemminger 			     struct rte_ring *ring,
65210f726efSStephen Hemminger 			     struct rte_mempool *mp,
65310f726efSStephen Hemminger 			     void *filter __rte_unused)
65410f726efSStephen Hemminger {
65510f726efSStephen Hemminger 	return pdump_enable_by_deviceid(device_id, queue, flags, 0,
65610f726efSStephen Hemminger 					ring, mp, NULL);
65710f726efSStephen Hemminger }
65810f726efSStephen Hemminger 
65910f726efSStephen Hemminger int
66010f726efSStephen Hemminger rte_pdump_enable_bpf_by_deviceid(const char *device_id, uint16_t queue,
66110f726efSStephen Hemminger 				 uint32_t flags, uint32_t snaplen,
66210f726efSStephen Hemminger 				 struct rte_ring *ring,
66310f726efSStephen Hemminger 				 struct rte_mempool *mp,
66410f726efSStephen Hemminger 				 const struct rte_bpf_prm *prm)
66510f726efSStephen Hemminger {
66610f726efSStephen Hemminger 	return pdump_enable_by_deviceid(device_id, queue, flags, snaplen,
66710f726efSStephen Hemminger 					ring, mp, prm);
66899a2dd95SBruce Richardson }
66999a2dd95SBruce Richardson 
67099a2dd95SBruce Richardson int
67199a2dd95SBruce Richardson rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
67299a2dd95SBruce Richardson {
67399a2dd95SBruce Richardson 	int ret = 0;
67499a2dd95SBruce Richardson 	char name[RTE_DEV_NAME_MAX_LEN];
67599a2dd95SBruce Richardson 
67699a2dd95SBruce Richardson 	ret = pdump_validate_port(port, name);
67799a2dd95SBruce Richardson 	if (ret < 0)
67899a2dd95SBruce Richardson 		return ret;
67999a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
68099a2dd95SBruce Richardson 	if (ret < 0)
68199a2dd95SBruce Richardson 		return ret;
68299a2dd95SBruce Richardson 
68310f726efSStephen Hemminger 	ret = pdump_prepare_client_request(name, queue, flags, 0,
68499a2dd95SBruce Richardson 					   DISABLE, NULL, NULL, NULL);
68599a2dd95SBruce Richardson 
68699a2dd95SBruce Richardson 	return ret;
68799a2dd95SBruce Richardson }
68899a2dd95SBruce Richardson 
68999a2dd95SBruce Richardson int
69099a2dd95SBruce Richardson rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
69199a2dd95SBruce Richardson 				uint32_t flags)
69299a2dd95SBruce Richardson {
69399a2dd95SBruce Richardson 	int ret = 0;
69499a2dd95SBruce Richardson 
69599a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
69699a2dd95SBruce Richardson 	if (ret < 0)
69799a2dd95SBruce Richardson 		return ret;
69899a2dd95SBruce Richardson 
69910f726efSStephen Hemminger 	ret = pdump_prepare_client_request(device_id, queue, flags, 0,
70099a2dd95SBruce Richardson 					   DISABLE, NULL, NULL, NULL);
70199a2dd95SBruce Richardson 
70299a2dd95SBruce Richardson 	return ret;
70399a2dd95SBruce Richardson }
70410f726efSStephen Hemminger 
70510f726efSStephen Hemminger static void
70610f726efSStephen Hemminger pdump_sum_stats(uint16_t port, uint16_t nq,
70710f726efSStephen Hemminger 		struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
70810f726efSStephen Hemminger 		struct rte_pdump_stats *total)
70910f726efSStephen Hemminger {
71010f726efSStephen Hemminger 	uint64_t *sum = (uint64_t *)total;
71110f726efSStephen Hemminger 	unsigned int i;
71210f726efSStephen Hemminger 	uint64_t val;
71310f726efSStephen Hemminger 	uint16_t qid;
71410f726efSStephen Hemminger 
71510f726efSStephen Hemminger 	for (qid = 0; qid < nq; qid++) {
71610f726efSStephen Hemminger 		const uint64_t *perq = (const uint64_t *)&stats[port][qid];
71710f726efSStephen Hemminger 
71810f726efSStephen Hemminger 		for (i = 0; i < sizeof(*total) / sizeof(uint64_t); i++) {
71910f726efSStephen Hemminger 			val = __atomic_load_n(&perq[i], __ATOMIC_RELAXED);
72010f726efSStephen Hemminger 			sum[i] += val;
72110f726efSStephen Hemminger 		}
72210f726efSStephen Hemminger 	}
72310f726efSStephen Hemminger }
72410f726efSStephen Hemminger 
72510f726efSStephen Hemminger int
72610f726efSStephen Hemminger rte_pdump_stats(uint16_t port, struct rte_pdump_stats *stats)
72710f726efSStephen Hemminger {
72810f726efSStephen Hemminger 	struct rte_eth_dev_info dev_info;
72910f726efSStephen Hemminger 	const struct rte_memzone *mz;
73010f726efSStephen Hemminger 	int ret;
73110f726efSStephen Hemminger 
73210f726efSStephen Hemminger 	memset(stats, 0, sizeof(*stats));
73310f726efSStephen Hemminger 	ret = rte_eth_dev_info_get(port, &dev_info);
73410f726efSStephen Hemminger 	if (ret != 0) {
73510f726efSStephen Hemminger 		PDUMP_LOG(ERR,
73610f726efSStephen Hemminger 			  "Error during getting device (port %u) info: %s\n",
73710f726efSStephen Hemminger 			  port, strerror(-ret));
73810f726efSStephen Hemminger 		return ret;
73910f726efSStephen Hemminger 	}
74010f726efSStephen Hemminger 
74110f726efSStephen Hemminger 	if (pdump_stats == NULL) {
74210f726efSStephen Hemminger 		if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
74310f726efSStephen Hemminger 			/* rte_pdump_init was not called */
74410f726efSStephen Hemminger 			PDUMP_LOG(ERR, "pdump stats not initialized\n");
74510f726efSStephen Hemminger 			rte_errno = EINVAL;
74610f726efSStephen Hemminger 			return -1;
74710f726efSStephen Hemminger 		}
74810f726efSStephen Hemminger 
74910f726efSStephen Hemminger 		/* secondary process looks up the memzone */
75010f726efSStephen Hemminger 		mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
75110f726efSStephen Hemminger 		if (mz == NULL) {
75210f726efSStephen Hemminger 			/* rte_pdump_init was not called in primary process?? */
75310f726efSStephen Hemminger 			PDUMP_LOG(ERR, "can not find pdump stats\n");
75410f726efSStephen Hemminger 			rte_errno = EINVAL;
75510f726efSStephen Hemminger 			return -1;
75610f726efSStephen Hemminger 		}
75710f726efSStephen Hemminger 		pdump_stats = mz->addr;
75810f726efSStephen Hemminger 	}
75910f726efSStephen Hemminger 
76010f726efSStephen Hemminger 	pdump_sum_stats(port, dev_info.nb_rx_queues, pdump_stats->rx, stats);
76110f726efSStephen Hemminger 	pdump_sum_stats(port, dev_info.nb_tx_queues, pdump_stats->tx, stats);
76210f726efSStephen Hemminger 	return 0;
76310f726efSStephen Hemminger }
764