From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id D5FB2A0C4D; Fri, 3 Sep 2021 02:47:50 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B7EAE410E6; Fri, 3 Sep 2021 02:47:41 +0200 (CEST) Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) by mails.dpdk.org (Postfix) with ESMTP id 37EE440DFD for ; Fri, 3 Sep 2021 02:47:39 +0200 (CEST) Received: by mail-pl1-f182.google.com with SMTP id k17so2286195pls.0 for ; Thu, 02 Sep 2021 17:47:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=FuhNhRpraSzn0b95FhD9sX5V3s3OU5oUWrA3zv85fJ0=; b=tJyecenwTAT+2zJSrDGd4m8VUaONsTFgWdaO0sPcf+W54aD2gQMgw3kToDQKcKZd4/ CZM1L4A/p8Sk1jyaGCtdCvst7PqjDXU7qEOs/CYr7wh8qaZN/gsdbw/f/ubKE+2sZXuZ lPgXhKQIQnLuPMq1XbNXeZaNXVvp3SKZLA/7I26KAjaifbBGSB3NqF/6OD3FWo7XYaBM NH1nFNmtpQs9ui3Z6zfdJTAhaN1VIGO3Yr72eE5rZ+CSxaTn+BgKJ1Pul80BRLBJ5QV/ ZrD3hBaN8FWIsSjqmrliCEmGVarOOKVjOZDL3jN9b7a1aReho6bFLv2aIzT+YiGOidUJ Ebzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=FuhNhRpraSzn0b95FhD9sX5V3s3OU5oUWrA3zv85fJ0=; b=S+ll3kOUaXZMD8ANQi7KdrApTsFiPKakcaVWmLG+uO7AvS/U8D7bpQe51H1llwE45x cG8oP2on5DNtyGGxAw1JIaMYZZHwzwdtX3fSwPFG1TxgkHapcIyUeSFedlTo2KB5J4FS eSzXc3pRNRUcOeyRwtRzIzc/0mj6aC2QLiX4M14mUe3Kv8uwftvpCm6dUy+EBEaPbKPm igLQs6o/lqI7PseCeOExTG8cFsoylIe3/NpFdwebUUKi1Toq32twg5K2bLZl3LQBSDrv HJa2YcUnbzZhu1c5Oim6ikTZzeWWU7JdsqCdaJ94nZJiV2Qv9snezBUhqRYt12d+izoA jSUg== X-Gm-Message-State: AOAM530eY6kRpcD4sWLmJ8SMRbEEZU2rSBq4wz6MyFWbPgpjEKxPohep OIWA3PHWwubdGe7czCt/Vhx6rCowEsFRYQ== X-Google-Smtp-Source: ABdhPJybHnFRJNSEw5dvB0uu4iMnVPg14Pp2e5SV23TCI74QzkIJm3YujYzyZCkr0UNAn20ane9Asg== X-Received: by 2002:a17:903:234d:b0:138:96ac:66c4 with SMTP id c13-20020a170903234d00b0013896ac66c4mr752458plh.18.1630630057444; Thu, 02 Sep 2021 17:47:37 -0700 (PDT) Received: from hermes.local (204-195-33-123.wavecable.com. [204.195.33.123]) by smtp.gmail.com with ESMTPSA id cq8sm3179033pjb.31.2021.09.02.17.47.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Sep 2021 17:47:36 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Date: Thu, 2 Sep 2021 17:47:29 -0700 Message-Id: <20210903004732.109023-3-stephen@networkplumber.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210903004732.109023-1-stephen@networkplumber.org> References: <20210903004732.109023-1-stephen@networkplumber.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-dev] [PATCH 2/5] pdump: support pcapng and filtering X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This enhances the DPDK pdump library to support new pcapng format and filtering via BPF. The internal client/server protocol is changed to support two versions: the original pdump basic version and a new pcapng version. The internal version number (not part of exposed API or ABI) is intentionally increased to cause any attempt to try mismatched primary/secondary process to fail. Add new API to do allow filtering of captured packets with DPDK BPF (eBPF) filter program. It keeps statistics on packets captured, filtered, and missed (because ring was full). Signed-off-by: Stephen Hemminger --- lib/meson.build | 4 +- lib/pdump/meson.build | 2 +- lib/pdump/rte_pdump.c | 386 +++++++++++++++++++++++++++++------------- lib/pdump/rte_pdump.h | 117 ++++++++++++- lib/pdump/version.map | 8 + 5 files changed, 394 insertions(+), 123 deletions(-) diff --git a/lib/meson.build b/lib/meson.build index 514be90b09ec..b59bec494275 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -26,6 +26,7 @@ libraries = [ 'timer', # eventdev depends on this 'acl', 'bbdev', + 'bpf', 'bitratestats', 'cfgfile', 'compressdev', @@ -43,7 +44,6 @@ libraries = [ 'member', 'pcapng', 'power', - 'pdump', 'rawdev', 'regexdev', 'rib', @@ -55,10 +55,10 @@ libraries = [ 'ipsec', # ipsec lib depends on net, crypto and security 'fib', #fib lib depends on rib 'port', # pkt framework libs which use other libs from above + 'pdump', # pdump lib depends on bpf pcapng 'table', 'pipeline', 'flow_classify', # flow_classify lib depends on pkt framework table lib - 'bpf', 'graph', 'node', ] diff --git a/lib/pdump/meson.build b/lib/pdump/meson.build index 3a95eabde6a6..51ceb2afdec5 100644 --- a/lib/pdump/meson.build +++ b/lib/pdump/meson.build @@ -3,4 +3,4 @@ sources = files('rte_pdump.c') headers = files('rte_pdump.h') -deps += ['ethdev'] +deps += ['ethdev', 'bpf', 'pcapng'] diff --git a/lib/pdump/rte_pdump.c b/lib/pdump/rte_pdump.c index 382217bc1564..3237c54af69e 100644 --- a/lib/pdump/rte_pdump.c +++ b/lib/pdump/rte_pdump.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "rte_pdump.h" @@ -27,30 +28,26 @@ enum pdump_operation { ENABLE = 2 }; +/* + * Note: version numbers intentionally start at 3 + * in order to catch any application built with older out + * version of DPDK using incompatiable client request format. + */ enum pdump_version { - V1 = 1 + PDUMP_CLIENT_LEGACY = 3, + PDUMP_CLIENT_PCAPNG = 4, }; struct pdump_request { uint16_t ver; uint16_t op; - uint32_t flags; - union pdump_data { - struct enable_v1 { - char device[RTE_DEV_NAME_MAX_LEN]; - uint16_t queue; - struct rte_ring *ring; - struct rte_mempool *mp; - void *filter; - } en_v1; - struct disable_v1 { - char device[RTE_DEV_NAME_MAX_LEN]; - uint16_t queue; - struct rte_ring *ring; - struct rte_mempool *mp; - void *filter; - } dis_v1; - } data; + uint16_t flags; + uint16_t queue; + struct rte_ring *ring; + struct rte_mempool *mp; + const struct rte_bpf *filter; + uint32_t snaplen; + char device[RTE_DEV_NAME_MAX_LEN]; }; struct pdump_response { @@ -63,36 +60,67 @@ static struct pdump_rxtx_cbs { struct rte_ring *ring; struct rte_mempool *mp; const struct rte_eth_rxtx_callback *cb; - void *filter; + const struct rte_bpf *filter; + enum pdump_version ver; + uint32_t snaplen; + struct rte_pdump_stats stats; } rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT], tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT]; -static inline void -pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params) +static void +pdump_copy(uint16_t port_id, uint16_t queue, + enum rte_pcapng_direction direction, + struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params) { unsigned int i; int ring_enq; uint16_t d_pkts = 0; struct rte_mbuf *dup_bufs[nb_pkts]; - struct pdump_rxtx_cbs *cbs; + struct pdump_rxtx_cbs *cbs = user_params; + uint64_t ts; struct rte_ring *ring; struct rte_mempool *mp; struct rte_mbuf *p; + uint64_t bpf_rc[nb_pkts]; + + if (cbs->filter && + !rte_bpf_exec_burst(cbs->filter, (void **)pkts, bpf_rc, nb_pkts)) + return; /* our work here is done */ - cbs = user_params; + ts = rte_get_tsc_cycles(); ring = cbs->ring; mp = cbs->mp; for (i = 0; i < nb_pkts; i++) { - p = rte_pktmbuf_copy(pkts[i], mp, 0, UINT32_MAX); - if (p) + /* + * Similar behavior to rte_bpf_eth callback. + * if BPF program returns zero value for a given packet, + * then it will be ignored. + */ + if (cbs->filter && bpf_rc[i] == 0) + continue; + + /* + * If using pcapng then want to wrap packets + * otherwise a simple copy. + */ + if (cbs->ver == PDUMP_CLIENT_PCAPNG) + p = rte_pcapng_copy(port_id, queue, + pkts[i], mp, cbs->snaplen, + ts, direction); + else + p = rte_pktmbuf_copy(pkts[i], mp, 0, cbs->snaplen); + + if (likely(p != NULL)) dup_bufs[d_pkts++] = p; } + cbs->stats.accepted += d_pkts; ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts, NULL); if (unlikely(ring_enq < d_pkts)) { unsigned int drops = d_pkts - ring_enq; + cbs->stats.missed += drops; PDUMP_LOG(DEBUG, "only %d of packets enqueued to ring\n", ring_enq); rte_pktmbuf_free_bulk(&dup_bufs[ring_enq], drops); @@ -100,43 +128,50 @@ pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params) } static uint16_t -pdump_rx(uint16_t port __rte_unused, uint16_t qidx __rte_unused, +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) { - pdump_copy(pkts, nb_pkts, user_params); + pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_IN, + pkts, nb_pkts, user_params); return nb_pkts; } static uint16_t -pdump_tx(uint16_t port __rte_unused, uint16_t qidx __rte_unused, +pdump_tx(uint16_t port, uint16_t queue, struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params) { - pdump_copy(pkts, nb_pkts, user_params); + pdump_copy(port, queue, RTE_PCAPNG_DIRECTION_OUT, + pkts, nb_pkts, user_params); return nb_pkts; } static int -pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, - struct rte_ring *ring, struct rte_mempool *mp, - uint16_t operation) +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, + uint16_t operation, uint32_t snaplen) { uint16_t qid; - struct pdump_rxtx_cbs *cbs = NULL; qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue; for (; qid < end_q; qid++) { - cbs = &rx_cbs[port][qid]; - if (cbs && operation == ENABLE) { + struct pdump_rxtx_cbs *cbs = &rx_cbs[port][qid]; + + if (operation == ENABLE) { if (cbs->cb) { PDUMP_LOG(ERR, "rx callback for port=%d queue=%d, already exists\n", port, qid); return -EEXIST; } + cbs->ver = ver; cbs->ring = ring; cbs->mp = mp; + cbs->snaplen = snaplen; + memset(&cbs->stats, 0, sizeof(cbs->stats)); + cbs->cb = rte_eth_add_first_rx_callback(port, qid, pdump_rx, cbs); if (cbs->cb == NULL) { @@ -145,8 +180,7 @@ pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, rte_errno); return rte_errno; } - } - if (cbs && operation == DISABLE) { + } else if (operation == DISABLE) { int ret; if (cbs->cb == NULL) { @@ -170,26 +204,30 @@ pdump_register_rx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, } static int -pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, - struct rte_ring *ring, struct rte_mempool *mp, - uint16_t operation) +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, + uint16_t operation, uint32_t snaplen) { uint16_t qid; - struct pdump_rxtx_cbs *cbs = NULL; qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue; for (; qid < end_q; qid++) { - cbs = &tx_cbs[port][qid]; - if (cbs && operation == ENABLE) { + struct pdump_rxtx_cbs *cbs = &tx_cbs[port][qid]; + + if (operation == ENABLE) { if (cbs->cb) { PDUMP_LOG(ERR, "tx callback for port=%d queue=%d, already exists\n", port, qid); return -EEXIST; } + cbs->ver = ver; cbs->ring = ring; cbs->mp = mp; + cbs->snaplen = snaplen; + memset(&cbs->stats, 0, sizeof(cbs->stats)); cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx, cbs); if (cbs->cb == NULL) { @@ -198,8 +236,7 @@ pdump_register_tx_callbacks(uint16_t end_q, uint16_t port, uint16_t queue, rte_errno); return rte_errno; } - } - if (cbs && operation == DISABLE) { + } else if (operation == DISABLE) { int ret; if (cbs->cb == NULL) { @@ -233,32 +270,25 @@ set_pdump_rxtx_cbs(const struct pdump_request *p) struct rte_ring *ring; struct rte_mempool *mp; + if (!(p->ver == PDUMP_CLIENT_LEGACY || + p->ver == PDUMP_CLIENT_PCAPNG)) { + PDUMP_LOG(ERR, + "incorrect client version %u\n", p->ver); + return -EINVAL; + } + flags = p->flags; operation = p->op; - if (operation == ENABLE) { - ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device, - &port); - if (ret < 0) { - PDUMP_LOG(ERR, - "failed to get port id for device id=%s\n", - p->data.en_v1.device); - return -EINVAL; - } - queue = p->data.en_v1.queue; - ring = p->data.en_v1.ring; - mp = p->data.en_v1.mp; - } else { - ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device, - &port); - if (ret < 0) { - PDUMP_LOG(ERR, - "failed to get port id for device id=%s\n", - p->data.dis_v1.device); - return -EINVAL; - } - queue = p->data.dis_v1.queue; - ring = p->data.dis_v1.ring; - mp = p->data.dis_v1.mp; + queue = p->queue; + ring = p->ring; + mp = p->mp; + + ret = rte_eth_dev_get_port_by_name(p->device, &port); + if (ret < 0) { + PDUMP_LOG(ERR, + "failed to get port id for device id=%s\n", + p->device); + return -EINVAL; } /* validation if packet capture is for all queues */ @@ -296,8 +326,8 @@ set_pdump_rxtx_cbs(const struct pdump_request *p) /* register RX callback */ if (flags & RTE_PDUMP_FLAG_RX) { end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1; - ret = pdump_register_rx_callbacks(end_q, port, queue, ring, mp, - operation); + ret = pdump_register_rx_callbacks(p->ver, end_q, port, queue, ring, mp, + operation, p->snaplen); if (ret < 0) return ret; } @@ -305,8 +335,8 @@ set_pdump_rxtx_cbs(const struct pdump_request *p) /* register TX callback */ if (flags & RTE_PDUMP_FLAG_TX) { end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1; - ret = pdump_register_tx_callbacks(end_q, port, queue, ring, mp, - operation); + ret = pdump_register_tx_callbacks(p->ver, end_q, port, queue, ring, mp, + operation, p->snaplen); if (ret < 0) return ret; } @@ -349,6 +379,8 @@ rte_pdump_init(void) { int ret; + rte_pcapng_init(); + ret = rte_mp_action_register(PDUMP_MP, pdump_server); if (ret && rte_errno != ENOTSUP) return -1; @@ -392,14 +424,21 @@ pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp) static int pdump_validate_flags(uint32_t flags) { - if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX && - flags != RTE_PDUMP_FLAG_RXTX) { + if ((flags & RTE_PDUMP_FLAG_RXTX) == 0) { PDUMP_LOG(ERR, "invalid flags, should be either rx/tx/rxtx\n"); rte_errno = EINVAL; return -1; } + /* mask off the flags we know about */ + if (flags & ~(RTE_PDUMP_FLAG_RXTX | RTE_PDUMP_FLAG_PCAPNG)) { + PDUMP_LOG(ERR, + "unknown flags: %#x\n", flags); + rte_errno = ENOTSUP; + return -1; + } + return 0; } @@ -426,12 +465,12 @@ pdump_validate_port(uint16_t port, char *name) } static int -pdump_prepare_client_request(char *device, uint16_t queue, - uint32_t flags, - uint16_t operation, - struct rte_ring *ring, - struct rte_mempool *mp, - void *filter) +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 *filter) { int ret = -1; struct rte_mp_msg mp_req, *mp_rep; @@ -440,23 +479,23 @@ pdump_prepare_client_request(char *device, uint16_t queue, struct pdump_request *req = (struct pdump_request *)mp_req.param; struct pdump_response *resp; - req->ver = 1; - req->flags = flags; + memset(req, 0, sizeof(*req)); + if (flags & RTE_PDUMP_FLAG_PCAPNG) + req->ver = PDUMP_CLIENT_PCAPNG; + else + req->ver = PDUMP_CLIENT_LEGACY; + + req->flags = flags & RTE_PDUMP_FLAG_RXTX; req->op = operation; + req->queue = queue; + strlcpy(req->device, device,sizeof(req->device)); + if ((operation & ENABLE) != 0) { - strlcpy(req->data.en_v1.device, device, - sizeof(req->data.en_v1.device)); - req->data.en_v1.queue = queue; - req->data.en_v1.ring = ring; - req->data.en_v1.mp = mp; - req->data.en_v1.filter = filter; - } else { - strlcpy(req->data.dis_v1.device, device, - sizeof(req->data.dis_v1.device)); - req->data.dis_v1.queue = queue; - req->data.dis_v1.ring = NULL; - req->data.dis_v1.mp = NULL; - req->data.dis_v1.filter = NULL; + req->queue = queue; + req->ring = ring; + req->mp = mp; + req->filter = filter; + req->snaplen = snaplen; } strlcpy(mp_req.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN); @@ -477,11 +516,17 @@ pdump_prepare_client_request(char *device, uint16_t queue, return ret; } -int -rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags, - struct rte_ring *ring, - struct rte_mempool *mp, - void *filter) +/* + * There are two versions of this function, because although original API + * left place holder for future filter, it never checked the value. + * Therefore the API can't depend on application passing a non + * bogus value. + */ +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 *filter) { int ret; char name[RTE_DEV_NAME_MAX_LEN]; @@ -496,20 +541,42 @@ rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags, if (ret < 0) return ret; - ret = pdump_prepare_client_request(name, queue, flags, - ENABLE, ring, mp, filter); + if (snaplen == 0) + snaplen = UINT32_MAX; - return ret; + return pdump_prepare_client_request(name, queue, flags, snaplen, + ENABLE, ring, mp, filter); } 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_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags, + struct rte_ring *ring, + struct rte_mempool *mp, + void *filter __rte_unused) { - int ret = 0; + return pdump_enable(port, queue, flags, 0, + ring, mp, NULL); +} + +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 *filter) +{ + return pdump_enable(port, queue, flags, snaplen, + ring, mp, filter); +} + +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 *filter) +{ + int ret; ret = pdump_validate_ring_mp(ring, mp); if (ret < 0) @@ -518,10 +585,30 @@ rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue, if (ret < 0) return ret; - ret = pdump_prepare_client_request(device_id, queue, flags, - ENABLE, ring, mp, filter); + return pdump_prepare_client_request(device_id, queue, flags, snaplen, + ENABLE, ring, mp, filter); +} - return ret; +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) +{ + return pdump_enable_by_deviceid(device_id, queue, flags, 0, + ring, mp, NULL); +} + +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 *filter) +{ + return pdump_enable_by_deviceid(device_id, queue, flags, snaplen, + ring, mp, filter); } int @@ -537,8 +624,8 @@ rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags) if (ret < 0) return ret; - ret = pdump_prepare_client_request(name, queue, flags, - DISABLE, NULL, NULL, NULL); + ret = pdump_prepare_client_request(name, queue, flags, 0, + DISABLE, NULL, NULL, NULL); return ret; } @@ -553,8 +640,73 @@ rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue, if (ret < 0) return ret; - ret = pdump_prepare_client_request(device_id, queue, flags, - DISABLE, NULL, NULL, NULL); + ret = pdump_prepare_client_request(device_id, queue, flags, 0, + DISABLE, NULL, NULL, NULL); return ret; } + +static void +pdump_sum_stats(struct rte_pdump_stats *total, + const struct pdump_rxtx_cbs *cbs, + uint16_t nq) +{ + uint16_t qid; + + memset(total, 0, sizeof(*total)); + + for (qid = 0; qid < nq; qid++) { + total->received += cbs[qid].stats.received; + total->missed += cbs[qid].stats.missed; + total->accepted += cbs[qid].stats.accepted; + } +} + +int +rte_pdump_get_stats(uint16_t port, uint16_t queue, + struct rte_pdump_stats *rx_stats, + struct rte_pdump_stats *tx_stats) +{ + uint16_t nb_rx_q = 0, nb_tx_q = 0; + + if (port >= RTE_MAX_ETHPORTS) { + PDUMP_LOG(ERR, "Invalid port id %u\n", port); + rte_errno = EINVAL; + return -1; + } + + if (queue == RTE_PDUMP_ALL_QUEUES) { + struct rte_eth_dev_info dev_info; + int ret; + + ret = rte_eth_dev_info_get(port, &dev_info); + if (ret != 0) { + PDUMP_LOG(ERR, + "Error during getting device (port %u) info: %s\n", + port, strerror(-ret)); + return ret; + } + nb_rx_q = dev_info.nb_rx_queues; + nb_tx_q = dev_info.nb_tx_queues; + } else if (queue >= RTE_MAX_QUEUES_PER_PORT) { + PDUMP_LOG(ERR, "Invalid queue id %u\n", queue); + rte_errno = EINVAL; + return -1; + } + + if (rx_stats) { + if (queue == RTE_PDUMP_ALL_QUEUES) + pdump_sum_stats(rx_stats, &rx_cbs[port][0], nb_rx_q); + else + *rx_stats = rx_cbs[port][queue].stats; + } + + if (tx_stats) { + if (queue == RTE_PDUMP_ALL_QUEUES) + pdump_sum_stats(tx_stats, &tx_cbs[port][0], nb_tx_q); + else + *tx_stats = tx_cbs[port][queue].stats; + } + + return 0; +} diff --git a/lib/pdump/rte_pdump.h b/lib/pdump/rte_pdump.h index 6b00fc17aeb2..992331fddffb 100644 --- a/lib/pdump/rte_pdump.h +++ b/lib/pdump/rte_pdump.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -26,7 +27,9 @@ enum { RTE_PDUMP_FLAG_RX = 1, /* receive direction */ RTE_PDUMP_FLAG_TX = 2, /* transmit direction */ /* both receive and transmit directions */ - RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX) + RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX), + + RTE_PDUMP_FLAG_PCAPNG = 4, /* format for pcapng */ }; /** @@ -68,7 +71,7 @@ rte_pdump_uninit(void); * @param mp * mempool on to which original packets will be mirrored or duplicated. * @param filter - * place holder for packet filtering. + * Unused should be NULL. * * @return * 0 on success, -1 on error, rte_errno is set accordingly. @@ -80,6 +83,42 @@ rte_pdump_enable(uint16_t port, uint16_t queue, uint32_t flags, struct rte_mempool *mp, void *filter); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Enables packet capturing on given port and queue with filtering. + * + * @param port + * port on which packet capturing should be enabled. + * @param queue + * queue of a given port on which packet capturing should be enabled. + * users should pass on value UINT16_MAX to enable packet capturing on all + * queues of a given port. + * @param flags + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX + * on which packet capturing should be enabled for a given port and queue. + * @param snaplen + * snapshot length. No more than snaplen bytes of the network packet + * will be saved. Use 0 or 262144 to capture all of the packet. + * @param ring + * ring on which captured packets will be enqueued for user. + * @param mp + * mempool on to which original packets will be mirrored or duplicated. + * @param filter + * BPF filter to run to filter packes (can be NULL) + * + * @return + * 0 on success, -1 on error, rte_errno is set accordingly. + */ +__rte_experimental +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 *filter); + /** * Disables packet capturing on given port and queue. * @@ -118,7 +157,7 @@ rte_pdump_disable(uint16_t port, uint16_t queue, uint32_t flags); * @param mp * mempool on to which original packets will be mirrored or duplicated. * @param filter - * place holder for packet filtering. + * unused should be NULL * * @return * 0 on success, -1 on error, rte_errno is set accordingly. @@ -131,6 +170,44 @@ rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue, struct rte_mempool *mp, void *filter); +/** + * @warning + * @b EXPERIMENTAL: this API may change, or be removed, without prior notice + * + * Enables packet capturing on given device id and queue with filtering. + * device_id can be name or pci address of device. + * + * @param device_id + * device id on which packet capturing should be enabled. + * @param queue + * queue of a given device id on which packet capturing should be enabled. + * users should pass on value UINT16_MAX to enable packet capturing on all + * queues of a given device id. + * @param flags + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX + * on which packet capturing should be enabled for a given port and queue. + * @param snaplen + * snapshot length. No more than snaplen bytes of the network packet + * will be saved. Use 0 or 262144 to capture all of the packet. + * @param ring + * ring on which captured packets will be enqueued for user. + * @param mp + * mempool on to which original packets will be mirrored or duplicated. + * @param filter + * BPF filter to run to filter packes (can be NULL) + * + * @return + * 0 on success, -1 on error, rte_errno is set accordingly. + */ +__rte_experimental +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 *filter); + + /** * Disables packet capturing on given device_id and queue. * device_id can be name or pci address of device. @@ -153,6 +230,40 @@ int rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue, uint32_t flags); +struct rte_pdump_stats { + uint64_t received; /**< callback called */ + uint64_t accepted; /**< allowed by filter */ + uint64_t missed; /**< ring full */ +}; + +/** + * Query packet capture statistics. + * + * @param port + * port on which packet capturing should be enabled. + * @param queue + * queue of a given port on which packet capturing should be enabled. + * users should pass on value UINT16_MAX to enable packet capturing on all + * queues of a given port. + * @param rx_stats + * A pointer to a structure of type *rte_pdump_stats* to be filled with + * the values of the capture statistics: + * - *received* with the total of received packets. + * - *accepted* with the total of packets matched by the filter. + * - *missed* with the total of packets missed because of ring full. + * @param tx_stats + * - *received* with the total of transmitted packets. + * - *accepted* with the total of packets matched by the filter. + * - *missed* with the total of packets missed because of ring full. + * @return + * Zero if successful. Non-zero otherwise. + */ +__rte_experimental +int +rte_pdump_get_stats(uint16_t port, uint16_t queue, + struct rte_pdump_stats *rx_stats, + struct rte_pdump_stats *tx_stats); + #ifdef __cplusplus } #endif diff --git a/lib/pdump/version.map b/lib/pdump/version.map index f0a9d12c9a9e..b4c20b56f237 100644 --- a/lib/pdump/version.map +++ b/lib/pdump/version.map @@ -10,3 +10,11 @@ DPDK_22 { local: *; }; + +EXPERIMENTAL { + global: + + rte_pdump_enable_bpf; + rte_pdump_enable_bpf_by_deviceid; + rte_pdump_get_stats; +}; -- 2.30.2