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