xref: /dpdk/lib/pdump/rte_pdump.c (revision 938c55cb932ef169da80da10d0a207f55fa65b48)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2016-2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
572b452c5SDmitry Kozlyuk #include <stdlib.h>
672b452c5SDmitry Kozlyuk 
799a2dd95SBruce Richardson #include <rte_mbuf.h>
899a2dd95SBruce Richardson #include <rte_ethdev.h>
999a2dd95SBruce Richardson #include <rte_lcore.h>
1099a2dd95SBruce Richardson #include <rte_log.h>
1110f726efSStephen Hemminger #include <rte_memzone.h>
1299a2dd95SBruce Richardson #include <rte_errno.h>
1399a2dd95SBruce Richardson #include <rte_string_fns.h>
1410f726efSStephen Hemminger #include <rte_pcapng.h>
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson #include "rte_pdump.h"
1799a2dd95SBruce Richardson 
18eeded204SDavid Marchand RTE_LOG_REGISTER_DEFAULT(pdump_logtype, NOTICE);
1999a2dd95SBruce Richardson 
2099a2dd95SBruce Richardson /* Macro for printing using RTE_LOG */
2199a2dd95SBruce Richardson #define PDUMP_LOG(level, fmt, args...)				\
2299a2dd95SBruce Richardson 	rte_log(RTE_LOG_ ## level, pdump_logtype, "%s(): " fmt,	\
2399a2dd95SBruce Richardson 		__func__, ## args)
2499a2dd95SBruce Richardson 
2599a2dd95SBruce Richardson /* Used for the multi-process communication */
2699a2dd95SBruce Richardson #define PDUMP_MP	"mp_pdump"
2799a2dd95SBruce Richardson 
2899a2dd95SBruce Richardson enum pdump_operation {
2999a2dd95SBruce Richardson 	DISABLE = 1,
3099a2dd95SBruce Richardson 	ENABLE = 2
3199a2dd95SBruce Richardson };
3299a2dd95SBruce Richardson 
3310f726efSStephen Hemminger /* Internal version number in request */
3499a2dd95SBruce Richardson enum pdump_version {
3510f726efSStephen Hemminger 	V1 = 1,		    /* no filtering or snap */
3610f726efSStephen Hemminger 	V2 = 2,
3799a2dd95SBruce Richardson };
3899a2dd95SBruce Richardson 
3999a2dd95SBruce Richardson struct pdump_request {
4099a2dd95SBruce Richardson 	uint16_t ver;
4199a2dd95SBruce Richardson 	uint16_t op;
4299a2dd95SBruce Richardson 	uint32_t flags;
4399a2dd95SBruce Richardson 	char device[RTE_DEV_NAME_MAX_LEN];
4499a2dd95SBruce Richardson 	uint16_t queue;
4599a2dd95SBruce Richardson 	struct rte_ring *ring;
4699a2dd95SBruce Richardson 	struct rte_mempool *mp;
4710f726efSStephen Hemminger 
4810f726efSStephen Hemminger 	const struct rte_bpf_prm *prm;
4910f726efSStephen Hemminger 	uint32_t snaplen;
5099a2dd95SBruce Richardson };
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson struct pdump_response {
5399a2dd95SBruce Richardson 	uint16_t ver;
5499a2dd95SBruce Richardson 	uint16_t res_op;
5599a2dd95SBruce Richardson 	int32_t err_value;
5699a2dd95SBruce Richardson };
5799a2dd95SBruce Richardson 
5899a2dd95SBruce Richardson static struct pdump_rxtx_cbs {
5999a2dd95SBruce Richardson 	struct rte_ring *ring;
6099a2dd95SBruce Richardson 	struct rte_mempool *mp;
6199a2dd95SBruce Richardson 	const struct rte_eth_rxtx_callback *cb;
6210f726efSStephen Hemminger 	const struct rte_bpf *filter;
6310f726efSStephen Hemminger 	enum pdump_version ver;
6410f726efSStephen Hemminger 	uint32_t snaplen;
6599a2dd95SBruce Richardson } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
6699a2dd95SBruce Richardson tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
6799a2dd95SBruce Richardson 
6899a2dd95SBruce Richardson 
6910f726efSStephen Hemminger /*
7010f726efSStephen Hemminger  * The packet capture statistics keep track of packets
7110f726efSStephen Hemminger  * accepted, filtered and dropped. These are per-queue
7210f726efSStephen Hemminger  * and in memory between primary and secondary processes.
7310f726efSStephen Hemminger  */
7410f726efSStephen Hemminger static const char MZ_RTE_PDUMP_STATS[] = "rte_pdump_stats";
7510f726efSStephen Hemminger static struct {
7610f726efSStephen Hemminger 	struct rte_pdump_stats rx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
7710f726efSStephen Hemminger 	struct rte_pdump_stats tx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
7853caecb8SKonstantin Ananyev 	const struct rte_memzone *mz;
7910f726efSStephen Hemminger } *pdump_stats;
8010f726efSStephen Hemminger 
8110f726efSStephen Hemminger /* Create a clone of mbuf to be placed into ring. */
8210f726efSStephen Hemminger static void
8310f726efSStephen Hemminger pdump_copy(uint16_t port_id, uint16_t queue,
8410f726efSStephen Hemminger 	   enum rte_pcapng_direction direction,
8510f726efSStephen Hemminger 	   struct rte_mbuf **pkts, uint16_t nb_pkts,
8610f726efSStephen Hemminger 	   const struct pdump_rxtx_cbs *cbs,
8710f726efSStephen Hemminger 	   struct rte_pdump_stats *stats)
8899a2dd95SBruce Richardson {
8999a2dd95SBruce Richardson 	unsigned int i;
9099a2dd95SBruce Richardson 	int ring_enq;
9199a2dd95SBruce Richardson 	uint16_t d_pkts = 0;
9299a2dd95SBruce Richardson 	struct rte_mbuf *dup_bufs[nb_pkts];
9310f726efSStephen Hemminger 	uint64_t ts;
9499a2dd95SBruce Richardson 	struct rte_ring *ring;
9599a2dd95SBruce Richardson 	struct rte_mempool *mp;
9699a2dd95SBruce Richardson 	struct rte_mbuf *p;
9710f726efSStephen Hemminger 	uint64_t rcs[nb_pkts];
9899a2dd95SBruce Richardson 
9910f726efSStephen Hemminger 	if (cbs->filter)
10010f726efSStephen Hemminger 		rte_bpf_exec_burst(cbs->filter, (void **)pkts, rcs, nb_pkts);
10110f726efSStephen Hemminger 
10210f726efSStephen Hemminger 	ts = rte_get_tsc_cycles();
10399a2dd95SBruce Richardson 	ring = cbs->ring;
10499a2dd95SBruce Richardson 	mp = cbs->mp;
10599a2dd95SBruce Richardson 	for (i = 0; i < nb_pkts; i++) {
10610f726efSStephen Hemminger 		/*
10710f726efSStephen Hemminger 		 * This uses same BPF return value convention as socket filter
10810f726efSStephen Hemminger 		 * and pcap_offline_filter.
10910f726efSStephen Hemminger 		 * if program returns zero
11010f726efSStephen Hemminger 		 * then packet doesn't match the filter (will be ignored).
11110f726efSStephen Hemminger 		 */
11210f726efSStephen Hemminger 		if (cbs->filter && rcs[i] == 0) {
113*938c55cbSTyler Retzlaff 			rte_atomic_fetch_add_explicit(&stats->filtered,
114*938c55cbSTyler Retzlaff 					   1, rte_memory_order_relaxed);
11510f726efSStephen Hemminger 			continue;
11610f726efSStephen Hemminger 		}
11710f726efSStephen Hemminger 
11810f726efSStephen Hemminger 		/*
11910f726efSStephen Hemminger 		 * If using pcapng then want to wrap packets
12010f726efSStephen Hemminger 		 * otherwise a simple copy.
12110f726efSStephen Hemminger 		 */
12210f726efSStephen Hemminger 		if (cbs->ver == V2)
12310f726efSStephen Hemminger 			p = rte_pcapng_copy(port_id, queue,
12410f726efSStephen Hemminger 					    pkts[i], mp, cbs->snaplen,
125c1abd1e9SAmit Prakash Shukla 					    ts, direction, NULL);
12610f726efSStephen Hemminger 		else
12710f726efSStephen Hemminger 			p = rte_pktmbuf_copy(pkts[i], mp, 0, cbs->snaplen);
12810f726efSStephen Hemminger 
12910f726efSStephen Hemminger 		if (unlikely(p == NULL))
130*938c55cbSTyler Retzlaff 			rte_atomic_fetch_add_explicit(&stats->nombuf, 1, rte_memory_order_relaxed);
13110f726efSStephen Hemminger 		else
13299a2dd95SBruce Richardson 			dup_bufs[d_pkts++] = p;
13399a2dd95SBruce Richardson 	}
13499a2dd95SBruce Richardson 
135*938c55cbSTyler Retzlaff 	rte_atomic_fetch_add_explicit(&stats->accepted, d_pkts, rte_memory_order_relaxed);
13610f726efSStephen Hemminger 
137b1824666SJoyce Kong 	ring_enq = rte_ring_enqueue_burst(ring, (void *)&dup_bufs[0], d_pkts, NULL);
13899a2dd95SBruce Richardson 	if (unlikely(ring_enq < d_pkts)) {
13999a2dd95SBruce Richardson 		unsigned int drops = d_pkts - ring_enq;
14099a2dd95SBruce Richardson 
141*938c55cbSTyler Retzlaff 		rte_atomic_fetch_add_explicit(&stats->ringfull, drops, rte_memory_order_relaxed);
14299a2dd95SBruce Richardson 		rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops);
14399a2dd95SBruce Richardson 	}
14499a2dd95SBruce Richardson }
14599a2dd95SBruce Richardson 
14699a2dd95SBruce Richardson static uint16_t
14710f726efSStephen Hemminger pdump_rx(uint16_t port, uint16_t queue,
14899a2dd95SBruce Richardson 	struct rte_mbuf **pkts, uint16_t nb_pkts,
14910f726efSStephen Hemminger 	uint16_t max_pkts __rte_unused, void *user_params)
15099a2dd95SBruce Richardson {
15110f726efSStephen Hemminger 	const struct pdump_rxtx_cbs *cbs = user_params;
15210f726efSStephen Hemminger 	struct rte_pdump_stats *stats = &pdump_stats->rx[port][queue];
15310f726efSStephen Hemminger 
15410f726efSStephen Hemminger 	pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_IN,
15510f726efSStephen Hemminger 		   pkts, nb_pkts, cbs, stats);
15699a2dd95SBruce Richardson 	return nb_pkts;
15799a2dd95SBruce Richardson }
15899a2dd95SBruce Richardson 
15999a2dd95SBruce Richardson static uint16_t
16010f726efSStephen Hemminger pdump_tx(uint16_t port, uint16_t queue,
16199a2dd95SBruce Richardson 		struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
16299a2dd95SBruce Richardson {
16310f726efSStephen Hemminger 	const struct pdump_rxtx_cbs *cbs = user_params;
16410f726efSStephen Hemminger 	struct rte_pdump_stats *stats = &pdump_stats->tx[port][queue];
16510f726efSStephen Hemminger 
16610f726efSStephen Hemminger 	pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_OUT,
16710f726efSStephen Hemminger 		   pkts, nb_pkts, cbs, stats);
16899a2dd95SBruce Richardson 	return nb_pkts;
16999a2dd95SBruce Richardson }
17099a2dd95SBruce Richardson 
17199a2dd95SBruce Richardson static int
17210f726efSStephen Hemminger pdump_register_rx_callbacks(enum pdump_version ver,
17310f726efSStephen Hemminger 			    uint16_t end_q, uint16_t port, uint16_t queue,
17499a2dd95SBruce Richardson 			    struct rte_ring *ring, struct rte_mempool *mp,
17510f726efSStephen Hemminger 			    struct rte_bpf *filter,
17610f726efSStephen Hemminger 			    uint16_t operation, uint32_t snaplen)
17799a2dd95SBruce Richardson {
17899a2dd95SBruce Richardson 	uint16_t qid;
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
18199a2dd95SBruce Richardson 	for (; qid < end_q; qid++) {
18210f726efSStephen Hemminger 		struct pdump_rxtx_cbs *cbs = &rx_cbs[port][qid];
18310f726efSStephen Hemminger 
18410f726efSStephen Hemminger 		if (operation == ENABLE) {
18599a2dd95SBruce Richardson 			if (cbs->cb) {
18699a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
18799a2dd95SBruce Richardson 					"rx callback for port=%d queue=%d, already exists\n",
18899a2dd95SBruce Richardson 					port, qid);
18999a2dd95SBruce Richardson 				return -EEXIST;
19099a2dd95SBruce Richardson 			}
19110f726efSStephen Hemminger 			cbs->ver = ver;
19299a2dd95SBruce Richardson 			cbs->ring = ring;
19399a2dd95SBruce Richardson 			cbs->mp = mp;
19410f726efSStephen Hemminger 			cbs->snaplen = snaplen;
19510f726efSStephen Hemminger 			cbs->filter = filter;
19610f726efSStephen Hemminger 
19799a2dd95SBruce Richardson 			cbs->cb = rte_eth_add_first_rx_callback(port, qid,
19899a2dd95SBruce Richardson 								pdump_rx, cbs);
19999a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
20099a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
20199a2dd95SBruce Richardson 					"failed to add rx callback, errno=%d\n",
20299a2dd95SBruce Richardson 					rte_errno);
20399a2dd95SBruce Richardson 				return rte_errno;
20499a2dd95SBruce Richardson 			}
20510f726efSStephen Hemminger 		} else if (operation == DISABLE) {
20699a2dd95SBruce Richardson 			int ret;
20799a2dd95SBruce Richardson 
20899a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
20999a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
21099a2dd95SBruce Richardson 					"no existing rx callback for port=%d queue=%d\n",
21199a2dd95SBruce Richardson 					port, qid);
21299a2dd95SBruce Richardson 				return -EINVAL;
21399a2dd95SBruce Richardson 			}
21499a2dd95SBruce Richardson 			ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
21599a2dd95SBruce Richardson 			if (ret < 0) {
21699a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
21799a2dd95SBruce Richardson 					"failed to remove rx callback, errno=%d\n",
21899a2dd95SBruce Richardson 					-ret);
21999a2dd95SBruce Richardson 				return ret;
22099a2dd95SBruce Richardson 			}
22199a2dd95SBruce Richardson 			cbs->cb = NULL;
22299a2dd95SBruce Richardson 		}
22399a2dd95SBruce Richardson 	}
22499a2dd95SBruce Richardson 
22599a2dd95SBruce Richardson 	return 0;
22699a2dd95SBruce Richardson }
22799a2dd95SBruce Richardson 
22899a2dd95SBruce Richardson static int
22910f726efSStephen Hemminger pdump_register_tx_callbacks(enum pdump_version ver,
23010f726efSStephen Hemminger 			    uint16_t end_q, uint16_t port, uint16_t queue,
23199a2dd95SBruce Richardson 			    struct rte_ring *ring, struct rte_mempool *mp,
23210f726efSStephen Hemminger 			    struct rte_bpf *filter,
23310f726efSStephen Hemminger 			    uint16_t operation, uint32_t snaplen)
23499a2dd95SBruce Richardson {
23599a2dd95SBruce Richardson 
23699a2dd95SBruce Richardson 	uint16_t qid;
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
23999a2dd95SBruce Richardson 	for (; qid < end_q; qid++) {
24010f726efSStephen Hemminger 		struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid];
24110f726efSStephen Hemminger 
24210f726efSStephen Hemminger 		if (operation == ENABLE) {
24399a2dd95SBruce Richardson 			if (cbs->cb) {
24499a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
24599a2dd95SBruce Richardson 					"tx callback for port=%d queue=%d, already exists\n",
24699a2dd95SBruce Richardson 					port, qid);
24799a2dd95SBruce Richardson 				return -EEXIST;
24899a2dd95SBruce Richardson 			}
24910f726efSStephen Hemminger 			cbs->ver = ver;
25099a2dd95SBruce Richardson 			cbs->ring = ring;
25199a2dd95SBruce Richardson 			cbs->mp = mp;
25210f726efSStephen Hemminger 			cbs->snaplen = snaplen;
25310f726efSStephen Hemminger 			cbs->filter = filter;
25410f726efSStephen Hemminger 
25599a2dd95SBruce Richardson 			cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
25699a2dd95SBruce Richardson 								cbs);
25799a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
25899a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
25999a2dd95SBruce Richardson 					"failed to add tx callback, errno=%d\n",
26099a2dd95SBruce Richardson 					rte_errno);
26199a2dd95SBruce Richardson 				return rte_errno;
26299a2dd95SBruce Richardson 			}
26310f726efSStephen Hemminger 		} else if (operation == DISABLE) {
26499a2dd95SBruce Richardson 			int ret;
26599a2dd95SBruce Richardson 
26699a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
26799a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
26899a2dd95SBruce Richardson 					"no existing tx callback for port=%d queue=%d\n",
26999a2dd95SBruce Richardson 					port, qid);
27099a2dd95SBruce Richardson 				return -EINVAL;
27199a2dd95SBruce Richardson 			}
27299a2dd95SBruce Richardson 			ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
27399a2dd95SBruce Richardson 			if (ret < 0) {
27499a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
27599a2dd95SBruce Richardson 					"failed to remove tx callback, errno=%d\n",
27699a2dd95SBruce Richardson 					-ret);
27799a2dd95SBruce Richardson 				return ret;
27899a2dd95SBruce Richardson 			}
27999a2dd95SBruce Richardson 			cbs->cb = NULL;
28099a2dd95SBruce Richardson 		}
28199a2dd95SBruce Richardson 	}
28299a2dd95SBruce Richardson 
28399a2dd95SBruce Richardson 	return 0;
28499a2dd95SBruce Richardson }
28599a2dd95SBruce Richardson 
28699a2dd95SBruce Richardson static int
28799a2dd95SBruce Richardson set_pdump_rxtx_cbs(const struct pdump_request *p)
28899a2dd95SBruce Richardson {
28999a2dd95SBruce Richardson 	uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
29099a2dd95SBruce Richardson 	uint16_t port;
29199a2dd95SBruce Richardson 	int ret = 0;
29210f726efSStephen Hemminger 	struct rte_bpf *filter = NULL;
29399a2dd95SBruce Richardson 	uint32_t flags;
29499a2dd95SBruce Richardson 	uint16_t operation;
29599a2dd95SBruce Richardson 	struct rte_ring *ring;
29699a2dd95SBruce Richardson 	struct rte_mempool *mp;
29799a2dd95SBruce Richardson 
29810f726efSStephen Hemminger 	/* Check for possible DPDK version mismatch */
29910f726efSStephen Hemminger 	if (!(p->ver == V1 || p->ver == V2)) {
30010f726efSStephen Hemminger 		PDUMP_LOG(ERR,
30110f726efSStephen Hemminger 			  "incorrect client version %u\n", p->ver);
30210f726efSStephen Hemminger 		return -EINVAL;
30310f726efSStephen Hemminger 	}
30410f726efSStephen Hemminger 
30510f726efSStephen Hemminger 	if (p->prm) {
30610f726efSStephen Hemminger 		if (p->prm->prog_arg.type != RTE_BPF_ARG_PTR_MBUF) {
30710f726efSStephen Hemminger 			PDUMP_LOG(ERR,
30810f726efSStephen Hemminger 				  "invalid BPF program type: %u\n",
30910f726efSStephen Hemminger 				  p->prm->prog_arg.type);
31010f726efSStephen Hemminger 			return -EINVAL;
31110f726efSStephen Hemminger 		}
31210f726efSStephen Hemminger 
31310f726efSStephen Hemminger 		filter = rte_bpf_load(p->prm);
31410f726efSStephen Hemminger 		if (filter == NULL) {
31510f726efSStephen Hemminger 			PDUMP_LOG(ERR, "cannot load BPF filter: %s\n",
31610f726efSStephen Hemminger 				  rte_strerror(rte_errno));
31710f726efSStephen Hemminger 			return -rte_errno;
31810f726efSStephen Hemminger 		}
31910f726efSStephen Hemminger 	}
32010f726efSStephen Hemminger 
32199a2dd95SBruce Richardson 	flags = p->flags;
32299a2dd95SBruce Richardson 	operation = p->op;
32310f726efSStephen Hemminger 	queue = p->queue;
32410f726efSStephen Hemminger 	ring = p->ring;
32510f726efSStephen Hemminger 	mp = p->mp;
32610f726efSStephen Hemminger 
32710f726efSStephen Hemminger 	ret = rte_eth_dev_get_port_by_name(p->device, &port);
32899a2dd95SBruce Richardson 	if (ret < 0) {
32999a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
33099a2dd95SBruce Richardson 			  "failed to get port id for device id=%s\n",
33110f726efSStephen Hemminger 			  p->device);
33299a2dd95SBruce Richardson 		return -EINVAL;
33399a2dd95SBruce Richardson 	}
33499a2dd95SBruce Richardson 
33599a2dd95SBruce Richardson 	/* validation if packet capture is for all queues */
33699a2dd95SBruce Richardson 	if (queue == RTE_PDUMP_ALL_QUEUES) {
33799a2dd95SBruce Richardson 		struct rte_eth_dev_info dev_info;
33899a2dd95SBruce Richardson 
33999a2dd95SBruce Richardson 		ret = rte_eth_dev_info_get(port, &dev_info);
34099a2dd95SBruce Richardson 		if (ret != 0) {
34199a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
34299a2dd95SBruce Richardson 				"Error during getting device (port %u) info: %s\n",
34399a2dd95SBruce Richardson 				port, strerror(-ret));
34499a2dd95SBruce Richardson 			return ret;
34599a2dd95SBruce Richardson 		}
34699a2dd95SBruce Richardson 
34799a2dd95SBruce Richardson 		nb_rx_q = dev_info.nb_rx_queues;
34899a2dd95SBruce Richardson 		nb_tx_q = dev_info.nb_tx_queues;
34999a2dd95SBruce Richardson 		if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
35099a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
35199a2dd95SBruce Richardson 				"number of rx queues cannot be 0\n");
35299a2dd95SBruce Richardson 			return -EINVAL;
35399a2dd95SBruce Richardson 		}
35499a2dd95SBruce Richardson 		if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
35599a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
35699a2dd95SBruce Richardson 				"number of tx queues cannot be 0\n");
35799a2dd95SBruce Richardson 			return -EINVAL;
35899a2dd95SBruce Richardson 		}
35999a2dd95SBruce Richardson 		if ((nb_tx_q == 0 || nb_rx_q == 0) &&
36099a2dd95SBruce Richardson 			flags == RTE_PDUMP_FLAG_RXTX) {
36199a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
36299a2dd95SBruce Richardson 				"both tx&rx queues must be non zero\n");
36399a2dd95SBruce Richardson 			return -EINVAL;
36499a2dd95SBruce Richardson 		}
36599a2dd95SBruce Richardson 	}
36699a2dd95SBruce Richardson 
36799a2dd95SBruce Richardson 	/* register RX callback */
36899a2dd95SBruce Richardson 	if (flags & RTE_PDUMP_FLAG_RX) {
36999a2dd95SBruce Richardson 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
37010f726efSStephen Hemminger 		ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue,
37110f726efSStephen Hemminger 						  ring, mp, filter,
37210f726efSStephen Hemminger 						  operation, p->snaplen);
37399a2dd95SBruce Richardson 		if (ret < 0)
37499a2dd95SBruce Richardson 			return ret;
37599a2dd95SBruce Richardson 	}
37699a2dd95SBruce Richardson 
37799a2dd95SBruce Richardson 	/* register TX callback */
37899a2dd95SBruce Richardson 	if (flags & RTE_PDUMP_FLAG_TX) {
37999a2dd95SBruce Richardson 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
38010f726efSStephen Hemminger 		ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue,
38110f726efSStephen Hemminger 						  ring, mp, filter,
38210f726efSStephen Hemminger 						  operation, p->snaplen);
38399a2dd95SBruce Richardson 		if (ret < 0)
38499a2dd95SBruce Richardson 			return ret;
38599a2dd95SBruce Richardson 	}
38699a2dd95SBruce Richardson 
38799a2dd95SBruce Richardson 	return ret;
38899a2dd95SBruce Richardson }
38999a2dd95SBruce Richardson 
39099a2dd95SBruce Richardson static int
39199a2dd95SBruce Richardson pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
39299a2dd95SBruce Richardson {
39399a2dd95SBruce Richardson 	struct rte_mp_msg mp_resp;
39499a2dd95SBruce Richardson 	const struct pdump_request *cli_req;
39599a2dd95SBruce Richardson 	struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
39699a2dd95SBruce Richardson 
39799a2dd95SBruce Richardson 	/* recv client requests */
39899a2dd95SBruce Richardson 	if (mp_msg->len_param != sizeof(*cli_req)) {
39999a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "failed to recv from client\n");
40099a2dd95SBruce Richardson 		resp->err_value = -EINVAL;
40199a2dd95SBruce Richardson 	} else {
40299a2dd95SBruce Richardson 		cli_req = (const struct pdump_request *)mp_msg->param;
40399a2dd95SBruce Richardson 		resp->ver = cli_req->ver;
40499a2dd95SBruce Richardson 		resp->res_op = cli_req->op;
40599a2dd95SBruce Richardson 		resp->err_value = set_pdump_rxtx_cbs(cli_req);
40699a2dd95SBruce Richardson 	}
40799a2dd95SBruce Richardson 
40810f726efSStephen Hemminger 	rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
40999a2dd95SBruce Richardson 	mp_resp.len_param = sizeof(*resp);
41099a2dd95SBruce Richardson 	mp_resp.num_fds = 0;
41199a2dd95SBruce Richardson 	if (rte_mp_reply(&mp_resp, peer) < 0) {
41299a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "failed to send to client:%s\n",
41399a2dd95SBruce Richardson 			  strerror(rte_errno));
41499a2dd95SBruce Richardson 		return -1;
41599a2dd95SBruce Richardson 	}
41699a2dd95SBruce Richardson 
41799a2dd95SBruce Richardson 	return 0;
41899a2dd95SBruce Richardson }
41999a2dd95SBruce Richardson 
42099a2dd95SBruce Richardson int
42199a2dd95SBruce Richardson rte_pdump_init(void)
42299a2dd95SBruce Richardson {
42310f726efSStephen Hemminger 	const struct rte_memzone *mz;
42499a2dd95SBruce Richardson 	int ret;
42599a2dd95SBruce Richardson 
42610f726efSStephen Hemminger 	mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
42710f726efSStephen Hemminger 				 rte_socket_id(), 0);
42810f726efSStephen Hemminger 	if (mz == NULL) {
42910f726efSStephen Hemminger 		PDUMP_LOG(ERR, "cannot allocate pdump statistics\n");
43010f726efSStephen Hemminger 		rte_errno = ENOMEM;
43110f726efSStephen Hemminger 		return -1;
43210f726efSStephen Hemminger 	}
43310f726efSStephen Hemminger 	pdump_stats = mz->addr;
43453caecb8SKonstantin Ananyev 	pdump_stats->mz = mz;
43510f726efSStephen Hemminger 
43699a2dd95SBruce Richardson 	ret = rte_mp_action_register(PDUMP_MP, pdump_server);
43799a2dd95SBruce Richardson 	if (ret && rte_errno != ENOTSUP)
43899a2dd95SBruce Richardson 		return -1;
43999a2dd95SBruce Richardson 	return 0;
44099a2dd95SBruce Richardson }
44199a2dd95SBruce Richardson 
44299a2dd95SBruce Richardson int
44399a2dd95SBruce Richardson rte_pdump_uninit(void)
44499a2dd95SBruce Richardson {
44599a2dd95SBruce Richardson 	rte_mp_action_unregister(PDUMP_MP);
44699a2dd95SBruce Richardson 
44753caecb8SKonstantin Ananyev 	if (pdump_stats != NULL) {
44853caecb8SKonstantin Ananyev 		rte_memzone_free(pdump_stats->mz);
44953caecb8SKonstantin Ananyev 		pdump_stats = NULL;
45053caecb8SKonstantin Ananyev 	}
45153caecb8SKonstantin Ananyev 
45299a2dd95SBruce Richardson 	return 0;
45399a2dd95SBruce Richardson }
45499a2dd95SBruce Richardson 
45599a2dd95SBruce Richardson static int
45699a2dd95SBruce Richardson pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
45799a2dd95SBruce Richardson {
45899a2dd95SBruce Richardson 	if (ring == NULL || mp == NULL) {
45999a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "NULL ring or mempool\n");
46099a2dd95SBruce Richardson 		rte_errno = EINVAL;
46199a2dd95SBruce Richardson 		return -1;
46299a2dd95SBruce Richardson 	}
463c47d7b90SAndrew Rybchenko 	if (mp->flags & RTE_MEMPOOL_F_SP_PUT ||
464c47d7b90SAndrew Rybchenko 	    mp->flags & RTE_MEMPOOL_F_SC_GET) {
46599a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
46699a2dd95SBruce Richardson 			  "mempool with SP or SC set not valid for pdump,"
46799a2dd95SBruce Richardson 			  "must have MP and MC set\n");
46899a2dd95SBruce Richardson 		rte_errno = EINVAL;
46999a2dd95SBruce Richardson 		return -1;
47099a2dd95SBruce Richardson 	}
47199a2dd95SBruce Richardson 	if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
47299a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
47399a2dd95SBruce Richardson 			  "ring with SP or SC set is not valid for pdump,"
47499a2dd95SBruce Richardson 			  "must have MP and MC set\n");
47599a2dd95SBruce Richardson 		rte_errno = EINVAL;
47699a2dd95SBruce Richardson 		return -1;
47799a2dd95SBruce Richardson 	}
47899a2dd95SBruce Richardson 
47999a2dd95SBruce Richardson 	return 0;
48099a2dd95SBruce Richardson }
48199a2dd95SBruce Richardson 
48299a2dd95SBruce Richardson static int
48399a2dd95SBruce Richardson pdump_validate_flags(uint32_t flags)
48499a2dd95SBruce Richardson {
48510f726efSStephen Hemminger 	if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) {
48699a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
48799a2dd95SBruce Richardson 			"invalid flags, should be either rx/tx/rxtx\n");
48899a2dd95SBruce Richardson 		rte_errno = EINVAL;
48999a2dd95SBruce Richardson 		return -1;
49099a2dd95SBruce Richardson 	}
49199a2dd95SBruce Richardson 
49210f726efSStephen Hemminger 	/* mask off the flags we know about */
49310f726efSStephen Hemminger 	if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) {
49410f726efSStephen Hemminger 		PDUMP_LOG(ERR,
49510f726efSStephen Hemminger 			  "unknown flags: %#x\n", flags);
49610f726efSStephen Hemminger 		rte_errno = ENOTSUP;
49710f726efSStephen Hemminger 		return -1;
49810f726efSStephen Hemminger 	}
49910f726efSStephen Hemminger 
50099a2dd95SBruce Richardson 	return 0;
50199a2dd95SBruce Richardson }
50299a2dd95SBruce Richardson 
50399a2dd95SBruce Richardson static int
50499a2dd95SBruce Richardson pdump_validate_port(uint16_t port, char *name)
50599a2dd95SBruce Richardson {
50699a2dd95SBruce Richardson 	int ret = 0;
50799a2dd95SBruce Richardson 
50899a2dd95SBruce Richardson 	if (port >= RTE_MAX_ETHPORTS) {
50999a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "Invalid port id %u\n", port);
51099a2dd95SBruce Richardson 		rte_errno = EINVAL;
51199a2dd95SBruce Richardson 		return -1;
51299a2dd95SBruce Richardson 	}
51399a2dd95SBruce Richardson 
51499a2dd95SBruce Richardson 	ret = rte_eth_dev_get_name_by_port(port, name);
51599a2dd95SBruce Richardson 	if (ret < 0) {
51699a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "port %u to name mapping failed\n",
51799a2dd95SBruce Richardson 			  port);
51899a2dd95SBruce Richardson 		rte_errno = EINVAL;
51999a2dd95SBruce Richardson 		return -1;
52099a2dd95SBruce Richardson 	}
52199a2dd95SBruce Richardson 
52299a2dd95SBruce Richardson 	return 0;
52399a2dd95SBruce Richardson }
52499a2dd95SBruce Richardson 
52599a2dd95SBruce Richardson static int
52610f726efSStephen Hemminger pdump_prepare_client_request(const char *device, uint16_t queue,
52710f726efSStephen Hemminger 			     uint32_t flags, uint32_t snaplen,
52899a2dd95SBruce Richardson 			     uint16_t operation,
52999a2dd95SBruce Richardson 			     struct rte_ring *ring,
53099a2dd95SBruce Richardson 			     struct rte_mempool *mp,
53110f726efSStephen Hemminger 			     const struct rte_bpf_prm *prm)
53299a2dd95SBruce Richardson {
53399a2dd95SBruce Richardson 	int ret = -1;
53499a2dd95SBruce Richardson 	struct rte_mp_msg mp_req, *mp_rep;
53599a2dd95SBruce Richardson 	struct rte_mp_reply mp_reply;
53699a2dd95SBruce Richardson 	struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
53799a2dd95SBruce Richardson 	struct pdump_request *req = (struct pdump_request *)mp_req.param;
53899a2dd95SBruce Richardson 	struct pdump_response *resp;
53999a2dd95SBruce Richardson 
5408a0cf0c4SStephen Hemminger 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
5418a0cf0c4SStephen Hemminger 		PDUMP_LOG(ERR,
5428a0cf0c4SStephen Hemminger 			  "pdump enable/disable not allowed in primary process\n");
5438a0cf0c4SStephen Hemminger 		return -EINVAL;
5448a0cf0c4SStephen Hemminger 	}
5458a0cf0c4SStephen Hemminger 
54610f726efSStephen Hemminger 	memset(req, 0, sizeof(*req));
54710f726efSStephen Hemminger 
54810f726efSStephen Hemminger 	req->ver = (flags & RTE_PDUMP_FLAG_PCAPNG) ? V2 : V1;
54910f726efSStephen Hemminger 	req->flags = flags & RTE_PDUMP_FLAG_RXTX;
55099a2dd95SBruce Richardson 	req->op = operation;
55110f726efSStephen Hemminger 	req->queue = queue;
55210f726efSStephen Hemminger 	rte_strscpy(req->device, device, sizeof(req->device));
55310f726efSStephen Hemminger 
55499a2dd95SBruce Richardson 	if ((operation & ENABLE) != 0) {
55510f726efSStephen Hemminger 		req->ring = ring;
55610f726efSStephen Hemminger 		req->mp = mp;
55710f726efSStephen Hemminger 		req->prm = prm;
55810f726efSStephen Hemminger 		req->snaplen = snaplen;
55999a2dd95SBruce Richardson 	}
56099a2dd95SBruce Richardson 
56110f726efSStephen Hemminger 	rte_strscpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
56299a2dd95SBruce Richardson 	mp_req.len_param = sizeof(*req);
56399a2dd95SBruce Richardson 	mp_req.num_fds = 0;
56499a2dd95SBruce Richardson 	if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
56599a2dd95SBruce Richardson 		mp_rep = &mp_reply.msgs[0];
56699a2dd95SBruce Richardson 		resp = (struct pdump_response *)mp_rep->param;
56799a2dd95SBruce Richardson 		rte_errno = resp->err_value;
56899a2dd95SBruce Richardson 		if (!resp->err_value)
56999a2dd95SBruce Richardson 			ret = 0;
57099a2dd95SBruce Richardson 		free(mp_reply.msgs);
57199a2dd95SBruce Richardson 	}
57299a2dd95SBruce Richardson 
57399a2dd95SBruce Richardson 	if (ret < 0)
57499a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
57599a2dd95SBruce Richardson 			"client request for pdump enable/disable failed\n");
57699a2dd95SBruce Richardson 	return ret;
57799a2dd95SBruce Richardson }
57899a2dd95SBruce Richardson 
57910f726efSStephen Hemminger /*
58010f726efSStephen Hemminger  * There are two versions of this function, because although original API
58110f726efSStephen Hemminger  * left place holder for future filter, it never checked the value.
58210f726efSStephen Hemminger  * Therefore the API can't depend on application passing a non
58310f726efSStephen Hemminger  * bogus value.
58410f726efSStephen Hemminger  */
58510f726efSStephen Hemminger static int
58610f726efSStephen Hemminger pdump_enable(uint16_t port, uint16_t queue,
58710f726efSStephen Hemminger 	     uint32_t flags, uint32_t snaplen,
58810f726efSStephen Hemminger 	     struct rte_ring *ring, struct rte_mempool *mp,
58910f726efSStephen Hemminger 	     const struct rte_bpf_prm *prm)
59099a2dd95SBruce Richardson {
59199a2dd95SBruce Richardson 	int ret;
59299a2dd95SBruce Richardson 	char name[RTE_DEV_NAME_MAX_LEN];
59399a2dd95SBruce Richardson 
59499a2dd95SBruce Richardson 	ret = pdump_validate_port(port, name);
59599a2dd95SBruce Richardson 	if (ret < 0)
59699a2dd95SBruce Richardson 		return ret;
59799a2dd95SBruce Richardson 	ret = pdump_validate_ring_mp(ring, mp);
59899a2dd95SBruce Richardson 	if (ret < 0)
59999a2dd95SBruce Richardson 		return ret;
60099a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
60199a2dd95SBruce Richardson 	if (ret < 0)
60299a2dd95SBruce Richardson 		return ret;
60399a2dd95SBruce Richardson 
60410f726efSStephen Hemminger 	if (snaplen == 0)
60510f726efSStephen Hemminger 		snaplen = UINT32_MAX;
60699a2dd95SBruce Richardson 
60710f726efSStephen Hemminger 	return pdump_prepare_client_request(name, queue, flags, snaplen,
60810f726efSStephen Hemminger 					    ENABLE, ring, mp, prm);
60999a2dd95SBruce Richardson }
61099a2dd95SBruce Richardson 
61199a2dd95SBruce Richardson int
61210f726efSStephen Hemminger rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
61399a2dd95SBruce Richardson 		 struct rte_ring *ring,
61499a2dd95SBruce Richardson 		 struct rte_mempool *mp,
61510f726efSStephen Hemminger 		 void *filter __rte_unused)
61699a2dd95SBruce Richardson {
61710f726efSStephen Hemminger 	return pdump_enable(port, queue, flags, 0,
61810f726efSStephen Hemminger 			    ring, mp, NULL);
61910f726efSStephen Hemminger }
62010f726efSStephen Hemminger 
62110f726efSStephen Hemminger int
62210f726efSStephen Hemminger rte_pdump_enable_bpf(uint16_t port, uint16_t queue,
62310f726efSStephen Hemminger 		     uint32_t flags, uint32_t snaplen,
62410f726efSStephen Hemminger 		     struct rte_ring *ring,
62510f726efSStephen Hemminger 		     struct rte_mempool *mp,
62610f726efSStephen Hemminger 		     const struct rte_bpf_prm *prm)
62710f726efSStephen Hemminger {
62810f726efSStephen Hemminger 	return pdump_enable(port, queue, flags, snaplen,
62910f726efSStephen Hemminger 			    ring, mp, prm);
63010f726efSStephen Hemminger }
63110f726efSStephen Hemminger 
63210f726efSStephen Hemminger static int
63310f726efSStephen Hemminger pdump_enable_by_deviceid(const char *device_id, uint16_t queue,
63410f726efSStephen Hemminger 			 uint32_t flags, uint32_t snaplen,
63510f726efSStephen Hemminger 			 struct rte_ring *ring,
63610f726efSStephen Hemminger 			 struct rte_mempool *mp,
63710f726efSStephen Hemminger 			 const struct rte_bpf_prm *prm)
63810f726efSStephen Hemminger {
63910f726efSStephen Hemminger 	int ret;
64099a2dd95SBruce Richardson 
64199a2dd95SBruce Richardson 	ret = pdump_validate_ring_mp(ring, mp);
64299a2dd95SBruce Richardson 	if (ret < 0)
64399a2dd95SBruce Richardson 		return ret;
64499a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
64599a2dd95SBruce Richardson 	if (ret < 0)
64699a2dd95SBruce Richardson 		return ret;
64799a2dd95SBruce Richardson 
648b2be63b5SStephen Hemminger 	if (snaplen == 0)
649b2be63b5SStephen Hemminger 		snaplen = UINT32_MAX;
650b2be63b5SStephen Hemminger 
65110f726efSStephen Hemminger 	return pdump_prepare_client_request(device_id, queue, flags, snaplen,
65210f726efSStephen Hemminger 					    ENABLE, ring, mp, prm);
65310f726efSStephen Hemminger }
65499a2dd95SBruce Richardson 
65510f726efSStephen Hemminger int
65610f726efSStephen Hemminger rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
65710f726efSStephen Hemminger 			     uint32_t flags,
65810f726efSStephen Hemminger 			     struct rte_ring *ring,
65910f726efSStephen Hemminger 			     struct rte_mempool *mp,
66010f726efSStephen Hemminger 			     void *filter __rte_unused)
66110f726efSStephen Hemminger {
66210f726efSStephen Hemminger 	return pdump_enable_by_deviceid(device_id, queue, flags, 0,
66310f726efSStephen Hemminger 					ring, mp, NULL);
66410f726efSStephen Hemminger }
66510f726efSStephen Hemminger 
66610f726efSStephen Hemminger int
66710f726efSStephen Hemminger rte_pdump_enable_bpf_by_deviceid(const char *device_id, uint16_t queue,
66810f726efSStephen Hemminger 				 uint32_t flags, uint32_t snaplen,
66910f726efSStephen Hemminger 				 struct rte_ring *ring,
67010f726efSStephen Hemminger 				 struct rte_mempool *mp,
67110f726efSStephen Hemminger 				 const struct rte_bpf_prm *prm)
67210f726efSStephen Hemminger {
67310f726efSStephen Hemminger 	return pdump_enable_by_deviceid(device_id, queue, flags, snaplen,
67410f726efSStephen Hemminger 					ring, mp, prm);
67599a2dd95SBruce Richardson }
67699a2dd95SBruce Richardson 
67799a2dd95SBruce Richardson int
67899a2dd95SBruce Richardson rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
67999a2dd95SBruce Richardson {
68099a2dd95SBruce Richardson 	int ret = 0;
68199a2dd95SBruce Richardson 	char name[RTE_DEV_NAME_MAX_LEN];
68299a2dd95SBruce Richardson 
68399a2dd95SBruce Richardson 	ret = pdump_validate_port(port, name);
68499a2dd95SBruce Richardson 	if (ret < 0)
68599a2dd95SBruce Richardson 		return ret;
68699a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
68799a2dd95SBruce Richardson 	if (ret < 0)
68899a2dd95SBruce Richardson 		return ret;
68999a2dd95SBruce Richardson 
69010f726efSStephen Hemminger 	ret = pdump_prepare_client_request(name, queue, flags, 0,
69199a2dd95SBruce Richardson 					   DISABLE, NULL, NULL, NULL);
69299a2dd95SBruce Richardson 
69399a2dd95SBruce Richardson 	return ret;
69499a2dd95SBruce Richardson }
69599a2dd95SBruce Richardson 
69699a2dd95SBruce Richardson int
69799a2dd95SBruce Richardson rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
69899a2dd95SBruce Richardson 				uint32_t flags)
69999a2dd95SBruce Richardson {
70099a2dd95SBruce Richardson 	int ret = 0;
70199a2dd95SBruce Richardson 
70299a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
70399a2dd95SBruce Richardson 	if (ret < 0)
70499a2dd95SBruce Richardson 		return ret;
70599a2dd95SBruce Richardson 
70610f726efSStephen Hemminger 	ret = pdump_prepare_client_request(device_id, queue, flags, 0,
70799a2dd95SBruce Richardson 					   DISABLE, NULL, NULL, NULL);
70899a2dd95SBruce Richardson 
70999a2dd95SBruce Richardson 	return ret;
71099a2dd95SBruce Richardson }
71110f726efSStephen Hemminger 
71210f726efSStephen Hemminger static void
71310f726efSStephen Hemminger pdump_sum_stats(uint16_t port, uint16_t nq,
71410f726efSStephen Hemminger 		struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
71510f726efSStephen Hemminger 		struct rte_pdump_stats *total)
71610f726efSStephen Hemminger {
71710f726efSStephen Hemminger 	uint64_t *sum = (uint64_t *)total;
71810f726efSStephen Hemminger 	unsigned int i;
71910f726efSStephen Hemminger 	uint64_t val;
72010f726efSStephen Hemminger 	uint16_t qid;
72110f726efSStephen Hemminger 
72210f726efSStephen Hemminger 	for (qid = 0; qid < nq; qid++) {
723*938c55cbSTyler Retzlaff 		const RTE_ATOMIC(uint64_t) *perq = (const uint64_t __rte_atomic *)&stats[port][qid];
72410f726efSStephen Hemminger 
72510f726efSStephen Hemminger 		for (i = 0; i < sizeof(*total) / sizeof(uint64_t); i++) {
726*938c55cbSTyler Retzlaff 			val = rte_atomic_load_explicit(&perq[i], rte_memory_order_relaxed);
72710f726efSStephen Hemminger 			sum[i] += val;
72810f726efSStephen Hemminger 		}
72910f726efSStephen Hemminger 	}
73010f726efSStephen Hemminger }
73110f726efSStephen Hemminger 
73210f726efSStephen Hemminger int
73310f726efSStephen Hemminger rte_pdump_stats(uint16_t port, struct rte_pdump_stats *stats)
73410f726efSStephen Hemminger {
73510f726efSStephen Hemminger 	struct rte_eth_dev_info dev_info;
73610f726efSStephen Hemminger 	const struct rte_memzone *mz;
73710f726efSStephen Hemminger 	int ret;
73810f726efSStephen Hemminger 
73910f726efSStephen Hemminger 	memset(stats, 0, sizeof(*stats));
74010f726efSStephen Hemminger 	ret = rte_eth_dev_info_get(port, &dev_info);
74110f726efSStephen Hemminger 	if (ret != 0) {
74210f726efSStephen Hemminger 		PDUMP_LOG(ERR,
74310f726efSStephen Hemminger 			  "Error during getting device (port %u) info: %s\n",
74410f726efSStephen Hemminger 			  port, strerror(-ret));
74510f726efSStephen Hemminger 		return ret;
74610f726efSStephen Hemminger 	}
74710f726efSStephen Hemminger 
74810f726efSStephen Hemminger 	if (pdump_stats == NULL) {
74910f726efSStephen Hemminger 		if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
75010f726efSStephen Hemminger 			/* rte_pdump_init was not called */
75110f726efSStephen Hemminger 			PDUMP_LOG(ERR, "pdump stats not initialized\n");
75210f726efSStephen Hemminger 			rte_errno = EINVAL;
75310f726efSStephen Hemminger 			return -1;
75410f726efSStephen Hemminger 		}
75510f726efSStephen Hemminger 
75610f726efSStephen Hemminger 		/* secondary process looks up the memzone */
75710f726efSStephen Hemminger 		mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
75810f726efSStephen Hemminger 		if (mz == NULL) {
75910f726efSStephen Hemminger 			/* rte_pdump_init was not called in primary process?? */
76010f726efSStephen Hemminger 			PDUMP_LOG(ERR, "can not find pdump stats\n");
76110f726efSStephen Hemminger 			rte_errno = EINVAL;
76210f726efSStephen Hemminger 			return -1;
76310f726efSStephen Hemminger 		}
76410f726efSStephen Hemminger 		pdump_stats = mz->addr;
76510f726efSStephen Hemminger 	}
76610f726efSStephen Hemminger 
76710f726efSStephen Hemminger 	pdump_sum_stats(port, dev_info.nb_rx_queues, pdump_stats->rx, stats);
76810f726efSStephen Hemminger 	pdump_sum_stats(port, dev_info.nb_tx_queues, pdump_stats->tx, stats);
76910f726efSStephen Hemminger 	return 0;
77010f726efSStephen Hemminger }
771