From patchwork Tue Apr 5 12:30:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 109147 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E519DA0509; Tue, 5 Apr 2022 14:30:08 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 78E9240F35; Tue, 5 Apr 2022 14:30:08 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id 31CEF40DF6 for ; Tue, 5 Apr 2022 14:30:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1649161806; x=1680697806; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=Xp/wjiLaSYg9aMxxnlefhSoA+Q3Unk5nofpZyZ18sr8=; b=B7OfRoannpzvcEcUuBTaryVy1Jx9IeCp7AiZ66K5lObSrD9zuA73UJcM gBg9QTh/MblSxPmSrro7jMnL9FiZgkzPZlz3+RYIatLm+43DlC/PwTrbz cA35oKyoMk9fPZQnfUUGfeSvB7gVUg/emrFq7Blz5mt28HscFDIikacEI smnxDgQadB/LM/Z9+5u0KDEsvez4naZIPNanKU1ngHFtLWG0kqKj4aC26 8kP3/ft+T4if9hm2riBD9piAGvY+pyISygBcDf9B6Qn5ttswoYU96hn5s WeIdl90ZpTKPhm6nOkEpLfue7kHKOQEce7aoOFe5IBufxUhkF6qnJ6Lw0 Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10307"; a="259567319" X-IronPort-AV: E=Sophos;i="5.90,236,1643702400"; d="scan'208";a="259567319" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Apr 2022 05:30:05 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,236,1643702400"; d="scan'208";a="523441133" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga002.jf.intel.com with ESMTP; 05 Apr 2022 05:30:03 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Cc: Kamalakannan R Subject: [PATCH V2 1/3] port: support packet mirroring Date: Tue, 5 Apr 2022 13:30:00 +0100 Message-Id: <20220405123002.40671-1-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220304180623.74893-1-cristian.dumitrescu@intel.com> References: <20220304180623.74893-1-cristian.dumitrescu@intel.com> 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 Add packet clone operation to the output ports in order to support packet mirroring. Signed-off-by: Cristian Dumitrescu Signed-off-by: Kamalakannan R --- lib/port/rte_swx_port.h | 37 ++++++++++++++++ lib/port/rte_swx_port_ethdev.c | 67 ++++++++++++++++++++++++++++- lib/port/rte_swx_port_fd.c | 65 +++++++++++++++++++++++++++- lib/port/rte_swx_port_ring.c | 65 +++++++++++++++++++++++++++- lib/port/rte_swx_port_source_sink.c | 51 +++++++++++++++++++++- 5 files changed, 281 insertions(+), 4 deletions(-) diff --git a/lib/port/rte_swx_port.h b/lib/port/rte_swx_port.h index ecf109d2ca..2c94335ffd 100644 --- a/lib/port/rte_swx_port.h +++ b/lib/port/rte_swx_port.h @@ -147,6 +147,31 @@ typedef void (*rte_swx_port_out_pkt_tx_t)(void *port, struct rte_swx_pkt *pkt); +/** + * Output port packet fast clone and transmit + * + * @param[in] port + * Output port handle. + * @param[in] pkt + * Packet to be transmitted. + */ +typedef void +(*rte_swx_port_out_pkt_fast_clone_tx_t)(void *port, + struct rte_swx_pkt *pkt); + +/** + * Output port packet clone and transmit + * + * @param[in] port + * Output port handle. + * @param[in] pkt + * Packet to be transmitted. + */ +typedef void +(*rte_swx_port_out_pkt_clone_tx_t)(void *port, + struct rte_swx_pkt *pkt, + uint32_t truncation_length); + /** * Output port flush * @@ -163,6 +188,12 @@ struct rte_swx_port_out_stats { /** Number of bytes. */ uint64_t n_bytes; + + /** Number of packets cloned successfully. */ + uint64_t n_pkts_clone; + + /** Number of packets with clone errors. */ + uint64_t n_pkts_clone_err; }; /** @@ -188,6 +219,12 @@ struct rte_swx_port_out_ops { /** Packet transmission. Must be non-NULL. */ rte_swx_port_out_pkt_tx_t pkt_tx; + /** Packet fast clone and transmission. Must be non-NULL. */ + rte_swx_port_out_pkt_fast_clone_tx_t pkt_fast_clone_tx; + + /** Packet clone and transmission. Must be non-NULL. */ + rte_swx_port_out_pkt_clone_tx_t pkt_clone_tx; + /** Flush. May be NULL. */ rte_swx_port_out_flush_t flush; diff --git a/lib/port/rte_swx_port_ethdev.c b/lib/port/rte_swx_port_ethdev.c index 18d1c0b5db..ca4a43ac4f 100644 --- a/lib/port/rte_swx_port_ethdev.c +++ b/lib/port/rte_swx_port_ethdev.c @@ -252,8 +252,8 @@ writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) if (TRACE_LEVEL) rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); m->pkt_len = pkt->length; - m->data_len = (uint16_t)pkt->length; m->data_off = (uint16_t)pkt->offset; p->stats.n_pkts++; @@ -264,6 +264,69 @@ writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) __writer_flush(p); } +static void +writer_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle; + + TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u) (fast clone)\n", + (uint32_t)p->params.port_id, + (uint32_t)p->params.queue_id, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + rte_pktmbuf_refcnt_update(m, 1); + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + + p->pkts[p->n_pkts++] = m; + if (p->n_pkts == (int)p->params.burst_size) + __writer_flush(p); +} + +static void +writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle, *m_clone; + + TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u) (clone)\n", + (uint32_t)p->params.port_id, + (uint32_t)p->params.queue_id, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + + m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length); + if (!m_clone) { + p->stats.n_pkts_clone_err++; + return; + } + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + + p->pkts[p->n_pkts++] = m_clone; + if (p->n_pkts == (int)p->params.burst_size) + __writer_flush(p); +} + static void writer_flush(void *port) { @@ -308,6 +371,8 @@ struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops = { .create = writer_create, .free = writer_free, .pkt_tx = writer_pkt_tx, + .pkt_fast_clone_tx = writer_pkt_fast_clone_tx, + .pkt_clone_tx = writer_pkt_clone_tx, .flush = writer_flush, .stats_read = writer_stats_read, }; diff --git a/lib/port/rte_swx_port_fd.c b/lib/port/rte_swx_port_fd.c index 51bcd3bb7b..1ee5086684 100644 --- a/lib/port/rte_swx_port_fd.c +++ b/lib/port/rte_swx_port_fd.c @@ -237,8 +237,8 @@ writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) if (TRACE_LEVEL) rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); m->pkt_len = pkt->length; - m->data_len = (uint16_t)pkt->length; m->data_off = (uint16_t)pkt->offset; p->stats.n_pkts++; @@ -249,6 +249,67 @@ writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) __writer_flush(p); } +static void +writer_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle; + + TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (fast clone)\n", + (uint32_t)p->params.fd, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + rte_pktmbuf_refcnt_update(m, 1); + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + + p->pkts[p->n_pkts++] = m; + if (p->n_pkts == p->params.burst_size) + __writer_flush(p); +} + +static void +writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle, *m_clone; + + TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (clone)\n", + (uint32_t)p->params.fd, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + + m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length); + if (!m_clone) { + p->stats.n_pkts_clone_err++; + return; + } + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + + p->pkts[p->n_pkts++] = m_clone; + if (p->n_pkts == p->params.burst_size) + __writer_flush(p); +} + static void writer_flush(void *port) { @@ -293,6 +354,8 @@ struct rte_swx_port_out_ops rte_swx_port_fd_writer_ops = { .create = writer_create, .free = writer_free, .pkt_tx = writer_pkt_tx, + .pkt_fast_clone_tx = writer_pkt_fast_clone_tx, + .pkt_clone_tx = writer_pkt_clone_tx, .flush = writer_flush, .stats_read = writer_stats_read, }; diff --git a/lib/port/rte_swx_port_ring.c b/lib/port/rte_swx_port_ring.c index 8a076a2135..c62fb3d8c8 100644 --- a/lib/port/rte_swx_port_ring.c +++ b/lib/port/rte_swx_port_ring.c @@ -252,8 +252,8 @@ writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) if (TRACE_LEVEL) rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); m->pkt_len = pkt->length; - m->data_len = (uint16_t)pkt->length; m->data_off = (uint16_t)pkt->offset; p->stats.n_pkts++; @@ -264,6 +264,67 @@ writer_pkt_tx(void *port, struct rte_swx_pkt *pkt) __writer_flush(p); } +static void +writer_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle; + + TRACE("[Ring %s] Pkt %d (%u bytes at offset %u) (fast clone)\n", + p->params.name, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + rte_pktmbuf_refcnt_update(m, 1); + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + + p->pkts[p->n_pkts++] = m; + if (p->n_pkts == (int)p->params.burst_size) + __writer_flush(p); +} + +static void +writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length) +{ + struct writer *p = port; + struct rte_mbuf *m = pkt->handle, *m_clone; + + TRACE("[Ring %s] Pkt %d (%u bytes at offset %u) (clone)\n", + p->params.name, + p->n_pkts - 1, + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + + m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length); + if (!m_clone) { + p->stats.n_pkts_clone_err++; + return; + } + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + + p->pkts[p->n_pkts++] = m_clone; + if (p->n_pkts == (int)p->params.burst_size) + __writer_flush(p); +} + static void writer_flush(void *port) { @@ -312,6 +373,8 @@ struct rte_swx_port_out_ops rte_swx_port_ring_writer_ops = { .create = writer_create, .free = writer_free, .pkt_tx = writer_pkt_tx, + .pkt_fast_clone_tx = writer_pkt_fast_clone_tx, + .pkt_clone_tx = writer_pkt_clone_tx, .flush = writer_flush, .stats_read = writer_stats_read, }; diff --git a/lib/port/rte_swx_port_source_sink.c b/lib/port/rte_swx_port_source_sink.c index 93c346cfb1..d3cf42c30b 100644 --- a/lib/port/rte_swx_port_source_sink.c +++ b/lib/port/rte_swx_port_source_sink.c @@ -295,8 +295,8 @@ sink_pkt_tx(void *port, struct rte_swx_pkt *pkt) if (TRACE_LEVEL) rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); m->pkt_len = pkt->length; - m->data_len = (uint16_t)pkt->length; m->data_off = (uint16_t)pkt->offset; p->stats.n_pkts++; @@ -319,6 +319,53 @@ sink_pkt_tx(void *port, struct rte_swx_pkt *pkt) rte_pktmbuf_free(m); } +static void +__sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length __rte_unused) +{ + struct sink *p = port; + struct rte_mbuf *m = pkt->handle; + + TRACE("[Sink port] Pkt TX (%u bytes at offset %u) (clone)\n", + pkt->length, + pkt->offset); + if (TRACE_LEVEL) + rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length); + + m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len); + m->pkt_len = pkt->length; + m->data_off = (uint16_t)pkt->offset; + + p->stats.n_pkts++; + p->stats.n_bytes += pkt->length; + p->stats.n_pkts_clone++; + +#ifdef RTE_PORT_PCAP + if (p->f_dump) { + struct pcap_pkthdr pcap_pkthdr; + uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *); + + pcap_pkthdr.len = m->pkt_len; + pcap_pkthdr.caplen = RTE_MIN(m->data_len, truncation_length); + gettimeofday(&pcap_pkthdr.ts, NULL); + + pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data); + pcap_dump_flush(p->f_dump); + } +#endif +} + +static void +sink_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt) +{ + __sink_pkt_clone_tx(port, pkt, UINT32_MAX); +} + +static void +sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length) +{ + __sink_pkt_clone_tx(port, pkt, truncation_length); +} + static void sink_stats_read(void *port, struct rte_swx_port_out_stats *stats) { @@ -337,6 +384,8 @@ struct rte_swx_port_out_ops rte_swx_port_sink_ops = { .create = sink_create, .free = sink_free, .pkt_tx = sink_pkt_tx, + .pkt_fast_clone_tx = sink_pkt_fast_clone_tx, + .pkt_clone_tx = sink_pkt_clone_tx, .flush = NULL, .stats_read = sink_stats_read, }; From patchwork Tue Apr 5 12:30:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 109148 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 97850A0509; Tue, 5 Apr 2022 14:30:17 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id BAAA642847; Tue, 5 Apr 2022 14:30:15 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id 455FE40DF6 for ; Tue, 5 Apr 2022 14:30:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1649161807; x=1680697807; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=+aDZ8RNYE6Mzqm8SABiim3xH2l/q2/7GJU1fT6hvU0A=; b=VAJaPILGj1V1u9msR7uKG/SgqFps7WzH2+BHUYdcAb5EzFBy9rifjK0U ZNZOHcWE/N7vgZ50moJ1dbfDqqborAVtYNw2mp4f81H1YIvAib6IRhkCp h5PVnG9YUIGrOoO5n+W7g9MGrXSGYFtv87raF2UJCo5CPWKhi1/uE62K4 NoNlu6T4JE00eKvIkuDix6B/ndbO33yFw/+i1RIj3L9Kc8wD5hgJ7KuKE ioLAVY2qonM3yp4YUwRuSQJu9NlrC4idPfIXbERRcSIz0x7QRtA9CNCem w7+cN2p7xHRWFGr4Cg61jyEy1/zVIFnB4dA34Ud2cY+g4J7ztpAqTdF+9 Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10307"; a="259567325" X-IronPort-AV: E=Sophos;i="5.90,236,1643702400"; d="scan'208";a="259567325" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Apr 2022 05:30:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,236,1643702400"; d="scan'208";a="523441147" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga002.jf.intel.com with ESMTP; 05 Apr 2022 05:30:04 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Cc: Kamalakannan R Subject: [PATCH V2 2/3] pipeline: support packet mirroring Date: Tue, 5 Apr 2022 13:30:01 +0100 Message-Id: <20220405123002.40671-2-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220405123002.40671-1-cristian.dumitrescu@intel.com> References: <20220304180623.74893-1-cristian.dumitrescu@intel.com> <20220405123002.40671-1-cristian.dumitrescu@intel.com> 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 The packet mirroring is configured through slots and sessions, with the number of slots and sessions set at init. The new "mirror" instruction assigns one of the existing sessions to a specific slot, which results in scheduling a mirror operation for the current packet to be executed later at the time the packet is either transmitted or dropped. Several copies of the same input packet can be mirrored to different output ports by using multiple slots. Signed-off-by: Cristian Dumitrescu Signed-off-by: Kamalakannan R --- lib/pipeline/rte_swx_ctl.h | 42 +++++ lib/pipeline/rte_swx_pipeline.c | 198 +++++++++++++++++++++++ lib/pipeline/rte_swx_pipeline.h | 30 ++++ lib/pipeline/rte_swx_pipeline_internal.h | 76 +++++++++ lib/pipeline/version.map | 2 + 5 files changed, 348 insertions(+) diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h index ed752ad5eb..204026dc0e 100644 --- a/lib/pipeline/rte_swx_ctl.h +++ b/lib/pipeline/rte_swx_ctl.h @@ -41,6 +41,12 @@ struct rte_swx_ctl_pipeline_info { /** Number of input ports. */ uint32_t n_ports_out; + /** Number of packet mirroring slots. */ + uint32_t n_mirroring_slots; + + /** Number of packet mirroring sessions. */ + uint32_t n_mirroring_sessions; + /** Number of actions. */ uint32_t n_actions; @@ -655,6 +661,42 @@ rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p, const char *learner_name, struct rte_swx_learner_stats *stats); +/* + * Packet mirroring API. + */ + +/** Packet mirroring session parameters. */ +struct rte_swx_pipeline_mirroring_session_params { + /** Output port ID. */ + uint32_t port_id; + + /** Fast clone flag. */ + int fast_clone; + + /** Truncation packet length (in bytes). Zero means no truncation. */ + uint32_t truncation_length; +}; + +/** + * Packet mirroring session set + * + * @param[in] p + * Pipeline handle. + * @param[in] session_id + * Packet mirroring session ID. + * @param[in] params + * Packet mirroring session parameters. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -EEXIST: Pipeline was already built successfully. + */ +__rte_experimental +int +rte_swx_ctl_pipeline_mirroring_session_set(struct rte_swx_pipeline *p, + uint32_t session_id, + struct rte_swx_pipeline_mirroring_session_params *params); + /* * Table Update API. */ diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c index 8c4670e111..062fbcfc89 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -423,6 +423,8 @@ rte_swx_pipeline_port_out_type_register(struct rte_swx_pipeline *p, CHECK(ops->create, EINVAL); CHECK(ops->free, EINVAL); CHECK(ops->pkt_tx, EINVAL); + CHECK(ops->pkt_fast_clone_tx, EINVAL); + CHECK(ops->pkt_clone_tx, EINVAL); CHECK(ops->stats_read, EINVAL); CHECK(!port_out_type_find(p, name), EEXIST); @@ -509,6 +511,8 @@ port_out_build(struct rte_swx_pipeline *p) struct port_out_runtime *out = &p->out[port->id]; out->pkt_tx = port->type->ops.pkt_tx; + out->pkt_fast_clone_tx = port->type->ops.pkt_fast_clone_tx; + out->pkt_clone_tx = port->type->ops.pkt_clone_tx; out->flush = port->type->ops.flush; out->obj = port->obj; } @@ -554,6 +558,81 @@ port_out_free(struct rte_swx_pipeline *p) } } +/* + * Packet mirroring. + */ +int +rte_swx_pipeline_mirroring_config(struct rte_swx_pipeline *p, + struct rte_swx_pipeline_mirroring_params *params) +{ + CHECK(p, EINVAL); + CHECK(params, EINVAL); + CHECK(params->n_slots, EINVAL); + CHECK(params->n_sessions, EINVAL); + CHECK(!p->build_done, EEXIST); + + p->n_mirroring_slots = rte_align32pow2(params->n_slots); + if (p->n_mirroring_slots > 64) + p->n_mirroring_slots = 64; + + p->n_mirroring_sessions = rte_align32pow2(params->n_sessions); + + return 0; +} + +static void +mirroring_build_free(struct rte_swx_pipeline *p) +{ + uint32_t i; + + for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { + struct thread *t = &p->threads[i]; + + /* mirroring_slots. */ + free(t->mirroring_slots); + t->mirroring_slots = NULL; + } + + /* mirroring_sessions. */ + free(p->mirroring_sessions); + p->mirroring_sessions = NULL; +} + +static void +mirroring_free(struct rte_swx_pipeline *p) +{ + mirroring_build_free(p); +} + +static int +mirroring_build(struct rte_swx_pipeline *p) +{ + uint32_t i; + + if (!p->n_mirroring_slots || !p->n_mirroring_sessions) + return 0; + + for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { + struct thread *t = &p->threads[i]; + + /* mirroring_slots. */ + t->mirroring_slots = calloc(p->n_mirroring_slots, sizeof(uint32_t)); + if (!t->mirroring_slots) + goto error; + } + + /* mirroring_sessions. */ + p->mirroring_sessions = calloc(p->n_mirroring_sessions, sizeof(struct mirroring_session)); + if (!p->mirroring_sessions) + goto error; + + return 0; + +error: + mirroring_build_free(p); + return -ENOMEM; +} + /* * Extern object. */ @@ -1653,6 +1732,56 @@ instr_drop_exec(struct rte_swx_pipeline *p) instr_rx_exec(p); } +/* + * mirror. + */ +static int +instr_mirror_translate(struct rte_swx_pipeline *p, + struct action *action, + char **tokens, + int n_tokens, + struct instruction *instr, + struct instruction_data *data __rte_unused) +{ + char *dst = tokens[1], *src = tokens[2]; + struct field *fdst, *fsrc; + uint32_t dst_struct_id = 0, src_struct_id = 0; + + CHECK(n_tokens == 3, EINVAL); + + fdst = struct_field_parse(p, action, dst, &dst_struct_id); + CHECK(fdst, EINVAL); + CHECK(dst[0] != 'h', EINVAL); + CHECK(!fdst->var_size, EINVAL); + + fsrc = struct_field_parse(p, action, src, &src_struct_id); + CHECK(fsrc, EINVAL); + CHECK(src[0] != 'h', EINVAL); + CHECK(!fsrc->var_size, EINVAL); + + instr->type = INSTR_MIRROR; + instr->mirror.dst.struct_id = (uint8_t)dst_struct_id; + instr->mirror.dst.n_bits = fdst->n_bits; + instr->mirror.dst.offset = fdst->offset / 8; + instr->mirror.src.struct_id = (uint8_t)src_struct_id; + instr->mirror.src.n_bits = fsrc->n_bits; + instr->mirror.src.offset = fsrc->offset / 8; + + return 0; +} + +static inline void +instr_mirror_exec(struct rte_swx_pipeline *p) +{ + struct thread *t = &p->threads[p->thread_id]; + struct instruction *ip = t->ip; + + __instr_mirror_exec(p, t, ip); + + /* Thread. */ + thread_ip_inc(p); +} + /* * extract. */ @@ -5653,6 +5782,14 @@ instr_translate(struct rte_swx_pipeline *p, instr, data); + if (!strcmp(tokens[tpos], "mirror")) + return instr_mirror_translate(p, + action, + &tokens[tpos], + n_tokens - tpos, + instr, + data); + if (!strcmp(tokens[tpos], "extract")) return instr_hdr_extract_translate(p, action, @@ -6677,6 +6814,7 @@ static instr_exec_t instruction_table[] = { [INSTR_TX] = instr_tx_exec, [INSTR_TX_I] = instr_tx_i_exec, [INSTR_DROP] = instr_drop_exec, + [INSTR_MIRROR] = instr_mirror_exec, [INSTR_HDR_EXTRACT] = instr_hdr_extract_exec, [INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec, @@ -9026,6 +9164,7 @@ rte_swx_pipeline_free(struct rte_swx_pipeline *p) header_free(p); extern_func_free(p); extern_obj_free(p); + mirroring_free(p); port_out_free(p); port_in_free(p); struct_free(p); @@ -9234,6 +9373,10 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) if (status) goto error; + status = mirroring_build(p); + if (status) + goto error; + status = struct_build(p); if (status) goto error; @@ -9305,6 +9448,7 @@ rte_swx_pipeline_build(struct rte_swx_pipeline *p) header_build_free(p); extern_func_build_free(p); extern_obj_build_free(p); + mirroring_build_free(p); port_out_build_free(p); port_in_build_free(p); struct_build_free(p); @@ -9356,6 +9500,8 @@ rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, pipeline->n_ports_in = p->n_ports_in; pipeline->n_ports_out = p->n_ports_out; + pipeline->n_mirroring_slots = p->n_mirroring_slots; + pipeline->n_mirroring_sessions = p->n_mirroring_sessions; pipeline->n_actions = n_actions; pipeline->n_tables = n_tables; pipeline->n_selectors = p->n_selectors; @@ -10043,6 +10189,27 @@ rte_swx_ctl_meter_stats_read(struct rte_swx_pipeline *p, return 0; } +int +rte_swx_ctl_pipeline_mirroring_session_set(struct rte_swx_pipeline *p, + uint32_t session_id, + struct rte_swx_pipeline_mirroring_session_params *params) +{ + struct mirroring_session *s; + + CHECK(p, EINVAL); + CHECK(p->build_done, EEXIST); + CHECK(session_id < p->n_mirroring_sessions, EINVAL); + CHECK(params, EINVAL); + CHECK(params->port_id < p->n_ports_out, EINVAL); + + s = &p->mirroring_sessions[session_id]; + s->port_id = params->port_id; + s->fast_clone = params->fast_clone; + s->truncation_length = params->truncation_length ? params->truncation_length : UINT32_MAX; + + return 0; +} + /* * Pipeline compilation. */ @@ -10055,6 +10222,7 @@ instr_type_to_name(struct instruction *instr) case INSTR_TX: return "INSTR_TX"; case INSTR_TX_I: return "INSTR_TX_I"; case INSTR_DROP: return "INSTR_DROP"; + case INSTR_MIRROR: return "INSTR_MIRROR"; case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT"; case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2"; @@ -10357,6 +10525,34 @@ instr_io_export(struct instruction *instr, FILE *f) "\t},\n"); } +static void +instr_mirror_export(struct instruction *instr, FILE *f) +{ + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.mirror = {\n" + "\t\t\t.dst = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t}\n," + "\t\t\t.src = {\n" + "\t\t\t\t.struct_id = %u,\n" + "\t\t\t\t.n_bits = %u,\n" + "\t\t\t\t.offset = %u,\n" + "\t\t\t}\n," + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->mirror.dst.struct_id, + instr->mirror.dst.n_bits, + instr->mirror.dst.offset, + instr->mirror.src.struct_id, + instr->mirror.src.n_bits, + instr->mirror.src.offset); +} + static void instr_hdr_validate_export(struct instruction *instr, FILE *f) { @@ -10924,6 +11120,7 @@ static instruction_export_t export_table[] = { [INSTR_TX] = instr_io_export, [INSTR_TX_I] = instr_io_export, [INSTR_DROP] = instr_io_export, + [INSTR_MIRROR] = instr_mirror_export, [INSTR_HDR_EXTRACT] = instr_io_export, [INSTR_HDR_EXTRACT2] = instr_io_export, @@ -11142,6 +11339,7 @@ instr_type_to_func(struct instruction *instr) case INSTR_TX: return "__instr_tx_exec"; case INSTR_TX_I: return "__instr_tx_i_exec"; case INSTR_DROP: return "__instr_drop_exec"; + case INSTR_MIRROR: return "__instr_mirror_exec"; case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec"; case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec"; diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h index 430e458335..1cfd1c542f 100644 --- a/lib/pipeline/rte_swx_pipeline.h +++ b/lib/pipeline/rte_swx_pipeline.h @@ -159,6 +159,36 @@ rte_swx_pipeline_port_out_config(struct rte_swx_pipeline *p, uint32_t port_id, const char *port_type_name, void *args); +/* + * Packet mirroring + */ + +/** Packet mirroring parameters. */ +struct rte_swx_pipeline_mirroring_params { + /** Number of packet mirroring slots. */ + uint32_t n_slots; + + /** Maximum number of packet mirroring sessions. */ + uint32_t n_sessions; +}; + +/** + * Packet mirroring configure + * + * @param[in] p + * Pipeline handle. + * @param[in] params + * Packet mirroring parameters. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument; + * -ENOMEM: Not enough memory; + * -EEXIST: Pipeline was already built successfully. + */ +__rte_experimental +int +rte_swx_pipeline_mirroring_config(struct rte_swx_pipeline *p, + struct rte_swx_pipeline_mirroring_params *params); /* * Extern objects and functions diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h index da3e88bfa8..808a0cbdbb 100644 --- a/lib/pipeline/rte_swx_pipeline_internal.h +++ b/lib/pipeline/rte_swx_pipeline_internal.h @@ -104,10 +104,21 @@ TAILQ_HEAD(port_out_tailq, port_out); struct port_out_runtime { rte_swx_port_out_pkt_tx_t pkt_tx; + rte_swx_port_out_pkt_fast_clone_tx_t pkt_fast_clone_tx; + rte_swx_port_out_pkt_clone_tx_t pkt_clone_tx; rte_swx_port_out_flush_t flush; void *obj; }; +/* + * Packet mirroring. + */ +struct mirroring_session { + uint32_t port_id; + int fast_clone; + uint32_t truncation_length; +}; + /* * Extern object. */ @@ -227,6 +238,13 @@ enum instruction_type { INSTR_TX_I, /* port_out = I */ INSTR_DROP, + /* + * mirror slot_id session_id + * slot_id = MEFT + * session_id = MEFT + */ + INSTR_MIRROR, + /* extract h.header */ INSTR_HDR_EXTRACT, INSTR_HDR_EXTRACT2, @@ -670,6 +688,7 @@ struct instruction { enum instruction_type type; union { struct instr_io io; + struct instr_dst_src mirror; struct instr_hdr_validity valid; struct instr_dst_src mov; struct instr_regarray regarray; @@ -902,6 +921,8 @@ struct thread { /* Packet. */ struct rte_swx_pkt pkt; uint8_t *ptr; + uint32_t *mirroring_slots; + uint64_t mirroring_slots_mask; /* Structures. */ uint8_t **structs; @@ -1399,6 +1420,7 @@ struct rte_swx_pipeline { struct port_in_runtime *in; struct port_out_runtime *out; + struct mirroring_session *mirroring_sessions; struct instruction **action_instructions; action_func_t *action_funcs; struct rte_swx_table_state *table_state; @@ -1416,6 +1438,8 @@ struct rte_swx_pipeline { uint32_t n_structs; uint32_t n_ports_in; uint32_t n_ports_out; + uint32_t n_mirroring_slots; + uint32_t n_mirroring_sessions; uint32_t n_extern_objs; uint32_t n_extern_funcs; uint32_t n_actions; @@ -1511,6 +1535,8 @@ __instr_rx_exec(struct rte_swx_pipeline *p, struct thread *t, const struct instr pkt_received ? "1 pkt" : "0 pkts", p->port_id); + t->mirroring_slots_mask = 0; + /* Headers. */ t->valid_headers = 0; t->n_headers_out = 0; @@ -1596,6 +1622,33 @@ emit_handler(struct thread *t) } } +static inline void +mirroring_handler(struct rte_swx_pipeline *p, struct thread *t, struct rte_swx_pkt *pkt) +{ + uint64_t slots_mask = t->mirroring_slots_mask, slot_mask; + uint32_t slot_id; + + for (slot_id = 0, slot_mask = 1LLU ; slots_mask; slot_id++, slot_mask <<= 1) + if (slot_mask & slots_mask) { + struct port_out_runtime *port; + struct mirroring_session *session; + uint32_t port_id, session_id; + + session_id = t->mirroring_slots[slot_id]; + session = &p->mirroring_sessions[session_id]; + + port_id = session->port_id; + port = &p->out[port_id]; + + if (session->fast_clone) + port->pkt_fast_clone_tx(port->obj, pkt); + else + port->pkt_clone_tx(port->obj, pkt, session->truncation_length); + + slots_mask &= ~slot_mask; + } +} + static inline void __instr_tx_exec(struct rte_swx_pipeline *p, struct thread *t, const struct instruction *ip) { @@ -1611,6 +1664,7 @@ __instr_tx_exec(struct rte_swx_pipeline *p, struct thread *t, const struct instr emit_handler(t); /* Packet. */ + mirroring_handler(p, t, pkt); port->pkt_tx(port->obj, pkt); } @@ -1629,6 +1683,7 @@ __instr_tx_i_exec(struct rte_swx_pipeline *p, struct thread *t, const struct ins emit_handler(t); /* Packet. */ + mirroring_handler(p, t, pkt); port->pkt_tx(port->obj, pkt); } @@ -1648,9 +1703,30 @@ __instr_drop_exec(struct rte_swx_pipeline *p, emit_handler(t); /* Packet. */ + mirroring_handler(p, t, pkt); port->pkt_tx(port->obj, pkt); } +static inline void +__instr_mirror_exec(struct rte_swx_pipeline *p, + struct thread *t, + const struct instruction *ip) +{ + uint64_t slot_id = instr_operand_hbo(t, &ip->mirror.dst); + uint64_t session_id = instr_operand_hbo(t, &ip->mirror.src); + + slot_id &= p->n_mirroring_slots - 1; + session_id &= p->n_mirroring_sessions - 1; + + TRACE("[Thread %2u]: mirror pkt (slot = %u, session = %u)\n", + p->thread_id, + (uint32_t)slot_id, + (uint32_t)session_id); + + t->mirroring_slots[slot_id] = session_id; + t->mirroring_slots_mask |= 1LLU << slot_id; +} + /* * extract. */ diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map index 8bc90e7cd7..44332aad26 100644 --- a/lib/pipeline/version.map +++ b/lib/pipeline/version.map @@ -67,6 +67,7 @@ EXPERIMENTAL { rte_swx_ctl_pipeline_create; rte_swx_ctl_pipeline_free; rte_swx_ctl_pipeline_info_get; + rte_swx_ctl_pipeline_mirroring_session_set; rte_swx_ctl_pipeline_numa_node_get; rte_swx_ctl_pipeline_port_in_stats_read; rte_swx_ctl_pipeline_port_out_stats_read; @@ -90,6 +91,7 @@ EXPERIMENTAL { rte_swx_pipeline_flush; rte_swx_pipeline_free; rte_swx_pipeline_instructions_config; + rte_swx_pipeline_mirroring_config; rte_swx_pipeline_packet_header_register; rte_swx_pipeline_packet_metadata_register; rte_swx_pipeline_port_in_config; From patchwork Tue Apr 5 12:30:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 109149 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 3F536A0509; Tue, 5 Apr 2022 14:30:24 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id AC16F4284F; Tue, 5 Apr 2022 14:30:16 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by mails.dpdk.org (Postfix) with ESMTP id B6B1540F35 for ; Tue, 5 Apr 2022 14:30:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1649161807; x=1680697807; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=xz+ZBX/GM0Y73d+uhk2BmxP+PXPMw8hqRomCjdoaLQI=; b=fSRxLk7YonCcagD1gPWWrQzK5rt+eo/NnFKrwwe/b1yxmJEvdmjNH+uu j0aNxsj0fINw1h52SgYLyECQZTVVXP7mFzT2eXaPDf4jajE+0rpquVKvI fkVLY0EbtZcTYIy978A9zUlL3TFHH3xbFSPE+pTxqy9RgD9on1axnAR4l BbVqBArpau73J1+1uelmRhleB+T8d/Tn5hZzPLjqHlgXcKAD5IaeIhJbD 5YLiNYeMgaflJs2fSXDdYHE9uVX9bWAZf9CPTxpLl9yPn0M0q8zjNFl90 TQpz3mNLuYRKKe+/SQ712Z203Digt/q2JwFtGxmyJqxv36VifI4VwzjvQ Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10307"; a="259567328" X-IronPort-AV: E=Sophos;i="5.90,236,1643702400"; d="scan'208";a="259567328" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Apr 2022 05:30:07 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,236,1643702400"; d="scan'208";a="523441169" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga002.jf.intel.com with ESMTP; 05 Apr 2022 05:30:06 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Cc: Yogesh Jangra , Kamalakannan R Subject: [PATCH V2 3/3] examples/pipeline: support packet mirroring Date: Tue, 5 Apr 2022 13:30:02 +0100 Message-Id: <20220405123002.40671-3-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220405123002.40671-1-cristian.dumitrescu@intel.com> References: <20220304180623.74893-1-cristian.dumitrescu@intel.com> <20220405123002.40671-1-cristian.dumitrescu@intel.com> 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 Add CLI commands for packet mirroring. Signed-off-by: Cristian Dumitrescu Signed-off-by: Yogesh Jangra Signed-off-by: Kamalakannan R --- examples/pipeline/cli.c | 203 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 195 insertions(+), 8 deletions(-) diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c index edae63dae6..9b8feff03f 100644 --- a/examples/pipeline/cli.c +++ b/examples/pipeline/cli.c @@ -2572,15 +2572,23 @@ cmd_pipeline_stats(char **tokens, rte_swx_ctl_pipeline_port_out_stats_read(p->p, i, &stats); if (i != info.n_ports_out - 1) - snprintf(out, out_size, "\tPort %u:" - " packets %" PRIu64 - " bytes %" PRIu64 "\n", - i, stats.n_pkts, stats.n_bytes); + snprintf(out, out_size, "\tPort %u:", i); else - snprintf(out, out_size, "\tDROP:" - " packets %" PRIu64 - " bytes %" PRIu64 "\n", - stats.n_pkts, stats.n_bytes); + snprintf(out, out_size, "\tDROP:"); + + out_size -= strlen(out); + out += strlen(out); + + snprintf(out, + out_size, + " packets %" PRIu64 + " bytes %" PRIu64 + " clone %" PRIu64 + " clonerr %" PRIu64 "\n", + stats.n_pkts, + stats.n_bytes, + stats.n_pkts_clone, + stats.n_pkts_clone_err); out_size -= strlen(out); out += strlen(out); @@ -2697,6 +2705,156 @@ cmd_pipeline_stats(char **tokens, } } +static const char cmd_pipeline_mirror_help[] = +"pipeline mirror slots sessions \n"; + +static void +cmd_pipeline_mirror(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct rte_swx_pipeline_mirroring_params params; + struct pipeline *p; + int status; + + if (n_tokens != 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + if (strcmp(tokens[0], "pipeline")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "mirror")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror"); + return; + } + + if (strcmp(tokens[3], "slots")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "slots"); + return; + } + + if (parser_read_uint32(¶ms.n_slots, tokens[4])) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_slots"); + return; + } + + if (strcmp(tokens[5], "sessions")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "sessions"); + return; + } + + if (parser_read_uint32(¶ms.n_sessions, tokens[6])) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_sessions"); + return; + } + + status = rte_swx_pipeline_mirroring_config(p->p, ¶ms); + if (status) { + snprintf(out, out_size, "Command failed!\n"); + return; + } +} + +static const char cmd_pipeline_mirror_session_help[] = +"pipeline mirror session port clone fast | slow " +"truncate \n"; + +static void +cmd_pipeline_mirror_session(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + void *obj) +{ + struct rte_swx_pipeline_mirroring_session_params params; + struct pipeline *p; + uint32_t session_id; + int status; + + if (n_tokens != 11) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + if (strcmp(tokens[0], "pipeline")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipeline"); + return; + } + + p = pipeline_find(obj, tokens[1]); + if (!p || !p->ctl) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipeline_name"); + return; + } + + if (strcmp(tokens[2], "mirror")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mirror"); + return; + } + + if (strcmp(tokens[3], "session")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "session"); + return; + } + + if (parser_read_uint32(&session_id, tokens[4])) { + snprintf(out, out_size, MSG_ARG_INVALID, "session_id"); + return; + } + + if (strcmp(tokens[5], "port")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (parser_read_uint32(¶ms.port_id, tokens[6])) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[7], "clone")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "clone"); + return; + } + + if (!strcmp(tokens[8], "fast")) + params.fast_clone = 1; + else if (!strcmp(tokens[8], "slow")) + params.fast_clone = 1; + else { + snprintf(out, out_size, MSG_ARG_INVALID, "clone"); + return; + } + + if (strcmp(tokens[9], "truncate")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "truncate"); + return; + } + + if (parser_read_uint32(¶ms.truncation_length, tokens[10])) { + snprintf(out, out_size, MSG_ARG_INVALID, "truncation_length"); + return; + } + + status = rte_swx_ctl_pipeline_mirroring_session_set(p->p, session_id, ¶ms); + if (status) { + snprintf(out, out_size, "Command failed!\n"); + return; + } +} + static const char cmd_thread_pipeline_enable_help[] = "thread pipeline enable\n"; @@ -2837,6 +2995,8 @@ cmd_help(char **tokens, "\tpipeline meter set\n" "\tpipeline meter stats\n" "\tpipeline stats\n" + "\tpipeline mirror\n" + "\tpipeline mirror session\n" "\tthread pipeline enable\n" "\tthread pipeline disable\n\n"); return; @@ -3056,6 +3216,19 @@ cmd_help(char **tokens, return; } + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 2) && !strcmp(tokens[1], "mirror")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_help); + return; + } + + if (!strcmp(tokens[0], "pipeline") && + (n_tokens == 3) && !strcmp(tokens[1], "mirror") + && !strcmp(tokens[2], "session")) { + snprintf(out, out_size, "\n%s\n", cmd_pipeline_mirror_session_help); + return; + } + if ((n_tokens == 3) && (strcmp(tokens[0], "thread") == 0) && (strcmp(tokens[1], "pipeline") == 0)) { @@ -3310,6 +3483,20 @@ cli_process(char *in, char *out, size_t out_size, void *obj) obj); return; } + + if ((n_tokens >= 4) && + (strcmp(tokens[2], "mirror") == 0) && + (strcmp(tokens[3], "slots") == 0)) { + cmd_pipeline_mirror(tokens, n_tokens, out, out_size, obj); + return; + } + + if ((n_tokens >= 4) && + (strcmp(tokens[2], "mirror") == 0) && + (strcmp(tokens[3], "session") == 0)) { + cmd_pipeline_mirror_session(tokens, n_tokens, out, out_size, obj); + return; + } } if (strcmp(tokens[0], "thread") == 0) {