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);
190e21c7c0SDavid Marchand #define RTE_LOGTYPE_PDUMP pdump_logtype
2099a2dd95SBruce Richardson
21*0f1dc8cbSTyler Retzlaff #define PDUMP_LOG_LINE(level, ...) \
22*0f1dc8cbSTyler Retzlaff RTE_LOG_LINE_PREFIX(level, PDUMP, "%s(): ", __func__, __VA_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];
7753caecb8SKonstantin 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
pdump_copy(uint16_t port_id,uint16_t queue,enum rte_pcapng_direction direction,struct rte_mbuf ** pkts,uint16_t nb_pkts,const struct pdump_rxtx_cbs * cbs,struct rte_pdump_stats * stats)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];
9299a2dd95SBruce Richardson struct rte_ring *ring;
9399a2dd95SBruce Richardson struct rte_mempool *mp;
9499a2dd95SBruce Richardson struct rte_mbuf *p;
9510f726efSStephen Hemminger uint64_t rcs[nb_pkts];
9699a2dd95SBruce Richardson
9710f726efSStephen Hemminger if (cbs->filter)
9810f726efSStephen Hemminger rte_bpf_exec_burst(cbs->filter, (void **)pkts, rcs, nb_pkts);
9910f726efSStephen Hemminger
10099a2dd95SBruce Richardson ring = cbs->ring;
10199a2dd95SBruce Richardson mp = cbs->mp;
10299a2dd95SBruce Richardson for (i = 0; i < nb_pkts; i++) {
10310f726efSStephen Hemminger /*
10410f726efSStephen Hemminger * This uses same BPF return value convention as socket filter
10510f726efSStephen Hemminger * and pcap_offline_filter.
10610f726efSStephen Hemminger * if program returns zero
10710f726efSStephen Hemminger * then packet doesn't match the filter (will be ignored).
10810f726efSStephen Hemminger */
10910f726efSStephen Hemminger if (cbs->filter && rcs[i] == 0) {
110938c55cbSTyler Retzlaff rte_atomic_fetch_add_explicit(&stats->filtered,
111938c55cbSTyler Retzlaff 1, rte_memory_order_relaxed);
11210f726efSStephen Hemminger continue;
11310f726efSStephen Hemminger }
11410f726efSStephen Hemminger
11510f726efSStephen Hemminger /*
11610f726efSStephen Hemminger * If using pcapng then want to wrap packets
11710f726efSStephen Hemminger * otherwise a simple copy.
11810f726efSStephen Hemminger */
11910f726efSStephen Hemminger if (cbs->ver == V2)
12010f726efSStephen Hemminger p = rte_pcapng_copy(port_id, queue,
12110f726efSStephen Hemminger pkts[i], mp, cbs->snaplen,
12216659193SStephen Hemminger direction, NULL);
12310f726efSStephen Hemminger else
12410f726efSStephen Hemminger p = rte_pktmbuf_copy(pkts[i], mp, 0, cbs->snaplen);
12510f726efSStephen Hemminger
12610f726efSStephen Hemminger if (unlikely(p == NULL))
127938c55cbSTyler Retzlaff rte_atomic_fetch_add_explicit(&stats->nombuf, 1, rte_memory_order_relaxed);
12810f726efSStephen Hemminger else
12999a2dd95SBruce Richardson dup_bufs[d_pkts++] = p;
13099a2dd95SBruce Richardson }
13199a2dd95SBruce Richardson
132938c55cbSTyler Retzlaff rte_atomic_fetch_add_explicit(&stats->accepted, d_pkts, rte_memory_order_relaxed);
13310f726efSStephen Hemminger
134b1824666SJoyce Kong ring_enq = rte_ring_enqueue_burst(ring, (void *)&dup_bufs[0], d_pkts, NULL);
13599a2dd95SBruce Richardson if (unlikely(ring_enq < d_pkts)) {
13699a2dd95SBruce Richardson unsigned int drops = d_pkts - ring_enq;
13799a2dd95SBruce Richardson
138938c55cbSTyler Retzlaff rte_atomic_fetch_add_explicit(&stats->ringfull, drops, rte_memory_order_relaxed);
13999a2dd95SBruce Richardson rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops);
14099a2dd95SBruce Richardson }
14199a2dd95SBruce Richardson }
14299a2dd95SBruce Richardson
14399a2dd95SBruce Richardson static uint16_t
pdump_rx(uint16_t port,uint16_t queue,struct rte_mbuf ** pkts,uint16_t nb_pkts,uint16_t max_pkts __rte_unused,void * user_params)14410f726efSStephen Hemminger pdump_rx(uint16_t port, uint16_t queue,
14599a2dd95SBruce Richardson struct rte_mbuf **pkts, uint16_t nb_pkts,
14610f726efSStephen Hemminger uint16_t max_pkts __rte_unused, void *user_params)
14799a2dd95SBruce Richardson {
14810f726efSStephen Hemminger const struct pdump_rxtx_cbs *cbs = user_params;
14910f726efSStephen Hemminger struct rte_pdump_stats *stats = &pdump_stats->rx[port][queue];
15010f726efSStephen Hemminger
15110f726efSStephen Hemminger pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_IN,
15210f726efSStephen Hemminger pkts, nb_pkts, cbs, stats);
15399a2dd95SBruce Richardson return nb_pkts;
15499a2dd95SBruce Richardson }
15599a2dd95SBruce Richardson
15699a2dd95SBruce Richardson static uint16_t
pdump_tx(uint16_t port,uint16_t queue,struct rte_mbuf ** pkts,uint16_t nb_pkts,void * user_params)15710f726efSStephen Hemminger pdump_tx(uint16_t port, uint16_t queue,
15899a2dd95SBruce Richardson struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
15999a2dd95SBruce Richardson {
16010f726efSStephen Hemminger const struct pdump_rxtx_cbs *cbs = user_params;
16110f726efSStephen Hemminger struct rte_pdump_stats *stats = &pdump_stats->tx[port][queue];
16210f726efSStephen Hemminger
16310f726efSStephen Hemminger pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_OUT,
16410f726efSStephen Hemminger pkts, nb_pkts, cbs, stats);
16599a2dd95SBruce Richardson return nb_pkts;
16699a2dd95SBruce Richardson }
16799a2dd95SBruce Richardson
16899a2dd95SBruce Richardson static int
pdump_register_rx_callbacks(enum pdump_version ver,uint16_t end_q,uint16_t port,uint16_t queue,struct rte_ring * ring,struct rte_mempool * mp,struct rte_bpf * filter,uint16_t operation,uint32_t snaplen)16910f726efSStephen Hemminger pdump_register_rx_callbacks(enum pdump_version ver,
17010f726efSStephen Hemminger uint16_t end_q, uint16_t port, uint16_t queue,
17199a2dd95SBruce Richardson struct rte_ring *ring, struct rte_mempool *mp,
17210f726efSStephen Hemminger struct rte_bpf *filter,
17310f726efSStephen Hemminger uint16_t operation, uint32_t snaplen)
17499a2dd95SBruce Richardson {
17599a2dd95SBruce Richardson uint16_t qid;
17699a2dd95SBruce Richardson
17799a2dd95SBruce Richardson qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
17899a2dd95SBruce Richardson for (; qid < end_q; qid++) {
17910f726efSStephen Hemminger struct pdump_rxtx_cbs *cbs = &rx_cbs[port][qid];
18010f726efSStephen Hemminger
18110f726efSStephen Hemminger if (operation == ENABLE) {
18299a2dd95SBruce Richardson if (cbs->cb) {
1830e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
1840e21c7c0SDavid Marchand "rx callback for port=%d queue=%d, already exists",
18599a2dd95SBruce Richardson port, qid);
18699a2dd95SBruce Richardson return -EEXIST;
18799a2dd95SBruce Richardson }
18810f726efSStephen Hemminger cbs->ver = ver;
18999a2dd95SBruce Richardson cbs->ring = ring;
19099a2dd95SBruce Richardson cbs->mp = mp;
19110f726efSStephen Hemminger cbs->snaplen = snaplen;
19210f726efSStephen Hemminger cbs->filter = filter;
19310f726efSStephen Hemminger
19499a2dd95SBruce Richardson cbs->cb = rte_eth_add_first_rx_callback(port, qid,
19599a2dd95SBruce Richardson pdump_rx, cbs);
19699a2dd95SBruce Richardson if (cbs->cb == NULL) {
1970e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
1980e21c7c0SDavid Marchand "failed to add rx callback, errno=%d",
19999a2dd95SBruce Richardson rte_errno);
20099a2dd95SBruce Richardson return rte_errno;
20199a2dd95SBruce Richardson }
20210f726efSStephen Hemminger } else if (operation == DISABLE) {
20399a2dd95SBruce Richardson int ret;
20499a2dd95SBruce Richardson
20599a2dd95SBruce Richardson if (cbs->cb == NULL) {
2060e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2070e21c7c0SDavid Marchand "no existing rx callback for port=%d queue=%d",
20899a2dd95SBruce Richardson port, qid);
20999a2dd95SBruce Richardson return -EINVAL;
21099a2dd95SBruce Richardson }
21199a2dd95SBruce Richardson ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
21299a2dd95SBruce Richardson if (ret < 0) {
2130e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2140e21c7c0SDavid Marchand "failed to remove rx callback, errno=%d",
21599a2dd95SBruce Richardson -ret);
21699a2dd95SBruce Richardson return ret;
21799a2dd95SBruce Richardson }
21899a2dd95SBruce Richardson cbs->cb = NULL;
21999a2dd95SBruce Richardson }
22099a2dd95SBruce Richardson }
22199a2dd95SBruce Richardson
22299a2dd95SBruce Richardson return 0;
22399a2dd95SBruce Richardson }
22499a2dd95SBruce Richardson
22599a2dd95SBruce Richardson static int
pdump_register_tx_callbacks(enum pdump_version ver,uint16_t end_q,uint16_t port,uint16_t queue,struct rte_ring * ring,struct rte_mempool * mp,struct rte_bpf * filter,uint16_t operation,uint32_t snaplen)22610f726efSStephen Hemminger pdump_register_tx_callbacks(enum pdump_version ver,
22710f726efSStephen Hemminger uint16_t end_q, uint16_t port, uint16_t queue,
22899a2dd95SBruce Richardson struct rte_ring *ring, struct rte_mempool *mp,
22910f726efSStephen Hemminger struct rte_bpf *filter,
23010f726efSStephen Hemminger uint16_t operation, uint32_t snaplen)
23199a2dd95SBruce Richardson {
23299a2dd95SBruce Richardson
23399a2dd95SBruce Richardson uint16_t qid;
23499a2dd95SBruce Richardson
23599a2dd95SBruce Richardson qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
23699a2dd95SBruce Richardson for (; qid < end_q; qid++) {
23710f726efSStephen Hemminger struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid];
23810f726efSStephen Hemminger
23910f726efSStephen Hemminger if (operation == ENABLE) {
24099a2dd95SBruce Richardson if (cbs->cb) {
2410e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2420e21c7c0SDavid Marchand "tx callback for port=%d queue=%d, already exists",
24399a2dd95SBruce Richardson port, qid);
24499a2dd95SBruce Richardson return -EEXIST;
24599a2dd95SBruce Richardson }
24610f726efSStephen Hemminger cbs->ver = ver;
24799a2dd95SBruce Richardson cbs->ring = ring;
24899a2dd95SBruce Richardson cbs->mp = mp;
24910f726efSStephen Hemminger cbs->snaplen = snaplen;
25010f726efSStephen Hemminger cbs->filter = filter;
25110f726efSStephen Hemminger
25299a2dd95SBruce Richardson cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
25399a2dd95SBruce Richardson cbs);
25499a2dd95SBruce Richardson if (cbs->cb == NULL) {
2550e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2560e21c7c0SDavid Marchand "failed to add tx callback, errno=%d",
25799a2dd95SBruce Richardson rte_errno);
25899a2dd95SBruce Richardson return rte_errno;
25999a2dd95SBruce Richardson }
26010f726efSStephen Hemminger } else if (operation == DISABLE) {
26199a2dd95SBruce Richardson int ret;
26299a2dd95SBruce Richardson
26399a2dd95SBruce Richardson if (cbs->cb == NULL) {
2640e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2650e21c7c0SDavid Marchand "no existing tx callback for port=%d queue=%d",
26699a2dd95SBruce Richardson port, qid);
26799a2dd95SBruce Richardson return -EINVAL;
26899a2dd95SBruce Richardson }
26999a2dd95SBruce Richardson ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
27099a2dd95SBruce Richardson if (ret < 0) {
2710e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2720e21c7c0SDavid Marchand "failed to remove tx callback, errno=%d",
27399a2dd95SBruce Richardson -ret);
27499a2dd95SBruce Richardson return ret;
27599a2dd95SBruce Richardson }
27699a2dd95SBruce Richardson cbs->cb = NULL;
27799a2dd95SBruce Richardson }
27899a2dd95SBruce Richardson }
27999a2dd95SBruce Richardson
28099a2dd95SBruce Richardson return 0;
28199a2dd95SBruce Richardson }
28299a2dd95SBruce Richardson
28399a2dd95SBruce Richardson static int
set_pdump_rxtx_cbs(const struct pdump_request * p)28499a2dd95SBruce Richardson set_pdump_rxtx_cbs(const struct pdump_request *p)
28599a2dd95SBruce Richardson {
28699a2dd95SBruce Richardson uint16_t nb_rx_q = 0, nb_tx_q = 0, end_q, queue;
28799a2dd95SBruce Richardson uint16_t port;
28899a2dd95SBruce Richardson int ret = 0;
28910f726efSStephen Hemminger struct rte_bpf *filter = NULL;
29099a2dd95SBruce Richardson uint32_t flags;
29199a2dd95SBruce Richardson uint16_t operation;
29299a2dd95SBruce Richardson struct rte_ring *ring;
29399a2dd95SBruce Richardson struct rte_mempool *mp;
29499a2dd95SBruce Richardson
29510f726efSStephen Hemminger /* Check for possible DPDK version mismatch */
29610f726efSStephen Hemminger if (!(p->ver == V1 || p->ver == V2)) {
2970e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
2980e21c7c0SDavid Marchand "incorrect client version %u", p->ver);
29910f726efSStephen Hemminger return -EINVAL;
30010f726efSStephen Hemminger }
30110f726efSStephen Hemminger
30210f726efSStephen Hemminger if (p->prm) {
30310f726efSStephen Hemminger if (p->prm->prog_arg.type != RTE_BPF_ARG_PTR_MBUF) {
3040e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
3050e21c7c0SDavid Marchand "invalid BPF program type: %u",
30610f726efSStephen Hemminger p->prm->prog_arg.type);
30710f726efSStephen Hemminger return -EINVAL;
30810f726efSStephen Hemminger }
30910f726efSStephen Hemminger
31010f726efSStephen Hemminger filter = rte_bpf_load(p->prm);
31110f726efSStephen Hemminger if (filter == NULL) {
3120e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "cannot load BPF filter: %s",
31310f726efSStephen Hemminger rte_strerror(rte_errno));
31410f726efSStephen Hemminger return -rte_errno;
31510f726efSStephen Hemminger }
31610f726efSStephen Hemminger }
31710f726efSStephen Hemminger
31899a2dd95SBruce Richardson flags = p->flags;
31999a2dd95SBruce Richardson operation = p->op;
32010f726efSStephen Hemminger queue = p->queue;
32110f726efSStephen Hemminger ring = p->ring;
32210f726efSStephen Hemminger mp = p->mp;
32310f726efSStephen Hemminger
32410f726efSStephen Hemminger ret = rte_eth_dev_get_port_by_name(p->device, &port);
32599a2dd95SBruce Richardson if (ret < 0) {
3260e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
3270e21c7c0SDavid Marchand "failed to get port id for device id=%s",
32810f726efSStephen Hemminger p->device);
32999a2dd95SBruce Richardson return -EINVAL;
33099a2dd95SBruce Richardson }
33199a2dd95SBruce Richardson
33299a2dd95SBruce Richardson /* validation if packet capture is for all queues */
33399a2dd95SBruce Richardson if (queue == RTE_PDUMP_ALL_QUEUES) {
33499a2dd95SBruce Richardson struct rte_eth_dev_info dev_info;
33599a2dd95SBruce Richardson
33699a2dd95SBruce Richardson ret = rte_eth_dev_info_get(port, &dev_info);
33799a2dd95SBruce Richardson if (ret != 0) {
3380e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
3390e21c7c0SDavid Marchand "Error during getting device (port %u) info: %s",
34099a2dd95SBruce Richardson port, strerror(-ret));
34199a2dd95SBruce Richardson return ret;
34299a2dd95SBruce Richardson }
34399a2dd95SBruce Richardson
34499a2dd95SBruce Richardson nb_rx_q = dev_info.nb_rx_queues;
34599a2dd95SBruce Richardson nb_tx_q = dev_info.nb_tx_queues;
34699a2dd95SBruce Richardson if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
3470e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
3480e21c7c0SDavid Marchand "number of rx queues cannot be 0");
34999a2dd95SBruce Richardson return -EINVAL;
35099a2dd95SBruce Richardson }
35199a2dd95SBruce Richardson if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
3520e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
3530e21c7c0SDavid Marchand "number of tx queues cannot be 0");
35499a2dd95SBruce Richardson return -EINVAL;
35599a2dd95SBruce Richardson }
35699a2dd95SBruce Richardson if ((nb_tx_q == 0 || nb_rx_q == 0) &&
35799a2dd95SBruce Richardson flags == RTE_PDUMP_FLAG_RXTX) {
3580e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
3590e21c7c0SDavid Marchand "both tx&rx queues must be non zero");
36099a2dd95SBruce Richardson return -EINVAL;
36199a2dd95SBruce Richardson }
36299a2dd95SBruce Richardson }
36399a2dd95SBruce Richardson
36499a2dd95SBruce Richardson /* register RX callback */
36599a2dd95SBruce Richardson if (flags & RTE_PDUMP_FLAG_RX) {
36699a2dd95SBruce Richardson end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
36710f726efSStephen Hemminger ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue,
36810f726efSStephen Hemminger ring, mp, filter,
36910f726efSStephen Hemminger operation, p->snaplen);
37099a2dd95SBruce Richardson if (ret < 0)
37199a2dd95SBruce Richardson return ret;
37299a2dd95SBruce Richardson }
37399a2dd95SBruce Richardson
37499a2dd95SBruce Richardson /* register TX callback */
37599a2dd95SBruce Richardson if (flags & RTE_PDUMP_FLAG_TX) {
37699a2dd95SBruce Richardson end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
37710f726efSStephen Hemminger ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue,
37810f726efSStephen Hemminger ring, mp, filter,
37910f726efSStephen Hemminger operation, p->snaplen);
38099a2dd95SBruce Richardson if (ret < 0)
38199a2dd95SBruce Richardson return ret;
38299a2dd95SBruce Richardson }
38399a2dd95SBruce Richardson
38499a2dd95SBruce Richardson return ret;
38599a2dd95SBruce Richardson }
38699a2dd95SBruce Richardson
38799a2dd95SBruce Richardson static int
pdump_server(const struct rte_mp_msg * mp_msg,const void * peer)38899a2dd95SBruce Richardson pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
38999a2dd95SBruce Richardson {
39099a2dd95SBruce Richardson struct rte_mp_msg mp_resp;
39199a2dd95SBruce Richardson const struct pdump_request *cli_req;
39299a2dd95SBruce Richardson struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
39399a2dd95SBruce Richardson
39499a2dd95SBruce Richardson /* recv client requests */
39599a2dd95SBruce Richardson if (mp_msg->len_param != sizeof(*cli_req)) {
3960e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "failed to recv from client");
39799a2dd95SBruce Richardson resp->err_value = -EINVAL;
39899a2dd95SBruce Richardson } else {
39999a2dd95SBruce Richardson cli_req = (const struct pdump_request *)mp_msg->param;
40099a2dd95SBruce Richardson resp->ver = cli_req->ver;
40199a2dd95SBruce Richardson resp->res_op = cli_req->op;
40299a2dd95SBruce Richardson resp->err_value = set_pdump_rxtx_cbs(cli_req);
40399a2dd95SBruce Richardson }
40499a2dd95SBruce Richardson
40510f726efSStephen Hemminger rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
40699a2dd95SBruce Richardson mp_resp.len_param = sizeof(*resp);
40799a2dd95SBruce Richardson mp_resp.num_fds = 0;
40899a2dd95SBruce Richardson if (rte_mp_reply(&mp_resp, peer) < 0) {
4090e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "failed to send to client:%s",
41099a2dd95SBruce Richardson strerror(rte_errno));
41199a2dd95SBruce Richardson return -1;
41299a2dd95SBruce Richardson }
41399a2dd95SBruce Richardson
41499a2dd95SBruce Richardson return 0;
41599a2dd95SBruce Richardson }
41699a2dd95SBruce Richardson
41799a2dd95SBruce Richardson int
rte_pdump_init(void)41899a2dd95SBruce Richardson rte_pdump_init(void)
41999a2dd95SBruce Richardson {
42010f726efSStephen Hemminger const struct rte_memzone *mz;
42199a2dd95SBruce Richardson int ret;
42299a2dd95SBruce Richardson
42310f726efSStephen Hemminger mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
42410f726efSStephen Hemminger rte_socket_id(), 0);
42510f726efSStephen Hemminger if (mz == NULL) {
4260e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics");
42710f726efSStephen Hemminger rte_errno = ENOMEM;
42810f726efSStephen Hemminger return -1;
42910f726efSStephen Hemminger }
43010f726efSStephen Hemminger pdump_stats = mz->addr;
43153caecb8SKonstantin Ananyev pdump_stats->mz = mz;
43210f726efSStephen 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
rte_pdump_uninit(void)44099a2dd95SBruce Richardson rte_pdump_uninit(void)
44199a2dd95SBruce Richardson {
44299a2dd95SBruce Richardson rte_mp_action_unregister(PDUMP_MP);
44399a2dd95SBruce Richardson
44453caecb8SKonstantin Ananyev if (pdump_stats != NULL) {
44553caecb8SKonstantin Ananyev rte_memzone_free(pdump_stats->mz);
44653caecb8SKonstantin Ananyev pdump_stats = NULL;
44753caecb8SKonstantin Ananyev }
44853caecb8SKonstantin Ananyev
44999a2dd95SBruce Richardson return 0;
45099a2dd95SBruce Richardson }
45199a2dd95SBruce Richardson
45299a2dd95SBruce Richardson static int
pdump_validate_ring_mp(struct rte_ring * ring,struct rte_mempool * mp)45399a2dd95SBruce Richardson pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
45499a2dd95SBruce Richardson {
45599a2dd95SBruce Richardson if (ring == NULL || mp == NULL) {
4560e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "NULL ring or mempool");
45799a2dd95SBruce Richardson rte_errno = EINVAL;
45899a2dd95SBruce Richardson return -1;
45999a2dd95SBruce Richardson }
460c47d7b90SAndrew Rybchenko if (mp->flags & RTE_MEMPOOL_F_SP_PUT ||
461c47d7b90SAndrew Rybchenko mp->flags & RTE_MEMPOOL_F_SC_GET) {
4620e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
46399a2dd95SBruce Richardson "mempool with SP or SC set not valid for pdump,"
4640e21c7c0SDavid Marchand "must have MP and MC set");
46599a2dd95SBruce Richardson rte_errno = EINVAL;
46699a2dd95SBruce Richardson return -1;
46799a2dd95SBruce Richardson }
46899a2dd95SBruce Richardson if (rte_ring_is_prod_single(ring) || rte_ring_is_cons_single(ring)) {
4690e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
47099a2dd95SBruce Richardson "ring with SP or SC set is not valid for pdump,"
4710e21c7c0SDavid Marchand "must have MP and MC set");
47299a2dd95SBruce Richardson rte_errno = EINVAL;
47399a2dd95SBruce Richardson return -1;
47499a2dd95SBruce Richardson }
47599a2dd95SBruce Richardson
47699a2dd95SBruce Richardson return 0;
47799a2dd95SBruce Richardson }
47899a2dd95SBruce Richardson
47999a2dd95SBruce Richardson static int
pdump_validate_flags(uint32_t flags)48099a2dd95SBruce Richardson pdump_validate_flags(uint32_t flags)
48199a2dd95SBruce Richardson {
48210f726efSStephen Hemminger if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) {
4830e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
4840e21c7c0SDavid Marchand "invalid flags, should be either rx/tx/rxtx");
48599a2dd95SBruce Richardson rte_errno = EINVAL;
48699a2dd95SBruce Richardson return -1;
48799a2dd95SBruce Richardson }
48899a2dd95SBruce Richardson
48910f726efSStephen Hemminger /* mask off the flags we know about */
49010f726efSStephen Hemminger if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) {
4910e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
4920e21c7c0SDavid Marchand "unknown flags: %#x", flags);
49310f726efSStephen Hemminger rte_errno = ENOTSUP;
49410f726efSStephen Hemminger return -1;
49510f726efSStephen Hemminger }
49610f726efSStephen Hemminger
49799a2dd95SBruce Richardson return 0;
49899a2dd95SBruce Richardson }
49999a2dd95SBruce Richardson
50099a2dd95SBruce Richardson static int
pdump_validate_port(uint16_t port,char * name)50199a2dd95SBruce Richardson pdump_validate_port(uint16_t port, char *name)
50299a2dd95SBruce Richardson {
50399a2dd95SBruce Richardson int ret = 0;
50499a2dd95SBruce Richardson
50599a2dd95SBruce Richardson if (port >= RTE_MAX_ETHPORTS) {
5060e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "Invalid port id %u", port);
50799a2dd95SBruce Richardson rte_errno = EINVAL;
50899a2dd95SBruce Richardson return -1;
50999a2dd95SBruce Richardson }
51099a2dd95SBruce Richardson
51199a2dd95SBruce Richardson ret = rte_eth_dev_get_name_by_port(port, name);
51299a2dd95SBruce Richardson if (ret < 0) {
5130e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "port %u to name mapping failed",
51499a2dd95SBruce Richardson port);
51599a2dd95SBruce Richardson rte_errno = EINVAL;
51699a2dd95SBruce Richardson return -1;
51799a2dd95SBruce Richardson }
51899a2dd95SBruce Richardson
51999a2dd95SBruce Richardson return 0;
52099a2dd95SBruce Richardson }
52199a2dd95SBruce Richardson
52299a2dd95SBruce Richardson static int
pdump_prepare_client_request(const char * device,uint16_t queue,uint32_t flags,uint32_t snaplen,uint16_t operation,struct rte_ring * ring,struct rte_mempool * mp,const struct rte_bpf_prm * prm)52310f726efSStephen Hemminger pdump_prepare_client_request(const char *device, uint16_t queue,
52410f726efSStephen Hemminger uint32_t flags, uint32_t snaplen,
52599a2dd95SBruce Richardson uint16_t operation,
52699a2dd95SBruce Richardson struct rte_ring *ring,
52799a2dd95SBruce Richardson struct rte_mempool *mp,
52810f726efSStephen Hemminger const struct rte_bpf_prm *prm)
52999a2dd95SBruce Richardson {
53099a2dd95SBruce Richardson int ret = -1;
53199a2dd95SBruce Richardson struct rte_mp_msg mp_req, *mp_rep;
53299a2dd95SBruce Richardson struct rte_mp_reply mp_reply;
53399a2dd95SBruce Richardson struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
53499a2dd95SBruce Richardson struct pdump_request *req = (struct pdump_request *)mp_req.param;
53599a2dd95SBruce Richardson struct pdump_response *resp;
53699a2dd95SBruce Richardson
5378a0cf0c4SStephen Hemminger if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
5380e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
5390e21c7c0SDavid Marchand "pdump enable/disable not allowed in primary process");
5408a0cf0c4SStephen Hemminger return -EINVAL;
5418a0cf0c4SStephen Hemminger }
5428a0cf0c4SStephen Hemminger
54310f726efSStephen Hemminger memset(req, 0, sizeof(*req));
54410f726efSStephen Hemminger
54510f726efSStephen Hemminger req->ver = (flags & RTE_PDUMP_FLAG_PCAPNG) ? V2 : V1;
54610f726efSStephen Hemminger req->flags = flags & RTE_PDUMP_FLAG_RXTX;
54799a2dd95SBruce Richardson req->op = operation;
54810f726efSStephen Hemminger req->queue = queue;
54910f726efSStephen Hemminger rte_strscpy(req->device, device, sizeof(req->device));
55010f726efSStephen Hemminger
55199a2dd95SBruce Richardson if ((operation & ENABLE) != 0) {
55210f726efSStephen Hemminger req->ring = ring;
55310f726efSStephen Hemminger req->mp = mp;
55410f726efSStephen Hemminger req->prm = prm;
55510f726efSStephen Hemminger req->snaplen = snaplen;
55699a2dd95SBruce Richardson }
55799a2dd95SBruce Richardson
55810f726efSStephen Hemminger rte_strscpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
55999a2dd95SBruce Richardson mp_req.len_param = sizeof(*req);
56099a2dd95SBruce Richardson mp_req.num_fds = 0;
56199a2dd95SBruce Richardson if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0) {
56299a2dd95SBruce Richardson mp_rep = &mp_reply.msgs[0];
56399a2dd95SBruce Richardson resp = (struct pdump_response *)mp_rep->param;
5645ec9575dSStephen Hemminger if (resp->err_value == 0)
56599a2dd95SBruce Richardson ret = 0;
5665ec9575dSStephen Hemminger else
5675ec9575dSStephen Hemminger rte_errno = -resp->err_value;
56899a2dd95SBruce Richardson free(mp_reply.msgs);
56999a2dd95SBruce Richardson }
57099a2dd95SBruce Richardson
57199a2dd95SBruce Richardson if (ret < 0)
5720e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
5730e21c7c0SDavid Marchand "client request for pdump enable/disable failed");
57499a2dd95SBruce Richardson return ret;
57599a2dd95SBruce Richardson }
57699a2dd95SBruce Richardson
57710f726efSStephen Hemminger /*
57810f726efSStephen Hemminger * There are two versions of this function, because although original API
57910f726efSStephen Hemminger * left place holder for future filter, it never checked the value.
58010f726efSStephen Hemminger * Therefore the API can't depend on application passing a non
58110f726efSStephen Hemminger * bogus value.
58210f726efSStephen Hemminger */
58310f726efSStephen Hemminger static int
pdump_enable(uint16_t port,uint16_t queue,uint32_t flags,uint32_t snaplen,struct rte_ring * ring,struct rte_mempool * mp,const struct rte_bpf_prm * prm)58410f726efSStephen Hemminger pdump_enable(uint16_t port, uint16_t queue,
58510f726efSStephen Hemminger uint32_t flags, uint32_t snaplen,
58610f726efSStephen Hemminger struct rte_ring *ring, struct rte_mempool *mp,
58710f726efSStephen Hemminger const struct rte_bpf_prm *prm)
58899a2dd95SBruce Richardson {
58999a2dd95SBruce Richardson int ret;
59099a2dd95SBruce Richardson char name[RTE_DEV_NAME_MAX_LEN];
59199a2dd95SBruce Richardson
59299a2dd95SBruce Richardson ret = pdump_validate_port(port, name);
59399a2dd95SBruce Richardson if (ret < 0)
59499a2dd95SBruce Richardson return ret;
59599a2dd95SBruce Richardson ret = pdump_validate_ring_mp(ring, mp);
59699a2dd95SBruce Richardson if (ret < 0)
59799a2dd95SBruce Richardson return ret;
59899a2dd95SBruce Richardson ret = pdump_validate_flags(flags);
59999a2dd95SBruce Richardson if (ret < 0)
60099a2dd95SBruce Richardson return ret;
60199a2dd95SBruce Richardson
60210f726efSStephen Hemminger if (snaplen == 0)
60310f726efSStephen Hemminger snaplen = UINT32_MAX;
60499a2dd95SBruce Richardson
60510f726efSStephen Hemminger return pdump_prepare_client_request(name, queue, flags, snaplen,
60610f726efSStephen Hemminger ENABLE, ring, mp, prm);
60799a2dd95SBruce Richardson }
60899a2dd95SBruce Richardson
60999a2dd95SBruce Richardson int
rte_pdump_enable(uint16_t port,uint16_t queue,uint32_t flags,struct rte_ring * ring,struct rte_mempool * mp,void * filter __rte_unused)61010f726efSStephen Hemminger rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags,
61199a2dd95SBruce Richardson struct rte_ring *ring,
61299a2dd95SBruce Richardson struct rte_mempool *mp,
61310f726efSStephen Hemminger void *filter __rte_unused)
61499a2dd95SBruce Richardson {
61510f726efSStephen Hemminger return pdump_enable(port, queue, flags, 0,
61610f726efSStephen Hemminger ring, mp, NULL);
61710f726efSStephen Hemminger }
61810f726efSStephen Hemminger
61910f726efSStephen Hemminger int
rte_pdump_enable_bpf(uint16_t port,uint16_t queue,uint32_t flags,uint32_t snaplen,struct rte_ring * ring,struct rte_mempool * mp,const struct rte_bpf_prm * prm)62010f726efSStephen Hemminger rte_pdump_enable_bpf(uint16_t port, uint16_t queue,
62110f726efSStephen Hemminger uint32_t flags, uint32_t snaplen,
62210f726efSStephen Hemminger struct rte_ring *ring,
62310f726efSStephen Hemminger struct rte_mempool *mp,
62410f726efSStephen Hemminger const struct rte_bpf_prm *prm)
62510f726efSStephen Hemminger {
62610f726efSStephen Hemminger return pdump_enable(port, queue, flags, snaplen,
62710f726efSStephen Hemminger ring, mp, prm);
62810f726efSStephen Hemminger }
62910f726efSStephen Hemminger
63010f726efSStephen Hemminger static int
pdump_enable_by_deviceid(const char * device_id,uint16_t queue,uint32_t flags,uint32_t snaplen,struct rte_ring * ring,struct rte_mempool * mp,const struct rte_bpf_prm * prm)63110f726efSStephen Hemminger pdump_enable_by_deviceid(const char *device_id, uint16_t queue,
63210f726efSStephen Hemminger uint32_t flags, uint32_t snaplen,
63310f726efSStephen Hemminger struct rte_ring *ring,
63410f726efSStephen Hemminger struct rte_mempool *mp,
63510f726efSStephen Hemminger const struct rte_bpf_prm *prm)
63610f726efSStephen Hemminger {
63710f726efSStephen Hemminger int ret;
63899a2dd95SBruce Richardson
63999a2dd95SBruce Richardson ret = pdump_validate_ring_mp(ring, mp);
64099a2dd95SBruce Richardson if (ret < 0)
64199a2dd95SBruce Richardson return ret;
64299a2dd95SBruce Richardson ret = pdump_validate_flags(flags);
64399a2dd95SBruce Richardson if (ret < 0)
64499a2dd95SBruce Richardson return ret;
64599a2dd95SBruce Richardson
646b2be63b5SStephen Hemminger if (snaplen == 0)
647b2be63b5SStephen Hemminger snaplen = UINT32_MAX;
648b2be63b5SStephen Hemminger
64910f726efSStephen Hemminger return pdump_prepare_client_request(device_id, queue, flags, snaplen,
65010f726efSStephen Hemminger ENABLE, ring, mp, prm);
65110f726efSStephen Hemminger }
65299a2dd95SBruce Richardson
65310f726efSStephen Hemminger int
rte_pdump_enable_by_deviceid(char * device_id,uint16_t queue,uint32_t flags,struct rte_ring * ring,struct rte_mempool * mp,void * filter __rte_unused)65410f726efSStephen Hemminger rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
65510f726efSStephen Hemminger uint32_t flags,
65610f726efSStephen Hemminger struct rte_ring *ring,
65710f726efSStephen Hemminger struct rte_mempool *mp,
65810f726efSStephen Hemminger void *filter __rte_unused)
65910f726efSStephen Hemminger {
66010f726efSStephen Hemminger return pdump_enable_by_deviceid(device_id, queue, flags, 0,
66110f726efSStephen Hemminger ring, mp, NULL);
66210f726efSStephen Hemminger }
66310f726efSStephen Hemminger
66410f726efSStephen Hemminger int
rte_pdump_enable_bpf_by_deviceid(const char * device_id,uint16_t queue,uint32_t flags,uint32_t snaplen,struct rte_ring * ring,struct rte_mempool * mp,const struct rte_bpf_prm * prm)66510f726efSStephen Hemminger rte_pdump_enable_bpf_by_deviceid(const char *device_id, uint16_t queue,
66610f726efSStephen Hemminger uint32_t flags, uint32_t snaplen,
66710f726efSStephen Hemminger struct rte_ring *ring,
66810f726efSStephen Hemminger struct rte_mempool *mp,
66910f726efSStephen Hemminger const struct rte_bpf_prm *prm)
67010f726efSStephen Hemminger {
67110f726efSStephen Hemminger return pdump_enable_by_deviceid(device_id, queue, flags, snaplen,
67210f726efSStephen Hemminger ring, mp, prm);
67399a2dd95SBruce Richardson }
67499a2dd95SBruce Richardson
67599a2dd95SBruce Richardson int
rte_pdump_disable(uint16_t port,uint16_t queue,uint32_t flags)67699a2dd95SBruce Richardson rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags)
67799a2dd95SBruce Richardson {
67899a2dd95SBruce Richardson int ret = 0;
67999a2dd95SBruce Richardson char name[RTE_DEV_NAME_MAX_LEN];
68099a2dd95SBruce Richardson
68199a2dd95SBruce Richardson ret = pdump_validate_port(port, name);
68299a2dd95SBruce Richardson if (ret < 0)
68399a2dd95SBruce Richardson return ret;
68499a2dd95SBruce Richardson ret = pdump_validate_flags(flags);
68599a2dd95SBruce Richardson if (ret < 0)
68699a2dd95SBruce Richardson return ret;
68799a2dd95SBruce Richardson
68810f726efSStephen Hemminger ret = pdump_prepare_client_request(name, queue, flags, 0,
68999a2dd95SBruce Richardson DISABLE, NULL, NULL, NULL);
69099a2dd95SBruce Richardson
69199a2dd95SBruce Richardson return ret;
69299a2dd95SBruce Richardson }
69399a2dd95SBruce Richardson
69499a2dd95SBruce Richardson int
rte_pdump_disable_by_deviceid(char * device_id,uint16_t queue,uint32_t flags)69599a2dd95SBruce Richardson rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
69699a2dd95SBruce Richardson uint32_t flags)
69799a2dd95SBruce Richardson {
69899a2dd95SBruce Richardson int ret = 0;
69999a2dd95SBruce Richardson
70099a2dd95SBruce Richardson ret = pdump_validate_flags(flags);
70199a2dd95SBruce Richardson if (ret < 0)
70299a2dd95SBruce Richardson return ret;
70399a2dd95SBruce Richardson
70410f726efSStephen Hemminger ret = pdump_prepare_client_request(device_id, queue, flags, 0,
70599a2dd95SBruce Richardson DISABLE, NULL, NULL, NULL);
70699a2dd95SBruce Richardson
70799a2dd95SBruce Richardson return ret;
70899a2dd95SBruce Richardson }
70910f726efSStephen Hemminger
71010f726efSStephen Hemminger static void
pdump_sum_stats(uint16_t port,uint16_t nq,struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],struct rte_pdump_stats * total)71110f726efSStephen Hemminger pdump_sum_stats(uint16_t port, uint16_t nq,
71210f726efSStephen Hemminger struct rte_pdump_stats stats[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
71310f726efSStephen Hemminger struct rte_pdump_stats *total)
71410f726efSStephen Hemminger {
71510f726efSStephen Hemminger uint64_t *sum = (uint64_t *)total;
71610f726efSStephen Hemminger unsigned int i;
71710f726efSStephen Hemminger uint64_t val;
71810f726efSStephen Hemminger uint16_t qid;
71910f726efSStephen Hemminger
72010f726efSStephen Hemminger for (qid = 0; qid < nq; qid++) {
721938c55cbSTyler Retzlaff const RTE_ATOMIC(uint64_t) *perq = (const uint64_t __rte_atomic *)&stats[port][qid];
72210f726efSStephen Hemminger
72310f726efSStephen Hemminger for (i = 0; i < sizeof(*total) / sizeof(uint64_t); i++) {
724938c55cbSTyler Retzlaff val = rte_atomic_load_explicit(&perq[i], rte_memory_order_relaxed);
72510f726efSStephen Hemminger sum[i] += val;
72610f726efSStephen Hemminger }
72710f726efSStephen Hemminger }
72810f726efSStephen Hemminger }
72910f726efSStephen Hemminger
73010f726efSStephen Hemminger int
rte_pdump_stats(uint16_t port,struct rte_pdump_stats * stats)73110f726efSStephen Hemminger rte_pdump_stats(uint16_t port, struct rte_pdump_stats *stats)
73210f726efSStephen Hemminger {
73310f726efSStephen Hemminger struct rte_eth_dev_info dev_info;
73410f726efSStephen Hemminger const struct rte_memzone *mz;
73510f726efSStephen Hemminger int ret;
73610f726efSStephen Hemminger
73710f726efSStephen Hemminger memset(stats, 0, sizeof(*stats));
73810f726efSStephen Hemminger ret = rte_eth_dev_info_get(port, &dev_info);
73910f726efSStephen Hemminger if (ret != 0) {
7400e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR,
7410e21c7c0SDavid Marchand "Error during getting device (port %u) info: %s",
74210f726efSStephen Hemminger port, strerror(-ret));
74310f726efSStephen Hemminger return ret;
74410f726efSStephen Hemminger }
74510f726efSStephen Hemminger
74610f726efSStephen Hemminger if (pdump_stats == NULL) {
74710f726efSStephen Hemminger if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
74810f726efSStephen Hemminger /* rte_pdump_init was not called */
7490e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "pdump stats not initialized");
75010f726efSStephen Hemminger rte_errno = EINVAL;
75110f726efSStephen Hemminger return -1;
75210f726efSStephen Hemminger }
75310f726efSStephen Hemminger
75410f726efSStephen Hemminger /* secondary process looks up the memzone */
75510f726efSStephen Hemminger mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
75610f726efSStephen Hemminger if (mz == NULL) {
75710f726efSStephen Hemminger /* rte_pdump_init was not called in primary process?? */
7580e21c7c0SDavid Marchand PDUMP_LOG_LINE(ERR, "can not find pdump stats");
75910f726efSStephen Hemminger rte_errno = EINVAL;
76010f726efSStephen Hemminger return -1;
76110f726efSStephen Hemminger }
76210f726efSStephen Hemminger pdump_stats = mz->addr;
76310f726efSStephen Hemminger }
76410f726efSStephen Hemminger
76510f726efSStephen Hemminger pdump_sum_stats(port, dev_info.nb_rx_queues, pdump_stats->rx, stats);
76610f726efSStephen Hemminger pdump_sum_stats(port, dev_info.nb_tx_queues, pdump_stats->tx, stats);
76710f726efSStephen Hemminger return 0;
76810f726efSStephen Hemminger }
769