xref: /dpdk/lib/pdump/rte_pdump.c (revision 10f726efe26c55805cf0bf6ca1b80e97b98eb724)
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>
10*10f726efSStephen Hemminger #include <rte_memzone.h>
1199a2dd95SBruce Richardson #include <rte_errno.h>
1299a2dd95SBruce Richardson #include <rte_string_fns.h>
13*10f726efSStephen 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 
32*10f726efSStephen Hemminger /* Internal version number in request */
3399a2dd95SBruce Richardson enum pdump_version {
34*10f726efSStephen Hemminger 	V1 = 1,		    /* no filtering or snap */
35*10f726efSStephen 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;
46*10f726efSStephen Hemminger 
47*10f726efSStephen Hemminger 	const struct rte_bpf_prm *prm;
48*10f726efSStephen 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;
61*10f726efSStephen Hemminger 	const struct rte_bpf *filter;
62*10f726efSStephen Hemminger 	enum pdump_version ver;
63*10f726efSStephen 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 
68*10f726efSStephen Hemminger /*
69*10f726efSStephen Hemminger  * The packet capture statistics keep track of packets
70*10f726efSStephen Hemminger  * accepted, filtered and dropped. These are per-queue
71*10f726efSStephen Hemminger  * and in memory between primary and secondary processes.
72*10f726efSStephen Hemminger  */
73*10f726efSStephen Hemminger static const char MZ_RTE_PDUMP_STATS[] = "rte_pdump_stats";
74*10f726efSStephen Hemminger static struct {
75*10f726efSStephen Hemminger 	struct rte_pdump_stats rx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
76*10f726efSStephen Hemminger 	struct rte_pdump_stats tx[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
77*10f726efSStephen Hemminger } *pdump_stats;
78*10f726efSStephen Hemminger 
79*10f726efSStephen Hemminger /* Create a clone of mbuf to be placed into ring. */
80*10f726efSStephen Hemminger static void
81*10f726efSStephen Hemminger pdump_copy(uint16_t port_id, uint16_t queue,
82*10f726efSStephen Hemminger 	   enum rte_pcapng_direction direction,
83*10f726efSStephen Hemminger 	   struct rte_mbuf **pkts, uint16_t nb_pkts,
84*10f726efSStephen Hemminger 	   const struct pdump_rxtx_cbs *cbs,
85*10f726efSStephen Hemminger 	   struct rte_pdump_stats *stats)
8699a2dd95SBruce Richardson {
8799a2dd95SBruce Richardson 	unsigned int i;
8899a2dd95SBruce Richardson 	int ring_enq;
8999a2dd95SBruce Richardson 	uint16_t d_pkts = 0;
9099a2dd95SBruce Richardson 	struct rte_mbuf *dup_bufs[nb_pkts];
91*10f726efSStephen Hemminger 	uint64_t ts;
9299a2dd95SBruce Richardson 	struct rte_ring *ring;
9399a2dd95SBruce Richardson 	struct rte_mempool *mp;
9499a2dd95SBruce Richardson 	struct rte_mbuf *p;
95*10f726efSStephen Hemminger 	uint64_t rcs[nb_pkts];
9699a2dd95SBruce Richardson 
97*10f726efSStephen Hemminger 	if (cbs->filter)
98*10f726efSStephen Hemminger 		rte_bpf_exec_burst(cbs->filter, (void **)pkts, rcs, nb_pkts);
99*10f726efSStephen Hemminger 
100*10f726efSStephen Hemminger 	ts = rte_get_tsc_cycles();
10199a2dd95SBruce Richardson 	ring = cbs->ring;
10299a2dd95SBruce Richardson 	mp = cbs->mp;
10399a2dd95SBruce Richardson 	for (i = 0; i < nb_pkts; i++) {
104*10f726efSStephen Hemminger 		/*
105*10f726efSStephen Hemminger 		 * This uses same BPF return value convention as socket filter
106*10f726efSStephen Hemminger 		 * and pcap_offline_filter.
107*10f726efSStephen Hemminger 		 * if program returns zero
108*10f726efSStephen Hemminger 		 * then packet doesn't match the filter (will be ignored).
109*10f726efSStephen Hemminger 		 */
110*10f726efSStephen Hemminger 		if (cbs->filter && rcs[i] == 0) {
111*10f726efSStephen Hemminger 			__atomic_fetch_add(&stats->filtered,
112*10f726efSStephen Hemminger 					   1, __ATOMIC_RELAXED);
113*10f726efSStephen Hemminger 			continue;
114*10f726efSStephen Hemminger 		}
115*10f726efSStephen Hemminger 
116*10f726efSStephen Hemminger 		/*
117*10f726efSStephen Hemminger 		 * If using pcapng then want to wrap packets
118*10f726efSStephen Hemminger 		 * otherwise a simple copy.
119*10f726efSStephen Hemminger 		 */
120*10f726efSStephen Hemminger 		if (cbs->ver == V2)
121*10f726efSStephen Hemminger 			p = rte_pcapng_copy(port_id, queue,
122*10f726efSStephen Hemminger 					    pkts[i], mp, cbs->snaplen,
123*10f726efSStephen Hemminger 					    ts, direction);
124*10f726efSStephen Hemminger 		else
125*10f726efSStephen Hemminger 			p = rte_pktmbuf_copy(pkts[i], mp, 0, cbs->snaplen);
126*10f726efSStephen Hemminger 
127*10f726efSStephen Hemminger 		if (unlikely(p == NULL))
128*10f726efSStephen Hemminger 			__atomic_fetch_add(&stats->nombuf, 1, __ATOMIC_RELAXED);
129*10f726efSStephen Hemminger 		else
13099a2dd95SBruce Richardson 			dup_bufs[d_pkts++] = p;
13199a2dd95SBruce Richardson 	}
13299a2dd95SBruce Richardson 
133*10f726efSStephen Hemminger 	__atomic_fetch_add(&stats->accepted, d_pkts, __ATOMIC_RELAXED);
134*10f726efSStephen Hemminger 
13599a2dd95SBruce Richardson 	ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL);
13699a2dd95SBruce Richardson 	if (unlikely(ring_enq < d_pkts)) {
13799a2dd95SBruce Richardson 		unsigned int drops = d_pkts - ring_enq;
13899a2dd95SBruce Richardson 
139*10f726efSStephen Hemminger 		__atomic_fetch_add(&stats->ringfull, drops, __ATOMIC_RELAXED);
14099a2dd95SBruce Richardson 		rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops);
14199a2dd95SBruce Richardson 	}
14299a2dd95SBruce Richardson }
14399a2dd95SBruce Richardson 
14499a2dd95SBruce Richardson static uint16_t
145*10f726efSStephen Hemminger pdump_rx(uint16_t port, uint16_t queue,
14699a2dd95SBruce Richardson 	struct rte_mbuf **pkts, uint16_t nb_pkts,
147*10f726efSStephen Hemminger 	uint16_t max_pkts __rte_unused, void *user_params)
14899a2dd95SBruce Richardson {
149*10f726efSStephen Hemminger 	const struct pdump_rxtx_cbs *cbs = user_params;
150*10f726efSStephen Hemminger 	struct rte_pdump_stats *stats = &pdump_stats->rx[port][queue];
151*10f726efSStephen Hemminger 
152*10f726efSStephen Hemminger 	pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_IN,
153*10f726efSStephen Hemminger 		   pkts, nb_pkts, cbs, stats);
15499a2dd95SBruce Richardson 	return nb_pkts;
15599a2dd95SBruce Richardson }
15699a2dd95SBruce Richardson 
15799a2dd95SBruce Richardson static uint16_t
158*10f726efSStephen Hemminger pdump_tx(uint16_t port, uint16_t queue,
15999a2dd95SBruce Richardson 		struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
16099a2dd95SBruce Richardson {
161*10f726efSStephen Hemminger 	const struct pdump_rxtx_cbs *cbs = user_params;
162*10f726efSStephen Hemminger 	struct rte_pdump_stats *stats = &pdump_stats->tx[port][queue];
163*10f726efSStephen Hemminger 
164*10f726efSStephen Hemminger 	pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_OUT,
165*10f726efSStephen Hemminger 		   pkts, nb_pkts, cbs, stats);
16699a2dd95SBruce Richardson 	return nb_pkts;
16799a2dd95SBruce Richardson }
16899a2dd95SBruce Richardson 
16999a2dd95SBruce Richardson static int
170*10f726efSStephen Hemminger pdump_register_rx_callbacks(enum pdump_version ver,
171*10f726efSStephen Hemminger 			    uint16_t end_q, uint16_t port, uint16_t queue,
17299a2dd95SBruce Richardson 			    struct rte_ring *ring, struct rte_mempool *mp,
173*10f726efSStephen Hemminger 			    struct rte_bpf *filter,
174*10f726efSStephen Hemminger 			    uint16_t operation, uint32_t snaplen)
17599a2dd95SBruce Richardson {
17699a2dd95SBruce Richardson 	uint16_t qid;
17799a2dd95SBruce Richardson 
17899a2dd95SBruce Richardson 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
17999a2dd95SBruce Richardson 	for (; qid < end_q; qid++) {
180*10f726efSStephen Hemminger 		struct pdump_rxtx_cbs *cbs = &rx_cbs[port][qid];
181*10f726efSStephen Hemminger 
182*10f726efSStephen Hemminger 		if (operation == ENABLE) {
18399a2dd95SBruce Richardson 			if (cbs->cb) {
18499a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
18599a2dd95SBruce Richardson 					"rx callback for port=%d queue=%d, already exists\n",
18699a2dd95SBruce Richardson 					port, qid);
18799a2dd95SBruce Richardson 				return -EEXIST;
18899a2dd95SBruce Richardson 			}
189*10f726efSStephen Hemminger 			cbs->ver = ver;
19099a2dd95SBruce Richardson 			cbs->ring = ring;
19199a2dd95SBruce Richardson 			cbs->mp = mp;
192*10f726efSStephen Hemminger 			cbs->snaplen = snaplen;
193*10f726efSStephen Hemminger 			cbs->filter = filter;
194*10f726efSStephen Hemminger 
19599a2dd95SBruce Richardson 			cbs->cb = rte_eth_add_first_rx_callback(port, qid,
19699a2dd95SBruce Richardson 								pdump_rx, cbs);
19799a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
19899a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
19999a2dd95SBruce Richardson 					"failed to add rx callback, errno=%d\n",
20099a2dd95SBruce Richardson 					rte_errno);
20199a2dd95SBruce Richardson 				return rte_errno;
20299a2dd95SBruce Richardson 			}
203*10f726efSStephen Hemminger 		} else if (operation == DISABLE) {
20499a2dd95SBruce Richardson 			int ret;
20599a2dd95SBruce Richardson 
20699a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
20799a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
20899a2dd95SBruce Richardson 					"no existing rx callback for port=%d queue=%d\n",
20999a2dd95SBruce Richardson 					port, qid);
21099a2dd95SBruce Richardson 				return -EINVAL;
21199a2dd95SBruce Richardson 			}
21299a2dd95SBruce Richardson 			ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
21399a2dd95SBruce Richardson 			if (ret < 0) {
21499a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
21599a2dd95SBruce Richardson 					"failed to remove rx callback, errno=%d\n",
21699a2dd95SBruce Richardson 					-ret);
21799a2dd95SBruce Richardson 				return ret;
21899a2dd95SBruce Richardson 			}
21999a2dd95SBruce Richardson 			cbs->cb = NULL;
22099a2dd95SBruce Richardson 		}
22199a2dd95SBruce Richardson 	}
22299a2dd95SBruce Richardson 
22399a2dd95SBruce Richardson 	return 0;
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson 
22699a2dd95SBruce Richardson static int
227*10f726efSStephen Hemminger pdump_register_tx_callbacks(enum pdump_version ver,
228*10f726efSStephen Hemminger 			    uint16_t end_q, uint16_t port, uint16_t queue,
22999a2dd95SBruce Richardson 			    struct rte_ring *ring, struct rte_mempool *mp,
230*10f726efSStephen Hemminger 			    struct rte_bpf *filter,
231*10f726efSStephen Hemminger 			    uint16_t operation, uint32_t snaplen)
23299a2dd95SBruce Richardson {
23399a2dd95SBruce Richardson 
23499a2dd95SBruce Richardson 	uint16_t qid;
23599a2dd95SBruce Richardson 
23699a2dd95SBruce Richardson 	qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
23799a2dd95SBruce Richardson 	for (; qid < end_q; qid++) {
238*10f726efSStephen Hemminger 		struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid];
239*10f726efSStephen Hemminger 
240*10f726efSStephen Hemminger 		if (operation == ENABLE) {
24199a2dd95SBruce Richardson 			if (cbs->cb) {
24299a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
24399a2dd95SBruce Richardson 					"tx callback for port=%d queue=%d, already exists\n",
24499a2dd95SBruce Richardson 					port, qid);
24599a2dd95SBruce Richardson 				return -EEXIST;
24699a2dd95SBruce Richardson 			}
247*10f726efSStephen Hemminger 			cbs->ver = ver;
24899a2dd95SBruce Richardson 			cbs->ring = ring;
24999a2dd95SBruce Richardson 			cbs->mp = mp;
250*10f726efSStephen Hemminger 			cbs->snaplen = snaplen;
251*10f726efSStephen Hemminger 			cbs->filter = filter;
252*10f726efSStephen Hemminger 
25399a2dd95SBruce Richardson 			cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
25499a2dd95SBruce Richardson 								cbs);
25599a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
25699a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
25799a2dd95SBruce Richardson 					"failed to add tx callback, errno=%d\n",
25899a2dd95SBruce Richardson 					rte_errno);
25999a2dd95SBruce Richardson 				return rte_errno;
26099a2dd95SBruce Richardson 			}
261*10f726efSStephen Hemminger 		} else if (operation == DISABLE) {
26299a2dd95SBruce Richardson 			int ret;
26399a2dd95SBruce Richardson 
26499a2dd95SBruce Richardson 			if (cbs->cb == NULL) {
26599a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
26699a2dd95SBruce Richardson 					"no existing tx callback for port=%d queue=%d\n",
26799a2dd95SBruce Richardson 					port, qid);
26899a2dd95SBruce Richardson 				return -EINVAL;
26999a2dd95SBruce Richardson 			}
27099a2dd95SBruce Richardson 			ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
27199a2dd95SBruce Richardson 			if (ret < 0) {
27299a2dd95SBruce Richardson 				PDUMP_LOG(ERR,
27399a2dd95SBruce Richardson 					"failed to remove tx callback, errno=%d\n",
27499a2dd95SBruce Richardson 					-ret);
27599a2dd95SBruce Richardson 				return ret;
27699a2dd95SBruce Richardson 			}
27799a2dd95SBruce Richardson 			cbs->cb = NULL;
27899a2dd95SBruce Richardson 		}
27999a2dd95SBruce Richardson 	}
28099a2dd95SBruce Richardson 
28199a2dd95SBruce Richardson 	return 0;
28299a2dd95SBruce Richardson }
28399a2dd95SBruce Richardson 
28499a2dd95SBruce Richardson static int
28599a2dd95SBruce Richardson set_pdump_rxtx_cbs(const struct pdump_request *p)
28699a2dd95SBruce Richardson {
28799a2dd95SBruce Richardson 	uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
28899a2dd95SBruce Richardson 	uint16_t port;
28999a2dd95SBruce Richardson 	int ret = 0;
290*10f726efSStephen Hemminger 	struct rte_bpf *filter = NULL;
29199a2dd95SBruce Richardson 	uint32_t flags;
29299a2dd95SBruce Richardson 	uint16_t operation;
29399a2dd95SBruce Richardson 	struct rte_ring *ring;
29499a2dd95SBruce Richardson 	struct rte_mempool *mp;
29599a2dd95SBruce Richardson 
296*10f726efSStephen Hemminger 	/* Check for possible DPDK version mismatch */
297*10f726efSStephen Hemminger 	if (!(p->ver == V1 || p->ver == V2)) {
298*10f726efSStephen Hemminger 		PDUMP_LOG(ERR,
299*10f726efSStephen Hemminger 			  "incorrect client version %u\n", p->ver);
300*10f726efSStephen Hemminger 		return -EINVAL;
301*10f726efSStephen Hemminger 	}
302*10f726efSStephen Hemminger 
303*10f726efSStephen Hemminger 	if (p->prm) {
304*10f726efSStephen Hemminger 		if (p->prm->prog_arg.type != RTE_BPF_ARG_PTR_MBUF) {
305*10f726efSStephen Hemminger 			PDUMP_LOG(ERR,
306*10f726efSStephen Hemminger 				  "invalid BPF program type: %u\n",
307*10f726efSStephen Hemminger 				  p->prm->prog_arg.type);
308*10f726efSStephen Hemminger 			return -EINVAL;
309*10f726efSStephen Hemminger 		}
310*10f726efSStephen Hemminger 
311*10f726efSStephen Hemminger 		filter = rte_bpf_load(p->prm);
312*10f726efSStephen Hemminger 		if (filter == NULL) {
313*10f726efSStephen Hemminger 			PDUMP_LOG(ERR, "cannot load BPF filter: %s\n",
314*10f726efSStephen Hemminger 				  rte_strerror(rte_errno));
315*10f726efSStephen Hemminger 			return -rte_errno;
316*10f726efSStephen Hemminger 		}
317*10f726efSStephen Hemminger 	}
318*10f726efSStephen Hemminger 
31999a2dd95SBruce Richardson 	flags = p->flags;
32099a2dd95SBruce Richardson 	operation = p->op;
321*10f726efSStephen Hemminger 	queue = p->queue;
322*10f726efSStephen Hemminger 	ring = p->ring;
323*10f726efSStephen Hemminger 	mp = p->mp;
324*10f726efSStephen Hemminger 
325*10f726efSStephen Hemminger 	ret = rte_eth_dev_get_port_by_name(p->device, &port);
32699a2dd95SBruce Richardson 	if (ret < 0) {
32799a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
32899a2dd95SBruce Richardson 			  "failed to get port id for device id=%s\n",
329*10f726efSStephen Hemminger 			  p->device);
33099a2dd95SBruce Richardson 		return -EINVAL;
33199a2dd95SBruce Richardson 	}
33299a2dd95SBruce Richardson 
33399a2dd95SBruce Richardson 	/* validation if packet capture is for all queues */
33499a2dd95SBruce Richardson 	if (queue == RTE_PDUMP_ALL_QUEUES) {
33599a2dd95SBruce Richardson 		struct rte_eth_dev_info dev_info;
33699a2dd95SBruce Richardson 
33799a2dd95SBruce Richardson 		ret = rte_eth_dev_info_get(port, &dev_info);
33899a2dd95SBruce Richardson 		if (ret != 0) {
33999a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
34099a2dd95SBruce Richardson 				"Error during getting device (port %u) info: %s\n",
34199a2dd95SBruce Richardson 				port, strerror(-ret));
34299a2dd95SBruce Richardson 			return ret;
34399a2dd95SBruce Richardson 		}
34499a2dd95SBruce Richardson 
34599a2dd95SBruce Richardson 		nb_rx_q = dev_info.nb_rx_queues;
34699a2dd95SBruce Richardson 		nb_tx_q = dev_info.nb_tx_queues;
34799a2dd95SBruce Richardson 		if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
34899a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
34999a2dd95SBruce Richardson 				"number of rx queues cannot be 0\n");
35099a2dd95SBruce Richardson 			return -EINVAL;
35199a2dd95SBruce Richardson 		}
35299a2dd95SBruce Richardson 		if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
35399a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
35499a2dd95SBruce Richardson 				"number of tx queues cannot be 0\n");
35599a2dd95SBruce Richardson 			return -EINVAL;
35699a2dd95SBruce Richardson 		}
35799a2dd95SBruce Richardson 		if ((nb_tx_q == 0 || nb_rx_q == 0) &&
35899a2dd95SBruce Richardson 			flags == RTE_PDUMP_FLAG_RXTX) {
35999a2dd95SBruce Richardson 			PDUMP_LOG(ERR,
36099a2dd95SBruce Richardson 				"both tx&rx queues must be non zero\n");
36199a2dd95SBruce Richardson 			return -EINVAL;
36299a2dd95SBruce Richardson 		}
36399a2dd95SBruce Richardson 	}
36499a2dd95SBruce Richardson 
36599a2dd95SBruce Richardson 	/* register RX callback */
36699a2dd95SBruce Richardson 	if (flags & RTE_PDUMP_FLAG_RX) {
36799a2dd95SBruce Richardson 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
368*10f726efSStephen Hemminger 		ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue,
369*10f726efSStephen Hemminger 						  ring, mp, filter,
370*10f726efSStephen Hemminger 						  operation, p->snaplen);
37199a2dd95SBruce Richardson 		if (ret < 0)
37299a2dd95SBruce Richardson 			return ret;
37399a2dd95SBruce Richardson 	}
37499a2dd95SBruce Richardson 
37599a2dd95SBruce Richardson 	/* register TX callback */
37699a2dd95SBruce Richardson 	if (flags & RTE_PDUMP_FLAG_TX) {
37799a2dd95SBruce Richardson 		end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
378*10f726efSStephen Hemminger 		ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue,
379*10f726efSStephen Hemminger 						  ring, mp, filter,
380*10f726efSStephen Hemminger 						  operation, p->snaplen);
38199a2dd95SBruce Richardson 		if (ret < 0)
38299a2dd95SBruce Richardson 			return ret;
38399a2dd95SBruce Richardson 	}
38499a2dd95SBruce Richardson 
38599a2dd95SBruce Richardson 	return ret;
38699a2dd95SBruce Richardson }
38799a2dd95SBruce Richardson 
38899a2dd95SBruce Richardson static int
38999a2dd95SBruce Richardson pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
39099a2dd95SBruce Richardson {
39199a2dd95SBruce Richardson 	struct rte_mp_msg mp_resp;
39299a2dd95SBruce Richardson 	const struct pdump_request *cli_req;
39399a2dd95SBruce Richardson 	struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
39499a2dd95SBruce Richardson 
39599a2dd95SBruce Richardson 	/* recv client requests */
39699a2dd95SBruce Richardson 	if (mp_msg->len_param != sizeof(*cli_req)) {
39799a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "failed to recv from client\n");
39899a2dd95SBruce Richardson 		resp->err_value = -EINVAL;
39999a2dd95SBruce Richardson 	} else {
40099a2dd95SBruce Richardson 		cli_req = (const struct pdump_request *)mp_msg->param;
40199a2dd95SBruce Richardson 		resp->ver = cli_req->ver;
40299a2dd95SBruce Richardson 		resp->res_op = cli_req->op;
40399a2dd95SBruce Richardson 		resp->err_value = set_pdump_rxtx_cbs(cli_req);
40499a2dd95SBruce Richardson 	}
40599a2dd95SBruce Richardson 
406*10f726efSStephen Hemminger 	rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
40799a2dd95SBruce Richardson 	mp_resp.len_param = sizeof(*resp);
40899a2dd95SBruce Richardson 	mp_resp.num_fds = 0;
40999a2dd95SBruce Richardson 	if (rte_mp_reply(&mp_resp, peer) < 0) {
41099a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "failed to send to client:%s\n",
41199a2dd95SBruce Richardson 			  strerror(rte_errno));
41299a2dd95SBruce Richardson 		return -1;
41399a2dd95SBruce Richardson 	}
41499a2dd95SBruce Richardson 
41599a2dd95SBruce Richardson 	return 0;
41699a2dd95SBruce Richardson }
41799a2dd95SBruce Richardson 
41899a2dd95SBruce Richardson int
41999a2dd95SBruce Richardson rte_pdump_init(void)
42099a2dd95SBruce Richardson {
421*10f726efSStephen Hemminger 	const struct rte_memzone *mz;
42299a2dd95SBruce Richardson 	int ret;
42399a2dd95SBruce Richardson 
424*10f726efSStephen Hemminger 	mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
425*10f726efSStephen Hemminger 				 rte_socket_id(), 0);
426*10f726efSStephen Hemminger 	if (mz == NULL) {
427*10f726efSStephen Hemminger 		PDUMP_LOG(ERR, "cannot allocate pdump statistics\n");
428*10f726efSStephen Hemminger 		rte_errno = ENOMEM;
429*10f726efSStephen Hemminger 		return -1;
430*10f726efSStephen Hemminger 	}
431*10f726efSStephen Hemminger 	pdump_stats = mz->addr;
432*10f726efSStephen Hemminger 
43399a2dd95SBruce Richardson 	ret = rte_mp_action_register(PDUMP_MP, pdump_server);
43499a2dd95SBruce Richardson 	if (ret && rte_errno != ENOTSUP)
43599a2dd95SBruce Richardson 		return -1;
43699a2dd95SBruce Richardson 	return 0;
43799a2dd95SBruce Richardson }
43899a2dd95SBruce Richardson 
43999a2dd95SBruce Richardson int
44099a2dd95SBruce Richardson rte_pdump_uninit(void)
44199a2dd95SBruce Richardson {
44299a2dd95SBruce Richardson 	rte_mp_action_unregister(PDUMP_MP);
44399a2dd95SBruce Richardson 
44499a2dd95SBruce Richardson 	return 0;
44599a2dd95SBruce Richardson }
44699a2dd95SBruce Richardson 
44799a2dd95SBruce Richardson static int
44899a2dd95SBruce Richardson pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
44999a2dd95SBruce Richardson {
45099a2dd95SBruce Richardson 	if (ring == NULL || mp == NULL) {
45199a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "NULL ring or mempool\n");
45299a2dd95SBruce Richardson 		rte_errno = EINVAL;
45399a2dd95SBruce Richardson 		return -1;
45499a2dd95SBruce Richardson 	}
455c47d7b90SAndrew Rybchenko 	if (mp->flags & RTE_MEMPOOL_F_SP_PUT ||
456c47d7b90SAndrew Rybchenko 	    mp->flags & RTE_MEMPOOL_F_SC_GET) {
45799a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
45899a2dd95SBruce Richardson 			  "mempool with SP or SC set not valid for pdump,"
45999a2dd95SBruce Richardson 			  "must have MP and MC set\n");
46099a2dd95SBruce Richardson 		rte_errno = EINVAL;
46199a2dd95SBruce Richardson 		return -1;
46299a2dd95SBruce Richardson 	}
46399a2dd95SBruce Richardson 	if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
46499a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
46599a2dd95SBruce Richardson 			  "ring with SP or SC set is 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 
47199a2dd95SBruce Richardson 	return 0;
47299a2dd95SBruce Richardson }
47399a2dd95SBruce Richardson 
47499a2dd95SBruce Richardson static int
47599a2dd95SBruce Richardson pdump_validate_flags(uint32_t flags)
47699a2dd95SBruce Richardson {
477*10f726efSStephen Hemminger 	if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) {
47899a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
47999a2dd95SBruce Richardson 			"invalid flags, should be either rx/tx/rxtx\n");
48099a2dd95SBruce Richardson 		rte_errno = EINVAL;
48199a2dd95SBruce Richardson 		return -1;
48299a2dd95SBruce Richardson 	}
48399a2dd95SBruce Richardson 
484*10f726efSStephen Hemminger 	/* mask off the flags we know about */
485*10f726efSStephen Hemminger 	if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) {
486*10f726efSStephen Hemminger 		PDUMP_LOG(ERR,
487*10f726efSStephen Hemminger 			  "unknown flags: %#x\n", flags);
488*10f726efSStephen Hemminger 		rte_errno = ENOTSUP;
489*10f726efSStephen Hemminger 		return -1;
490*10f726efSStephen Hemminger 	}
491*10f726efSStephen Hemminger 
49299a2dd95SBruce Richardson 	return 0;
49399a2dd95SBruce Richardson }
49499a2dd95SBruce Richardson 
49599a2dd95SBruce Richardson static int
49699a2dd95SBruce Richardson pdump_validate_port(uint16_t port, char *name)
49799a2dd95SBruce Richardson {
49899a2dd95SBruce Richardson 	int ret = 0;
49999a2dd95SBruce Richardson 
50099a2dd95SBruce Richardson 	if (port >= RTE_MAX_ETHPORTS) {
50199a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "Invalid port id %u\n", port);
50299a2dd95SBruce Richardson 		rte_errno = EINVAL;
50399a2dd95SBruce Richardson 		return -1;
50499a2dd95SBruce Richardson 	}
50599a2dd95SBruce Richardson 
50699a2dd95SBruce Richardson 	ret = rte_eth_dev_get_name_by_port(port, name);
50799a2dd95SBruce Richardson 	if (ret < 0) {
50899a2dd95SBruce Richardson 		PDUMP_LOG(ERR, "port %u to name mapping failed\n",
50999a2dd95SBruce Richardson 			  port);
51099a2dd95SBruce Richardson 		rte_errno = EINVAL;
51199a2dd95SBruce Richardson 		return -1;
51299a2dd95SBruce Richardson 	}
51399a2dd95SBruce Richardson 
51499a2dd95SBruce Richardson 	return 0;
51599a2dd95SBruce Richardson }
51699a2dd95SBruce Richardson 
51799a2dd95SBruce Richardson static int
518*10f726efSStephen Hemminger pdump_prepare_client_request(const char *device, uint16_t queue,
519*10f726efSStephen Hemminger 			     uint32_t flags, uint32_t snaplen,
52099a2dd95SBruce Richardson 			     uint16_t operation,
52199a2dd95SBruce Richardson 			     struct rte_ring *ring,
52299a2dd95SBruce Richardson 			     struct rte_mempool *mp,
523*10f726efSStephen Hemminger 			     const struct rte_bpf_prm *prm)
52499a2dd95SBruce Richardson {
52599a2dd95SBruce Richardson 	int ret = -1;
52699a2dd95SBruce Richardson 	struct rte_mp_msg mp_req, *mp_rep;
52799a2dd95SBruce Richardson 	struct rte_mp_reply mp_reply;
52899a2dd95SBruce Richardson 	struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
52999a2dd95SBruce Richardson 	struct pdump_request *req = (struct pdump_request *)mp_req.param;
53099a2dd95SBruce Richardson 	struct pdump_response *resp;
53199a2dd95SBruce Richardson 
532*10f726efSStephen Hemminger 	memset(req, 0, sizeof(*req));
533*10f726efSStephen Hemminger 
534*10f726efSStephen Hemminger 	req->ver = (flags & RTE_PDUMP_FLAG_PCAPNG) ? V2 : V1;
535*10f726efSStephen Hemminger 	req->flags = flags & RTE_PDUMP_FLAG_RXTX;
53699a2dd95SBruce Richardson 	req->op = operation;
537*10f726efSStephen Hemminger 	req->queue = queue;
538*10f726efSStephen Hemminger 	rte_strscpy(req->device, device, sizeof(req->device));
539*10f726efSStephen Hemminger 
54099a2dd95SBruce Richardson 	if ((operation & ENABLE) != 0) {
541*10f726efSStephen Hemminger 		req->ring = ring;
542*10f726efSStephen Hemminger 		req->mp = mp;
543*10f726efSStephen Hemminger 		req->prm = prm;
544*10f726efSStephen Hemminger 		req->snaplen = snaplen;
54599a2dd95SBruce Richardson 	}
54699a2dd95SBruce Richardson 
547*10f726efSStephen Hemminger 	rte_strscpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
54899a2dd95SBruce Richardson 	mp_req.len_param = sizeof(*req);
54999a2dd95SBruce Richardson 	mp_req.num_fds = 0;
55099a2dd95SBruce Richardson 	if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
55199a2dd95SBruce Richardson 		mp_rep = &mp_reply.msgs[0];
55299a2dd95SBruce Richardson 		resp = (struct pdump_response *)mp_rep->param;
55399a2dd95SBruce Richardson 		rte_errno = resp->err_value;
55499a2dd95SBruce Richardson 		if (!resp->err_value)
55599a2dd95SBruce Richardson 			ret = 0;
55699a2dd95SBruce Richardson 		free(mp_reply.msgs);
55799a2dd95SBruce Richardson 	}
55899a2dd95SBruce Richardson 
55999a2dd95SBruce Richardson 	if (ret < 0)
56099a2dd95SBruce Richardson 		PDUMP_LOG(ERR,
56199a2dd95SBruce Richardson 			"client request for pdump enable/disable failed\n");
56299a2dd95SBruce Richardson 	return ret;
56399a2dd95SBruce Richardson }
56499a2dd95SBruce Richardson 
565*10f726efSStephen Hemminger /*
566*10f726efSStephen Hemminger  * There are two versions of this function, because although original API
567*10f726efSStephen Hemminger  * left place holder for future filter, it never checked the value.
568*10f726efSStephen Hemminger  * Therefore the API can't depend on application passing a non
569*10f726efSStephen Hemminger  * bogus value.
570*10f726efSStephen Hemminger  */
571*10f726efSStephen Hemminger static int
572*10f726efSStephen Hemminger pdump_enable(uint16_t port, uint16_t queue,
573*10f726efSStephen Hemminger 	     uint32_t flags, uint32_t snaplen,
574*10f726efSStephen Hemminger 	     struct rte_ring *ring, struct rte_mempool *mp,
575*10f726efSStephen Hemminger 	     const struct rte_bpf_prm *prm)
57699a2dd95SBruce Richardson {
57799a2dd95SBruce Richardson 	int ret;
57899a2dd95SBruce Richardson 	char name[RTE_DEV_NAME_MAX_LEN];
57999a2dd95SBruce Richardson 
58099a2dd95SBruce Richardson 	ret = pdump_validate_port(port, name);
58199a2dd95SBruce Richardson 	if (ret < 0)
58299a2dd95SBruce Richardson 		return ret;
58399a2dd95SBruce Richardson 	ret = pdump_validate_ring_mp(ring, mp);
58499a2dd95SBruce Richardson 	if (ret < 0)
58599a2dd95SBruce Richardson 		return ret;
58699a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
58799a2dd95SBruce Richardson 	if (ret < 0)
58899a2dd95SBruce Richardson 		return ret;
58999a2dd95SBruce Richardson 
590*10f726efSStephen Hemminger 	if (snaplen == 0)
591*10f726efSStephen Hemminger 		snaplen = UINT32_MAX;
59299a2dd95SBruce Richardson 
593*10f726efSStephen Hemminger 	return pdump_prepare_client_request(name, queue, flags, snaplen,
594*10f726efSStephen Hemminger 					    ENABLE, ring, mp, prm);
59599a2dd95SBruce Richardson }
59699a2dd95SBruce Richardson 
59799a2dd95SBruce Richardson int
598*10f726efSStephen Hemminger rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
59999a2dd95SBruce Richardson 		 struct rte_ring *ring,
60099a2dd95SBruce Richardson 		 struct rte_mempool *mp,
601*10f726efSStephen Hemminger 		 void *filter __rte_unused)
60299a2dd95SBruce Richardson {
603*10f726efSStephen Hemminger 	return pdump_enable(port, queue, flags, 0,
604*10f726efSStephen Hemminger 			    ring, mp, NULL);
605*10f726efSStephen Hemminger }
606*10f726efSStephen Hemminger 
607*10f726efSStephen Hemminger int
608*10f726efSStephen Hemminger rte_pdump_enable_bpf(uint16_t port, uint16_t queue,
609*10f726efSStephen Hemminger 		     uint32_t flags, uint32_t snaplen,
610*10f726efSStephen Hemminger 		     struct rte_ring *ring,
611*10f726efSStephen Hemminger 		     struct rte_mempool *mp,
612*10f726efSStephen Hemminger 		     const struct rte_bpf_prm *prm)
613*10f726efSStephen Hemminger {
614*10f726efSStephen Hemminger 	return pdump_enable(port, queue, flags, snaplen,
615*10f726efSStephen Hemminger 			    ring, mp, prm);
616*10f726efSStephen Hemminger }
617*10f726efSStephen Hemminger 
618*10f726efSStephen Hemminger static int
619*10f726efSStephen Hemminger pdump_enable_by_deviceid(const char *device_id, uint16_t queue,
620*10f726efSStephen Hemminger 			 uint32_t flags, uint32_t snaplen,
621*10f726efSStephen Hemminger 			 struct rte_ring *ring,
622*10f726efSStephen Hemminger 			 struct rte_mempool *mp,
623*10f726efSStephen Hemminger 			 const struct rte_bpf_prm *prm)
624*10f726efSStephen Hemminger {
625*10f726efSStephen Hemminger 	int ret;
62699a2dd95SBruce Richardson 
62799a2dd95SBruce Richardson 	ret = pdump_validate_ring_mp(ring, mp);
62899a2dd95SBruce Richardson 	if (ret < 0)
62999a2dd95SBruce Richardson 		return ret;
63099a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
63199a2dd95SBruce Richardson 	if (ret < 0)
63299a2dd95SBruce Richardson 		return ret;
63399a2dd95SBruce Richardson 
634*10f726efSStephen Hemminger 	return pdump_prepare_client_request(device_id, queue, flags, snaplen,
635*10f726efSStephen Hemminger 					    ENABLE, ring, mp, prm);
636*10f726efSStephen Hemminger }
63799a2dd95SBruce Richardson 
638*10f726efSStephen Hemminger int
639*10f726efSStephen Hemminger rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
640*10f726efSStephen Hemminger 			     uint32_t flags,
641*10f726efSStephen Hemminger 			     struct rte_ring *ring,
642*10f726efSStephen Hemminger 			     struct rte_mempool *mp,
643*10f726efSStephen Hemminger 			     void *filter __rte_unused)
644*10f726efSStephen Hemminger {
645*10f726efSStephen Hemminger 	return pdump_enable_by_deviceid(device_id, queue, flags, 0,
646*10f726efSStephen Hemminger 					ring, mp, NULL);
647*10f726efSStephen Hemminger }
648*10f726efSStephen Hemminger 
649*10f726efSStephen Hemminger int
650*10f726efSStephen Hemminger rte_pdump_enable_bpf_by_deviceid(const char *device_id, uint16_t queue,
651*10f726efSStephen Hemminger 				 uint32_t flags, uint32_t snaplen,
652*10f726efSStephen Hemminger 				 struct rte_ring *ring,
653*10f726efSStephen Hemminger 				 struct rte_mempool *mp,
654*10f726efSStephen Hemminger 				 const struct rte_bpf_prm *prm)
655*10f726efSStephen Hemminger {
656*10f726efSStephen Hemminger 	return pdump_enable_by_deviceid(device_id, queue, flags, snaplen,
657*10f726efSStephen Hemminger 					ring, mp, prm);
65899a2dd95SBruce Richardson }
65999a2dd95SBruce Richardson 
66099a2dd95SBruce Richardson int
66199a2dd95SBruce Richardson rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
66299a2dd95SBruce Richardson {
66399a2dd95SBruce Richardson 	int ret = 0;
66499a2dd95SBruce Richardson 	char name[RTE_DEV_NAME_MAX_LEN];
66599a2dd95SBruce Richardson 
66699a2dd95SBruce Richardson 	ret = pdump_validate_port(port, name);
66799a2dd95SBruce Richardson 	if (ret < 0)
66899a2dd95SBruce Richardson 		return ret;
66999a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
67099a2dd95SBruce Richardson 	if (ret < 0)
67199a2dd95SBruce Richardson 		return ret;
67299a2dd95SBruce Richardson 
673*10f726efSStephen Hemminger 	ret = pdump_prepare_client_request(name, queue, flags, 0,
67499a2dd95SBruce Richardson 					   DISABLE, NULL, NULL, NULL);
67599a2dd95SBruce Richardson 
67699a2dd95SBruce Richardson 	return ret;
67799a2dd95SBruce Richardson }
67899a2dd95SBruce Richardson 
67999a2dd95SBruce Richardson int
68099a2dd95SBruce Richardson rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
68199a2dd95SBruce Richardson 				uint32_t flags)
68299a2dd95SBruce Richardson {
68399a2dd95SBruce Richardson 	int ret = 0;
68499a2dd95SBruce Richardson 
68599a2dd95SBruce Richardson 	ret = pdump_validate_flags(flags);
68699a2dd95SBruce Richardson 	if (ret < 0)
68799a2dd95SBruce Richardson 		return ret;
68899a2dd95SBruce Richardson 
689*10f726efSStephen Hemminger 	ret = pdump_prepare_client_request(device_id, queue, flags, 0,
69099a2dd95SBruce Richardson 					   DISABLE, NULL, NULL, NULL);
69199a2dd95SBruce Richardson 
69299a2dd95SBruce Richardson 	return ret;
69399a2dd95SBruce Richardson }
694*10f726efSStephen Hemminger 
695*10f726efSStephen Hemminger static void
696*10f726efSStephen Hemminger pdump_sum_stats(uint16_t port, uint16_t nq,
697*10f726efSStephen Hemminger 		struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
698*10f726efSStephen Hemminger 		struct rte_pdump_stats *total)
699*10f726efSStephen Hemminger {
700*10f726efSStephen Hemminger 	uint64_t *sum = (uint64_t *)total;
701*10f726efSStephen Hemminger 	unsigned int i;
702*10f726efSStephen Hemminger 	uint64_t val;
703*10f726efSStephen Hemminger 	uint16_t qid;
704*10f726efSStephen Hemminger 
705*10f726efSStephen Hemminger 	for (qid = 0; qid < nq; qid++) {
706*10f726efSStephen Hemminger 		const uint64_t *perq = (const uint64_t *)&stats[port][qid];
707*10f726efSStephen Hemminger 
708*10f726efSStephen Hemminger 		for (i = 0; i < sizeof(*total) / sizeof(uint64_t); i++) {
709*10f726efSStephen Hemminger 			val = __atomic_load_n(&perq[i], __ATOMIC_RELAXED);
710*10f726efSStephen Hemminger 			sum[i] += val;
711*10f726efSStephen Hemminger 		}
712*10f726efSStephen Hemminger 	}
713*10f726efSStephen Hemminger }
714*10f726efSStephen Hemminger 
715*10f726efSStephen Hemminger int
716*10f726efSStephen Hemminger rte_pdump_stats(uint16_t port, struct rte_pdump_stats *stats)
717*10f726efSStephen Hemminger {
718*10f726efSStephen Hemminger 	struct rte_eth_dev_info dev_info;
719*10f726efSStephen Hemminger 	const struct rte_memzone *mz;
720*10f726efSStephen Hemminger 	int ret;
721*10f726efSStephen Hemminger 
722*10f726efSStephen Hemminger 	memset(stats, 0, sizeof(*stats));
723*10f726efSStephen Hemminger 	ret = rte_eth_dev_info_get(port, &dev_info);
724*10f726efSStephen Hemminger 	if (ret != 0) {
725*10f726efSStephen Hemminger 		PDUMP_LOG(ERR,
726*10f726efSStephen Hemminger 			  "Error during getting device (port %u) info: %s\n",
727*10f726efSStephen Hemminger 			  port, strerror(-ret));
728*10f726efSStephen Hemminger 		return ret;
729*10f726efSStephen Hemminger 	}
730*10f726efSStephen Hemminger 
731*10f726efSStephen Hemminger 	if (pdump_stats == NULL) {
732*10f726efSStephen Hemminger 		if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
733*10f726efSStephen Hemminger 			/* rte_pdump_init was not called */
734*10f726efSStephen Hemminger 			PDUMP_LOG(ERR, "pdump stats not initialized\n");
735*10f726efSStephen Hemminger 			rte_errno = EINVAL;
736*10f726efSStephen Hemminger 			return -1;
737*10f726efSStephen Hemminger 		}
738*10f726efSStephen Hemminger 
739*10f726efSStephen Hemminger 		/* secondary process looks up the memzone */
740*10f726efSStephen Hemminger 		mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
741*10f726efSStephen Hemminger 		if (mz == NULL) {
742*10f726efSStephen Hemminger 			/* rte_pdump_init was not called in primary process?? */
743*10f726efSStephen Hemminger 			PDUMP_LOG(ERR, "can not find pdump stats\n");
744*10f726efSStephen Hemminger 			rte_errno = EINVAL;
745*10f726efSStephen Hemminger 			return -1;
746*10f726efSStephen Hemminger 		}
747*10f726efSStephen Hemminger 		pdump_stats = mz->addr;
748*10f726efSStephen Hemminger 	}
749*10f726efSStephen Hemminger 
750*10f726efSStephen Hemminger 	pdump_sum_stats(port, dev_info.nb_rx_queues, pdump_stats->rx, stats);
751*10f726efSStephen Hemminger 	pdump_sum_stats(port, dev_info.nb_tx_queues, pdump_stats->tx, stats);
752*10f726efSStephen Hemminger 	return 0;
753*10f726efSStephen Hemminger }
754