DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib
@ 2020-09-09  0:22 Patrick Fu
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API Patrick Fu
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Patrick Fu @ 2020-09-09  0:22 UTC (permalink / raw)
  To: dev
  Cc: thomas, ferruh.yigit, maxime.coquelin, bruce.richardson, mm6021,
	zhihong.wang, liang-min.wang, konstantin.ananyev,
	timothy.miskell, cunming.liang, patrick.fu

Network Test Access Point (TAP) is the network monitoring service
commonly adotpted in SDN-based network infrastructures. When VMs are
inter-connected over virtual switches, TAP requires vSwitch to mirror
out network traffics from specific workload VM ports to the TAP
device/VM ports. Classical mirroring impmentations in vSwitch make an
extra copy of the source packets, which results in significant degradation
in the throughput levels vSwitch could normally archieve. Therefore, we
propose a new set of APIs to support high-throughput packet mirroring
through hardware offloading.

The proposal is consisted of three major parts:
 - Mirror registration APIs
 - Mirror offload/customization callbacks
 - Shared mirror data path

In this patch set, mirroring happens between a pair of ethdev ports (one for
the source port and the other for the mirror port), which is configurable
on a per-port per-direction basis. i.e. applications invoke the mirroring
API to register source ports and traffic directions (tx or rx). The
registration API will then attach the mirror data path to the source port
as a standard ethdev tx or rx callback. If any custom mirror offload
functions are specified by applications, the offload function will be
executed within the mirror data path.

The mirror data path intercepts the packets flowing over the registered
source ports and, rather than doing extra packets copy operations, simply
transmits packets to the destination (mirror) port with an incremented
mbuf reference count. In this way, an identical copy of the packet data is
transmitted to both the mirror port and the original traffic destination.

In addition, with the proposed APIs we can implement even more complicated
mirrorings scenarios. Two examples include flow based mirroring and MAC
address matching, both of which have common usage within the industry.

Our prior studies demonstrate that this methedology is capble of doubling
the mirroring performance as compared to the default OVS port mirroring
performance (refer to the paper in IEEE xplore for further details:
https://ieeexplore.ieee.org/document/9110293)
An OVS implementation was also suggested to the OVS community for review
and comments (refer to the following OVS RFC patch:
https://patchwork.ozlabs.org/project/openvswitch/patch/
1595596858-78846-2-git-send-email-emma.finn@intel.com/)

We are considering implementing the mirroring APIs as a standalone library
in DPDK, but it's also reasonble to place it inside ethdev layer or within
the vhost-pmd considering the potential usage scenarios.

Patrick Fu (3):
  lib/mirror: introduce traffic mirror API
  lib/mirror: add port based mirroring
  lib/mirror: add flow based mirroring

 config/common_base                       |   5 +
 lib/Makefile                             |   2 +
 lib/librte_mirror/Makefile               |  20 +
 lib/librte_mirror/meson.build            |   6 +
 lib/librte_mirror/rte_mirror.c           | 461 +++++++++++++++++++++++
 lib/librte_mirror/rte_mirror.h           | 111 ++++++
 lib/librte_mirror/rte_mirror_version.map |   7 +
 lib/meson.build                          |   2 +-
 8 files changed, 613 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_mirror/Makefile
 create mode 100644 lib/librte_mirror/meson.build
 create mode 100644 lib/librte_mirror/rte_mirror.c
 create mode 100644 lib/librte_mirror/rte_mirror.h
 create mode 100644 lib/librte_mirror/rte_mirror_version.map

-- 
2.18.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
  2020-09-09  0:22 [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Patrick Fu
@ 2020-09-09  0:22 ` Patrick Fu
  2020-09-09  1:09   ` Wang, Haiyue
  2020-09-21 15:26   ` MEHAN, MUNISH
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 2/3] lib/mirror: add port based mirroring Patrick Fu
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 8+ messages in thread
From: Patrick Fu @ 2020-09-09  0:22 UTC (permalink / raw)
  To: dev
  Cc: thomas, ferruh.yigit, maxime.coquelin, bruce.richardson, mm6021,
	zhihong.wang, liang-min.wang, konstantin.ananyev,
	timothy.miskell, cunming.liang, patrick.fu

Network Test Access Point (TAP) is the network monitoring service
commonly adotpted in SDN-based network infrastructures. When VMs are
inter-connected over virtual switches, TAP requires vSwitch to mirror
out network traffics from specific workload VM ports to the TAP
device/VM ports.

This patch introduce 2 a new APIs to support high-throughput packet
mirroring:
 - rte_mirror_register()
 - rte_mirror_unregister()
Applications use the new API to setup the source traffic port and
the mirror traffic port. Packets flowing over the registered
source ports will be transmited to the mirror port when registration
succeeds.

Signed-off-by: Liang-min Wang <liang-min.wang@intel.com>
Signed-off-by: Patrick Fu <patrick.fu@intel.com>
Signed-off-by: Timothy Miskell <timothy.miskell@intel.com>
---
 config/common_base                       |   5 +
 lib/Makefile                             |   2 +
 lib/librte_mirror/Makefile               |  20 ++
 lib/librte_mirror/meson.build            |   6 +
 lib/librte_mirror/rte_mirror.c           | 297 +++++++++++++++++++++++
 lib/librte_mirror/rte_mirror.h           | 111 +++++++++
 lib/librte_mirror/rte_mirror_version.map |   7 +
 lib/meson.build                          |   2 +-
 8 files changed, 449 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_mirror/Makefile
 create mode 100644 lib/librte_mirror/meson.build
 create mode 100644 lib/librte_mirror/rte_mirror.c
 create mode 100644 lib/librte_mirror/rte_mirror.h
 create mode 100644 lib/librte_mirror/rte_mirror_version.map

diff --git a/config/common_base b/config/common_base
index fbf0ee70c..60217cc93 100644
--- a/config/common_base
+++ b/config/common_base
@@ -1110,6 +1110,11 @@ CONFIG_RTE_LIBRTE_GRAPH_STATS=y
 #
 CONFIG_RTE_LIBRTE_NODE=y
 
+#
+# Compile librte_mirror
+#
+CONFIG_RTE_LIBRTE_MIRROR=y
+
 #
 # Compile the test application
 #
diff --git a/lib/Makefile b/lib/Makefile
index 8f5b68a2d..24175dd98 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -112,6 +112,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
 DEPDIRS-librte_reorder := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
 DEPDIRS-librte_pdump := librte_eal librte_mempool librte_mbuf librte_ethdev
+DIRS-$(CONFIG_RTE_LIBRTE_MIRROR) += librte_mirror
+DEPDIRS-librte_mirror := librte_eal librte_mempool librte_mbuf librte_ethdev
 DIRS-$(CONFIG_RTE_LIBRTE_GSO) += librte_gso
 DEPDIRS-librte_gso := librte_eal librte_mbuf librte_ethdev librte_net
 DEPDIRS-librte_gso += librte_mempool
diff --git a/lib/librte_mirror/Makefile b/lib/librte_mirror/Makefile
new file mode 100644
index 000000000..3ca1db734
--- /dev/null
+++ b/lib/librte_mirror/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2020- Intel Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_mirror.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ethdev
+
+EXPORT_MAP := rte_mirror_version.map
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_MIRROR) := rte_mirror.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_MIRROR)-include := rte_mirror.h
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_mirror/meson.build b/lib/librte_mirror/meson.build
new file mode 100644
index 000000000..2d0ba0ed2
--- /dev/null
+++ b/lib/librte_mirror/meson.build
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2020 Intel Corporation
+
+sources = files('rte_mirror.c')
+headers = files('rte_mirror.h')
+deps += ['ethdev']
diff --git a/lib/librte_mirror/rte_mirror.c b/lib/librte_mirror/rte_mirror.c
new file mode 100644
index 000000000..f2a85976a
--- /dev/null
+++ b/lib/librte_mirror/rte_mirror.c
@@ -0,0 +1,297 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020- Intel Corporation
+ */
+
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_errno.h>
+
+#include "rte_mirror.h"
+
+/* Macro for printing using RTE_LOG */
+extern int mirror_logtype;
+#define MIRROR_LOG(level, fmt, args...)				\
+	rte_log(RTE_LOG_ ## level, mirror_logtype, "%s(): " fmt,	\
+		__func__, ## args)
+
+#define MAC_ADDR_MAP           0x0000FFFFFFFFFFFFULL
+#define VLAN_INSERT_FLAG       (PKT_TX_VLAN_PKT)
+#define is_mac_addr_match(a, b) (((a^b)&MAC_ADDR_MAP) == 0)
+#define INIT_MIRROR_DB_SIZE    8
+#define INVALID_PORT_ID        0xFFFF
+#define SRC_MAC_OFFSET         6
+#define DST_MAC_OFFSET         0
+
+static int mirror_port_db_size;
+static int mirror_port_used;
+static struct rte_mirror_offload_port *mirror_port_db;
+
+static int
+rte_mirror_param_copy(struct rte_mirror_param *dst,
+	struct rte_mirror_param *src)
+{
+	void *extra_data;
+
+	memcpy(dst, src, sizeof(struct rte_mirror_param));
+
+	if (src->extra_data_size) {
+		extra_data = malloc(src->extra_data_size);
+		if (!extra_data) {
+			MIRROR_LOG(ERR, "Out of memory !!!\n");
+			return -1;
+		}
+		memcpy(extra_data, src->extra_data, src->extra_data_size);
+
+		dst->extra_data = extra_data;
+	} else
+		dst->extra_data = NULL;
+	return 0;
+}
+
+static struct rte_mirror_offload_port*
+mirror_data_find(uint16_t port_id)
+{
+	int i;
+
+	if (mirror_port_db == NULL)
+		return NULL;
+	for (i = 0; i < mirror_port_db_size; i++) {
+		if (port_id == mirror_port_db[i].port_id)
+			return &mirror_port_db[i];
+	}
+	return NULL;
+}
+
+static void
+mirror_db_init(struct rte_mirror_offload_port *db, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		memset(&db[i], 0, sizeof(struct rte_mirror_offload_port));
+		db[i].port_id = INVALID_PORT_ID;
+	}
+}
+
+/* Double the db size when it runs out of space */
+static int
+mirror_db_resize(void)
+{
+	int new_size = 2*mirror_port_db_size;
+	struct rte_mirror_offload_port *new_db = malloc(
+		sizeof(struct rte_mirror_offload_port)*new_size);
+
+	if (new_db == NULL) {
+		MIRROR_LOG(ERR, "Out of memory!!!\n");
+		return -1;
+	}
+
+	memcpy(new_db, mirror_port_db, sizeof(struct rte_mirror_offload_port)
+		*mirror_port_db_size);
+	mirror_db_init(&new_db[mirror_port_db_size], mirror_port_db_size);
+	mirror_port_db_size = new_size;
+	mirror_port_db = new_db;
+
+	return 0;
+}
+
+/* release db when used count drop to 0 */
+static void
+mirror_data_remove(uint16_t port_id, int tx)
+{
+	struct rte_mirror_offload_port *target = mirror_data_find(port_id);
+
+	if (!target)
+		MIRROR_LOG(ERR, "Attempt to remove unsaved port, "
+			"%d, %s callback\n", port_id, tx?"tx" : "rx");
+
+	if (tx)
+		memset(&target->tx, 0, sizeof(struct rte_mirror_param));
+	else
+		memset(&target->rx, 0, sizeof(struct rte_mirror_param));
+
+	if ((target->rx.mirror_cb == NULL) &&
+		(target->tx.mirror_cb == NULL)) {
+		target->port_id = INVALID_PORT_ID;
+		mirror_port_used--;
+		if (mirror_port_used == 0) {
+			free(mirror_port_db);
+			mirror_port_db = NULL;
+			mirror_port_db_size = 0;
+		}
+	}
+}
+
+static struct rte_mirror_offload_port*
+mirror_data_add(uint16_t port_id, int tx,
+		struct rte_mirror_param *new_param)
+{
+	struct rte_mirror_offload_port *target = NULL;
+	struct rte_mirror_param *param;
+	int i;
+
+	if (!mirror_port_db) {
+		mirror_port_db_size = INIT_MIRROR_DB_SIZE;
+		mirror_port_db = malloc(sizeof(struct rte_mirror_offload_port)*
+			mirror_port_db_size);
+		if (!mirror_port_db) {
+			MIRROR_LOG(ERR, "Out of memory!!!\n");
+			return NULL;
+		}
+		mirror_db_init(mirror_port_db, mirror_port_db_size);
+	}
+	target = mirror_data_find(port_id);
+	if (target) {
+		if (tx) {
+			if (target->tx.mirror_cb) {
+				MIRROR_LOG(ERR, "Attempt to add ingress mirror "
+					"offloading on port, %d, "
+					"while one is outstanding\n", port_id);
+				return target;
+			}
+
+			if (rte_mirror_param_copy(&target->tx, new_param))
+				return NULL;
+
+		} else {
+			if (target->rx.mirror_cb) {
+				MIRROR_LOG(ERR, "Attempt to add egress mirror "
+					"offloading on port, %d, "
+					"while one is outstanding\n", port_id);
+				return target;
+			}
+
+			if (rte_mirror_param_copy(&target->rx, new_param))
+				return NULL;
+		}
+	} else {
+		/* find an unused spot on db */
+		for (i = 0; i < mirror_port_db_size; i++) {
+			if (mirror_port_db[i].port_id == INVALID_PORT_ID)
+				break;
+		}
+		if (i == mirror_port_db_size) {
+			if (mirror_db_resize())
+				return NULL;
+		}
+
+		param = tx ? &mirror_port_db[i].tx : &mirror_port_db[i].rx;
+		if (rte_mirror_param_copy(param, new_param))
+			return NULL;
+
+		target = &mirror_port_db[i];
+		target->port_id = port_id;
+		mirror_port_used++;
+	}
+	return target;
+}
+
+static inline void
+mirror_pkt_update(struct rte_mbuf *pkt, uint16_t dst_vlan_id)
+{
+	pkt->ol_flags |= VLAN_INSERT_FLAG;
+	pkt->vlan_tci = dst_vlan_id;
+	rte_mbuf_refcnt_update(pkt, 1);
+}
+
+int
+rte_mirror_offload_register(uint16_t src_port,
+		struct rte_mirror_param *param, int tx_cb)
+{
+	int i;
+	struct rte_mirror_offload_port *port_info;
+	struct rte_mirror_param *data;
+	rte_rx_callback_fn rx_fn = NULL;
+	rte_tx_callback_fn tx_fn = NULL;
+
+
+	port_info = mirror_data_add(src_port, tx_cb, param);
+	if (!port_info)
+		return -EINVAL;
+
+	data = tx_cb ? &port_info->tx : &port_info->rx;
+	data->pkt_buf = NULL;
+	data->mirror_cb = malloc(sizeof(struct rte_eth_rxtx_callbac *) *
+			data->n_src_queue);
+	if (!data->mirror_cb) {
+		MIRROR_LOG(ERR, "Out of memory !!!\n");
+		return -EINVAL;
+	}
+
+	switch (data->mirror_type) {
+	default:
+		MIRROR_LOG(ERR, "Un-supported mirror offloading type!!!\n");
+		return -ENOTSUP;
+	}
+
+	if (data->mirror_type != rte_mirror_type_port) {
+		data->pkt_buf = malloc(sizeof(struct rte_mbuf *) *
+				data->max_burst_size * data->n_src_queue);
+		if (!data->pkt_buf) {
+			RTE_ETHDEV_LOG(ERR, "Out of memory !!!");
+			return -EINVAL;
+		}
+	}
+
+	if (!tx_cb) {
+		for (i = 0; i < data->n_src_queue; i++) {
+			data->mirror_cb[i] = rte_eth_add_rx_callback(src_port,
+				i, rx_fn, data);
+		}
+	} else {
+		for (i = 0; i < data->n_src_queue; i++) {
+			data->mirror_cb[i] = rte_eth_add_tx_callback(src_port,
+				i, tx_fn, data);
+		}
+	}
+
+	return 0;
+}
+
+int
+rte_mirror_offload_unregister(uint16_t src_port, int tx_cb)
+{
+	/* release both cb and pkt_buf */
+	int i;
+	struct rte_mirror_offload_port *port_info;
+	struct rte_mirror_param *data;
+
+	port_info = mirror_data_find(src_port);
+	if (port_info == NULL) {
+		MIRROR_LOG(ERR, "Source port %d is not on outstanding "
+			"port mirror db\n", src_port);
+		return -1;
+	}
+	data = tx_cb ? &port_info->tx : &port_info->rx;
+
+	for (i = 0; i < data->n_src_queue; i++) {
+		if (data->mirror_cb[i]) {
+			if (tx_cb)
+				rte_eth_remove_tx_callback(src_port,
+						i, data->mirror_cb[i]);
+			else
+				rte_eth_remove_rx_callback(src_port,
+						i, data->mirror_cb[i]);
+		}
+		data->mirror_cb[i] = 0;
+	}
+	free(data->mirror_cb);
+
+	if (data->pkt_buf) {
+		free(data->pkt_buf);
+		data->pkt_buf = NULL;
+	}
+
+	if (data->extra_data) {
+		free(data->extra_data);
+		data->extra_data = NULL;
+		data->extra_data_size = 0;
+	}
+
+	mirror_data_remove(src_port, tx_cb);
+	return 0;
+}
+
+RTE_LOG_REGISTER(mirror_logtype, lib.mirror, NOTICE);
diff --git a/lib/librte_mirror/rte_mirror.h b/lib/librte_mirror/rte_mirror.h
new file mode 100644
index 000000000..71f3e1ea1
--- /dev/null
+++ b/lib/librte_mirror/rte_mirror.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020- Intel Corporation
+ */
+
+#ifndef _RTE_MIRROR_H_
+#define _RTE_MIRROR_H_
+
+/**
+ * @file
+ * RTE mirror
+ *
+ * packet mirror offloading library to provide packet mirroring support on dpdk.
+ */
+
+#include <stdint.h>
+#include <rte_ethdev_core.h>
+#include <rte_mbuf_core.h>
+#include <rte_spinlock.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Function type used for mirrored packet header scan.
+ *
+ * The callback function is called on each mirrored packet
+ * to determinate if mirror condition is match.
+ *
+ * @param pkt
+ *   Pointer to one packet data.
+ * @param user_param
+ *   The arbitrary user parameter passed in by the application when the callback
+ *   was originally configured.
+ * @return
+ *   One if the condition matches, else 0.
+ */
+typedef int (*rte_mirror_scan_fn)(struct rte_mbuf *pkt, void *user_param);
+
+typedef enum {
+	rte_mirror_type_port = 0,	/* port mirror */
+	rte_mirror_type_flow_mac,	/* mac based flow mirror */
+	rte_mirror_type_flow_custom,	/* custom flow mirror */
+	rte_mirror_type_invalid = 0xFF,	/* invalid mirror_type */
+} rte_mirror_type;
+
+struct rte_mirror_param {
+	uint16_t dst_port_id;
+	uint16_t dst_vlan_id;
+	rte_spinlock_t *locks;
+	int n_src_queue;
+	int n_dst_queue;
+	struct rte_mbuf **pkt_buf;
+	const struct rte_eth_rxtx_callback **mirror_cb;
+	unsigned int max_burst_size;
+	rte_mirror_scan_fn custom_scan;
+	rte_mirror_type mirror_type;
+	unsigned int extra_data_size;
+	void *extra_data; /* extra mirror parameter */
+};
+
+struct rte_mirror_offload_port {
+	uint16_t port_id;
+	struct rte_mirror_param rx;
+	struct rte_mirror_param tx;
+};
+
+/**
+ * Add a port mirroring via port offloading
+ *
+ * This function adds traffic (ingress or egress) mirroring from
+ * the specified port
+ *
+ * @param src_port
+ *   The source port where port traffic is to be captured and sent to
+ *   the offload port.
+ * @param param
+ *   The port mirror offloading parameters
+ * @param tx_cb
+ *   1: register tx callback; 0: register rx callback
+ * @return
+ *   0 = success
+ *   N > 0 any error encouter
+ */
+__rte_experimental
+int rte_mirror_offload_register(uint16_t src_port,
+	struct rte_mirror_param *param, int tx_cb);
+
+/**
+ * Remove a port mirroring via port offloading
+ *
+ * This function removes traffic (ingress or egress) mirroring from
+ * the specified port
+ *
+ * @param src_port
+ *   The port-id of source port where port traffic is to be captured
+ *   and sent to the offload port.
+ * @param tx_cb
+ *   1: tx callback; 0: rx callback
+ * @return
+ *   0 = success
+ *   N > 0 any error encouter
+ */
+__rte_experimental
+int rte_mirror_offload_unregister(uint16_t src_port, int tx_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDUMP_H_ */
diff --git a/lib/librte_mirror/rte_mirror_version.map b/lib/librte_mirror/rte_mirror_version.map
new file mode 100644
index 000000000..e0a4d69d1
--- /dev/null
+++ b/lib/librte_mirror/rte_mirror_version.map
@@ -0,0 +1,7 @@
+EXPERIMENTAL {
+	global:
+
+	rte_mirror_offload_register;
+	rte_mirror_offload_unregister;
+};
+
diff --git a/lib/meson.build b/lib/meson.build
index 3852c0156..6674749dd 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -24,7 +24,7 @@ libraries = [
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
-	'power', 'pdump', 'rawdev', 'regexdev',
+	'power', 'pdump', 'rawdev', 'regexdev', 'mirror',
 	'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',
 	# ipsec lib depends on net, crypto and security
 	'ipsec',
-- 
2.18.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH v1 2/3] lib/mirror: add port based mirroring
  2020-09-09  0:22 [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Patrick Fu
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API Patrick Fu
@ 2020-09-09  0:22 ` Patrick Fu
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 3/3] lib/mirror: add flow " Patrick Fu
  2020-09-22  7:40 ` [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Thomas Monjalon
  3 siblings, 0 replies; 8+ messages in thread
From: Patrick Fu @ 2020-09-09  0:22 UTC (permalink / raw)
  To: dev
  Cc: thomas, ferruh.yigit, maxime.coquelin, bruce.richardson, mm6021,
	zhihong.wang, liang-min.wang, konstantin.ananyev,
	timothy.miskell, cunming.liang, patrick.fu

This patch add port based mirroring support for the mirror lib.
The port based mirroring is unconditional traffic mirroring
between 2 ethdev ports.

Signed-off-by: Liang-min Wang <liang-min.wang@intel.com>
Signed-off-by: Patrick Fu <patrick.fu@intel.com>
Signed-off-by: Timothy Miskell <timothy.miskell@intel.com>
---
 lib/librte_mirror/rte_mirror.c | 57 ++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/lib/librte_mirror/rte_mirror.c b/lib/librte_mirror/rte_mirror.c
index f2a85976a..d2c0d8eab 100644
--- a/lib/librte_mirror/rte_mirror.c
+++ b/lib/librte_mirror/rte_mirror.c
@@ -196,6 +196,57 @@ mirror_pkt_update(struct rte_mbuf *pkt, uint16_t dst_vlan_id)
 	rte_mbuf_refcnt_update(pkt, 1);
 }
 
+static inline uint16_t
+mirror_port_cb(uint16_t qidx, struct rte_mbuf **pkts,
+	uint16_t nb_pkts, void *user_params)
+{
+	struct rte_mirror_param *data = user_params;
+	uint16_t i, dst_qidx;
+	uint16_t pkt_trans;
+	uint16_t dst_port_id = data->dst_port_id;
+	uint16_t dst_vlan_id = data->dst_vlan_id;
+
+	if (nb_pkts == 0)
+		return 0;
+
+	for (i = 0; i < nb_pkts; i++)
+		mirror_pkt_update(pkts[i], dst_vlan_id);
+
+	dst_qidx = data->n_dst_queue > qidx ? qidx : data->n_dst_queue - 1;
+
+	rte_spinlock_lock(&data->locks[dst_qidx]);
+	pkt_trans = rte_eth_tx_burst(dst_port_id, dst_qidx, pkts, nb_pkts);
+	rte_spinlock_unlock(&data->locks[dst_qidx]);
+	if (pkt_trans != nb_pkts)
+		RTE_ETHDEV_LOG(ERR, "%d packets for tapping but "
+			"only %d packet get through\n", nb_pkts, pkt_trans);
+
+	for (i = 0; i < nb_pkts; i++)
+		pkts[i]->ol_flags &= ~VLAN_INSERT_FLAG;
+
+	while (unlikely(pkt_trans < nb_pkts)) {
+		rte_pktmbuf_free(pkts[pkt_trans]);
+		pkt_trans++;
+	}
+
+	return nb_pkts;
+}
+
+static uint16_t
+mirror_rx_port_cb(uint16_t port_id __rte_unused, uint16_t qidx,
+	struct rte_mbuf **pkts, uint16_t nb_pkts,
+	uint16_t max_pkts __rte_unused, void *user_params)
+{
+	return mirror_port_cb(qidx, pkts, nb_pkts, user_params);
+}
+
+static uint16_t
+mirror_tx_port_cb(uint16_t port_id __rte_unused, uint16_t qidx,
+		struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+	return mirror_port_cb(qidx, pkts, nb_pkts, user_params);
+}
+
 int
 rte_mirror_offload_register(uint16_t src_port,
 		struct rte_mirror_param *param, int tx_cb)
@@ -221,6 +272,12 @@ rte_mirror_offload_register(uint16_t src_port,
 	}
 
 	switch (data->mirror_type) {
+	case rte_mirror_type_port:
+		if (tx_cb)
+			tx_fn = mirror_tx_port_cb;
+		else
+			rx_fn = mirror_rx_port_cb;
+		break;
 	default:
 		MIRROR_LOG(ERR, "Un-supported mirror offloading type!!!\n");
 		return -ENOTSUP;
-- 
2.18.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dpdk-dev] [PATCH v1 3/3] lib/mirror: add flow based mirroring
  2020-09-09  0:22 [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Patrick Fu
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API Patrick Fu
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 2/3] lib/mirror: add port based mirroring Patrick Fu
@ 2020-09-09  0:22 ` Patrick Fu
  2020-09-22  7:40 ` [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Thomas Monjalon
  3 siblings, 0 replies; 8+ messages in thread
From: Patrick Fu @ 2020-09-09  0:22 UTC (permalink / raw)
  To: dev
  Cc: thomas, ferruh.yigit, maxime.coquelin, bruce.richardson, mm6021,
	zhihong.wang, liang-min.wang, konstantin.ananyev,
	timothy.miskell, cunming.liang, patrick.fu

This patch add flow based mirroring support to the mirror lib.
The flow based mirroring is traffic mirroring with flow rules.
Applications may either use a customized callback to apply their
own flow rules, or use MAC matching rules implemented by mirror
lib.

Signed-off-by: Liang-min Wang <liang-min.wang@intel.com>
Signed-off-by: Patrick Fu <patrick.fu@intel.com>
Signed-off-by: Timothy Miskell <timothy.miskell@intel.com>
---
 lib/librte_mirror/rte_mirror.c | 107 +++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/lib/librte_mirror/rte_mirror.c b/lib/librte_mirror/rte_mirror.c
index d2c0d8eab..523ab37ff 100644
--- a/lib/librte_mirror/rte_mirror.c
+++ b/lib/librte_mirror/rte_mirror.c
@@ -196,6 +196,101 @@ mirror_pkt_update(struct rte_mbuf *pkt, uint16_t dst_vlan_id)
 	rte_mbuf_refcnt_update(pkt, 1);
 }
 
+static inline uint16_t
+mirror_flow_cb(uint16_t qidx, struct rte_mbuf **pkts, uint16_t nb_pkts,
+		void *user_params, bool is_custom, uint8_t mac_offset)
+{
+	struct rte_mirror_param *data = user_params;
+	uint16_t i, dst_qidx, match_count = 0;
+	uint16_t pkt_trans;
+	uint16_t dst_port_id = data->dst_port_id;
+	uint16_t dst_vlan_id = data->dst_vlan_id;
+	uint64_t target_addr = *((uint64_t *)data->extra_data);
+	struct rte_mbuf **pkt_buf = &data->pkt_buf[qidx*data->max_burst_size];
+	uint64_t *mac_addr = 0;
+
+	if (nb_pkts == 0)
+		return 0;
+
+	if (nb_pkts > data->max_burst_size) {
+		MIRROR_LOG(ERR, "Per-flow batch size, %d, exceeds "
+			"maximum limit, %d.\n", nb_pkts, data->max_burst_size);
+		return -EINVAL;
+	}
+
+	if (unlikely(is_custom)) {
+		for (i = 0; i < nb_pkts; i++) {
+			if (data->custom_scan(pkts[i], user_params)) {
+				pkt_buf[match_count] = pkts[i];
+				mirror_pkt_update(pkt_buf[match_count],
+						dst_vlan_id);
+				match_count++;
+			}
+		}
+	} else {
+		for (i = 0; i < nb_pkts; i++) {
+			mac_addr =
+				rte_pktmbuf_mtod_offset(pkts[i],
+						uint64_t *, mac_offset);
+			if (is_mac_addr_match(target_addr, (*mac_addr))) {
+				pkt_buf[match_count] = pkts[i];
+				mirror_pkt_update(pkt_buf[match_count],
+						dst_vlan_id);
+				match_count++;
+			}
+		}
+	}
+
+	dst_qidx = (data->n_dst_queue > qidx) ? qidx : (data->n_dst_queue - 1);
+
+	rte_spinlock_lock(&data->locks[dst_qidx]);
+	pkt_trans = rte_eth_tx_burst(dst_port_id, dst_qidx,
+			pkt_buf, match_count);
+	rte_spinlock_unlock(&data->locks[dst_qidx]);
+
+	for (i = 0; i < match_count; i++)
+		pkt_buf[i]->ol_flags &= ~VLAN_INSERT_FLAG;
+
+	while (unlikely(pkt_trans < match_count)) {
+		rte_pktmbuf_free(pkt_buf[pkt_trans]);
+		pkt_trans++;
+	}
+
+	return nb_pkts;
+}
+
+static uint16_t
+mirror_rx_flow_custom_cb(uint16_t port_id __rte_unused, uint16_t qidx,
+	struct rte_mbuf **pkts, uint16_t nb_pkts,
+	uint16_t maxi_pkts __rte_unused, void *user_params)
+{
+	return mirror_flow_cb(qidx, pkts, nb_pkts, user_params, true, 0);
+}
+
+static uint16_t
+mirror_tx_flow_custom_cb(uint16_t port_id __rte_unused, uint16_t qidx,
+	struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+	return mirror_flow_cb(qidx, pkts, nb_pkts, user_params, true, 0);
+}
+
+static uint16_t
+mirror_rx_flow_mac_cb(uint16_t port_id __rte_unused, uint16_t qidx,
+	struct rte_mbuf **pkts, uint16_t nb_pkts,
+	uint16_t maxi_pkts __rte_unused, void *user_params)
+{
+	return mirror_flow_cb(qidx, pkts, nb_pkts,
+			user_params, false, DST_MAC_OFFSET);
+}
+
+static uint16_t
+mirror_tx_flow_mac_cb(uint16_t port_id __rte_unused, uint16_t qidx,
+	struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+	return mirror_flow_cb(qidx, pkts, nb_pkts,
+			user_params, false, SRC_MAC_OFFSET);
+}
+
 static inline uint16_t
 mirror_port_cb(uint16_t qidx, struct rte_mbuf **pkts,
 	uint16_t nb_pkts, void *user_params)
@@ -278,6 +373,18 @@ rte_mirror_offload_register(uint16_t src_port,
 		else
 			rx_fn = mirror_rx_port_cb;
 		break;
+	case rte_mirror_type_flow_mac:
+		if (tx_cb)
+			tx_fn = mirror_tx_flow_mac_cb;
+		else
+			rx_fn = mirror_rx_flow_mac_cb;
+		break;
+	case rte_mirror_type_flow_custom:
+		if (tx_cb)
+			tx_fn = mirror_tx_flow_custom_cb;
+		else
+			rx_fn = mirror_rx_flow_custom_cb;
+		break;
 	default:
 		MIRROR_LOG(ERR, "Un-supported mirror offloading type!!!\n");
 		return -ENOTSUP;
-- 
2.18.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API Patrick Fu
@ 2020-09-09  1:09   ` Wang, Haiyue
  2020-09-09  6:02     ` Fu, Patrick
  2020-09-21 15:26   ` MEHAN, MUNISH
  1 sibling, 1 reply; 8+ messages in thread
From: Wang, Haiyue @ 2020-09-09  1:09 UTC (permalink / raw)
  To: Fu, Patrick, dev
  Cc: thomas, Yigit, Ferruh, maxime.coquelin, Richardson, Bruce,
	mm6021, Wang, Zhihong, Wang, Liang-min, Ananyev, Konstantin,
	Miskell, Timothy, Liang, Cunming, Fu,  Patrick

> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Patrick Fu
> Sent: Wednesday, September 9, 2020 08:23
> To: dev@dpdk.org
> Cc: thomas@monjalon.net; Yigit, Ferruh <ferruh.yigit@intel.com>; maxime.coquelin@redhat.com;
> Richardson, Bruce <bruce.richardson@intel.com>; mm6021@att.com; Wang, Zhihong <zhihong.wang@intel.com>;
> Wang, Liang-min <liang-min.wang@intel.com>; Ananyev, Konstantin <konstantin.ananyev@intel.com>;
> Miskell, Timothy <timothy.miskell@intel.com>; Liang, Cunming <cunming.liang@intel.com>; Fu, Patrick
> <patrick.fu@intel.com>
> Subject: [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
> 
> Network Test Access Point (TAP) is the network monitoring service
> commonly adotpted in SDN-based network infrastructures. When VMs are
> inter-connected over virtual switches, TAP requires vSwitch to mirror
> out network traffics from specific workload VM ports to the TAP
> device/VM ports.
> 
> This patch introduce 2 a new APIs to support high-throughput packet
> mirroring:
>  - rte_mirror_register()
>  - rte_mirror_unregister()
> Applications use the new API to setup the source traffic port and
> the mirror traffic port. Packets flowing over the registered
> source ports will be transmited to the mirror port when registration
> succeeds.
> 
> Signed-off-by: Liang-min Wang <liang-min.wang@intel.com>
> Signed-off-by: Patrick Fu <patrick.fu@intel.com>
> Signed-off-by: Timothy Miskell <timothy.miskell@intel.com>
> ---
>  config/common_base                       |   5 +
>  lib/Makefile                             |   2 +

Makefile has been removed now. ;-)

> --
> 2.18.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
  2020-09-09  1:09   ` Wang, Haiyue
@ 2020-09-09  6:02     ` Fu, Patrick
  0 siblings, 0 replies; 8+ messages in thread
From: Fu, Patrick @ 2020-09-09  6:02 UTC (permalink / raw)
  To: Wang, Haiyue, dev
  Cc: thomas, Yigit, Ferruh, maxime.coquelin, Richardson, Bruce,
	mm6021, Wang, Zhihong, Wang, Liang-min, Ananyev, Konstantin,
	Miskell, Timothy, Liang, Cunming

> -----Original Message-----
> From: Wang, Haiyue <haiyue.wang@intel.com>
> Sent: Wednesday, September 9, 2020 9:10 AM
> To: Fu, Patrick <patrick.fu@intel.com>; dev@dpdk.org
> Cc: thomas@monjalon.net; Yigit, Ferruh <ferruh.yigit@intel.com>;
> maxime.coquelin@redhat.com; Richardson, Bruce
> <bruce.richardson@intel.com>; mm6021@att.com; Wang, Zhihong
> <zhihong.wang@intel.com>; Wang, Liang-min <liang-min.wang@intel.com>;
> Ananyev, Konstantin <konstantin.ananyev@intel.com>; Miskell, Timothy
> <timothy.miskell@intel.com>; Liang, Cunming <cunming.liang@intel.com>;
> Fu, Patrick <patrick.fu@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
> 
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Patrick Fu
> > Sent: Wednesday, September 9, 2020 08:23
> > To: dev@dpdk.org
> > Cc: thomas@monjalon.net; Yigit, Ferruh <ferruh.yigit@intel.com>;
> maxime.coquelin@redhat.com;
> > Richardson, Bruce <bruce.richardson@intel.com>; mm6021@att.com;
> Wang, Zhihong <zhihong.wang@intel.com>;
> > Wang, Liang-min <liang-min.wang@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>;
> > Miskell, Timothy <timothy.miskell@intel.com>; Liang, Cunming
> <cunming.liang@intel.com>; Fu, Patrick
> > <patrick.fu@intel.com>
> > Subject: [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
> >
> > Network Test Access Point (TAP) is the network monitoring service
> > commonly adotpted in SDN-based network infrastructures. When VMs are
> > inter-connected over virtual switches, TAP requires vSwitch to mirror
> > out network traffics from specific workload VM ports to the TAP
> > device/VM ports.
> >
> > This patch introduce 2 a new APIs to support high-throughput packet
> > mirroring:
> >  - rte_mirror_register()
> >  - rte_mirror_unregister()
> > Applications use the new API to setup the source traffic port and
> > the mirror traffic port. Packets flowing over the registered
> > source ports will be transmited to the mirror port when registration
> > succeeds.
> >
> > Signed-off-by: Liang-min Wang <liang-min.wang@intel.com>
> > Signed-off-by: Patrick Fu <patrick.fu@intel.com>
> > Signed-off-by: Timothy Miskell <timothy.miskell@intel.com>
> > ---
> >  config/common_base                       |   5 +
> >  lib/Makefile                             |   2 +
> 
> Makefile has been removed now. ;-)
> 
Thanks Haiyue. I did forget to make the patch meson only. Will update in the next update.

> > --
> > 2.18.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API Patrick Fu
  2020-09-09  1:09   ` Wang, Haiyue
@ 2020-09-21 15:26   ` MEHAN, MUNISH
  1 sibling, 0 replies; 8+ messages in thread
From: MEHAN, MUNISH @ 2020-09-21 15:26 UTC (permalink / raw)
  To: Patrick Fu, dev
  Cc: thomas, ferruh.yigit, maxime.coquelin, bruce.richardson,
	zhihong.wang, liang-min.wang, konstantin.ananyev,
	timothy.miskell, cunming.liang

Acked-by: MEHAN, MUNISH <mm6021@att.com>


On 9/8/20, 8:28 PM, "Patrick Fu" <patrick.fu@intel.com> wrote:

    Network Test Access Point (TAP) is the network monitoring service
    commonly adotpted in SDN-based network infrastructures. When VMs are
    inter-connected over virtual switches, TAP requires vSwitch to mirror
    out network traffics from specific workload VM ports to the TAP
    device/VM ports.
    
    This patch introduce 2 a new APIs to support high-throughput packet
    mirroring:
     - rte_mirror_register()
     - rte_mirror_unregister()
    Applications use the new API to setup the source traffic port and
    the mirror traffic port. Packets flowing over the registered
    source ports will be transmited to the mirror port when registration
    succeeds.
    
    Signed-off-by: Liang-min Wang <liang-min.wang@intel.com>
    Signed-off-by: Patrick Fu <patrick.fu@intel.com>
    Signed-off-by: Timothy Miskell <timothy.miskell@intel.com>
    ---
     config/common_base                       |   5 +
     lib/Makefile                             |   2 +
     lib/librte_mirror/Makefile               |  20 ++
     lib/librte_mirror/meson.build            |   6 +
     lib/librte_mirror/rte_mirror.c           | 297 +++++++++++++++++++++++
     lib/librte_mirror/rte_mirror.h           | 111 +++++++++
     lib/librte_mirror/rte_mirror_version.map |   7 +
     lib/meson.build                          |   2 +-
     8 files changed, 449 insertions(+), 1 deletion(-)
     create mode 100644 lib/librte_mirror/Makefile
     create mode 100644 lib/librte_mirror/meson.build
     create mode 100644 lib/librte_mirror/rte_mirror.c
     create mode 100644 lib/librte_mirror/rte_mirror.h
     create mode 100644 lib/librte_mirror/rte_mirror_version.map
    
    diff --git a/config/common_base b/config/common_base
    index fbf0ee70c..60217cc93 100644
    --- a/config/common_base
    +++ b/config/common_base
    @@ -1110,6 +1110,11 @@ CONFIG_RTE_LIBRTE_GRAPH_STATS=y
     #
     CONFIG_RTE_LIBRTE_NODE=y
     
    +#
    +# Compile librte_mirror
    +#
    +CONFIG_RTE_LIBRTE_MIRROR=y
    +
     #
     # Compile the test application
     #
    diff --git a/lib/Makefile b/lib/Makefile
    index 8f5b68a2d..24175dd98 100644
    --- a/lib/Makefile
    +++ b/lib/Makefile
    @@ -112,6 +112,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
     DEPDIRS-librte_reorder := librte_eal librte_mempool librte_mbuf
     DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
     DEPDIRS-librte_pdump := librte_eal librte_mempool librte_mbuf librte_ethdev
    +DIRS-$(CONFIG_RTE_LIBRTE_MIRROR) += librte_mirror
    +DEPDIRS-librte_mirror := librte_eal librte_mempool librte_mbuf librte_ethdev
     DIRS-$(CONFIG_RTE_LIBRTE_GSO) += librte_gso
     DEPDIRS-librte_gso := librte_eal librte_mbuf librte_ethdev librte_net
     DEPDIRS-librte_gso += librte_mempool
    diff --git a/lib/librte_mirror/Makefile b/lib/librte_mirror/Makefile
    new file mode 100644
    index 000000000..3ca1db734
    --- /dev/null
    +++ b/lib/librte_mirror/Makefile
    @@ -0,0 +1,20 @@
    +# SPDX-License-Identifier: BSD-3-Clause
    +# Copyright(c) 2020- Intel Corporation
    +
    +include $(RTE_SDK)/mk/rte.vars.mk
    +
    +# library name
    +LIB = librte_mirror.a
    +
    +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
    +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ethdev
    +
    +EXPORT_MAP := rte_mirror_version.map
    +
    +# all source are stored in SRCS-y
    +SRCS-$(CONFIG_RTE_LIBRTE_MIRROR) := rte_mirror.c
    +
    +# install this header file
    +SYMLINK-$(CONFIG_RTE_LIBRTE_MIRROR)-include := rte_mirror.h
    +
    +include $(RTE_SDK)/mk/rte.lib.mk
    diff --git a/lib/librte_mirror/meson.build b/lib/librte_mirror/meson.build
    new file mode 100644
    index 000000000..2d0ba0ed2
    --- /dev/null
    +++ b/lib/librte_mirror/meson.build
    @@ -0,0 +1,6 @@
    +# SPDX-License-Identifier: BSD-3-Clause
    +# Copyright(c) 2020 Intel Corporation
    +
    +sources = files('rte_mirror.c')
    +headers = files('rte_mirror.h')
    +deps += ['ethdev']
    diff --git a/lib/librte_mirror/rte_mirror.c b/lib/librte_mirror/rte_mirror.c
    new file mode 100644
    index 000000000..f2a85976a
    --- /dev/null
    +++ b/lib/librte_mirror/rte_mirror.c
    @@ -0,0 +1,297 @@
    +/* SPDX-License-Identifier: BSD-3-Clause
    + * Copyright(c) 2020- Intel Corporation
    + */
    +
    +#include <rte_memcpy.h>
    +#include <rte_mbuf.h>
    +#include <rte_ethdev.h>
    +#include <rte_log.h>
    +#include <rte_errno.h>
    +
    +#include "rte_mirror.h"
    +
    +/* Macro for printing using RTE_LOG */
    +extern int mirror_logtype;
    +#define MIRROR_LOG(level, fmt, args...)				\
    +	rte_log(RTE_LOG_ ## level, mirror_logtype, "%s(): " fmt,	\
    +		__func__, ## args)
    +
    +#define MAC_ADDR_MAP           0x0000FFFFFFFFFFFFULL
    +#define VLAN_INSERT_FLAG       (PKT_TX_VLAN_PKT)
    +#define is_mac_addr_match(a, b) (((a^b)&MAC_ADDR_MAP) == 0)
    +#define INIT_MIRROR_DB_SIZE    8
    +#define INVALID_PORT_ID        0xFFFF
    +#define SRC_MAC_OFFSET         6
    +#define DST_MAC_OFFSET         0
    +
    +static int mirror_port_db_size;
    +static int mirror_port_used;
    +static struct rte_mirror_offload_port *mirror_port_db;
    +
    +static int
    +rte_mirror_param_copy(struct rte_mirror_param *dst,
    +	struct rte_mirror_param *src)
    +{
    +	void *extra_data;
    +
    +	memcpy(dst, src, sizeof(struct rte_mirror_param));
    +
    +	if (src->extra_data_size) {
    +		extra_data = malloc(src->extra_data_size);
    +		if (!extra_data) {
    +			MIRROR_LOG(ERR, "Out of memory !!!\n");
    +			return -1;
    +		}
    +		memcpy(extra_data, src->extra_data, src->extra_data_size);
    +
    +		dst->extra_data = extra_data;
    +	} else
    +		dst->extra_data = NULL;
    +	return 0;
    +}
    +
    +static struct rte_mirror_offload_port*
    +mirror_data_find(uint16_t port_id)
    +{
    +	int i;
    +
    +	if (mirror_port_db == NULL)
    +		return NULL;
    +	for (i = 0; i < mirror_port_db_size; i++) {
    +		if (port_id == mirror_port_db[i].port_id)
    +			return &mirror_port_db[i];
    +	}
    +	return NULL;
    +}
    +
    +static void
    +mirror_db_init(struct rte_mirror_offload_port *db, int size)
    +{
    +	int i;
    +
    +	for (i = 0; i < size; i++) {
    +		memset(&db[i], 0, sizeof(struct rte_mirror_offload_port));
    +		db[i].port_id = INVALID_PORT_ID;
    +	}
    +}
    +
    +/* Double the db size when it runs out of space */
    +static int
    +mirror_db_resize(void)
    +{
    +	int new_size = 2*mirror_port_db_size;
    +	struct rte_mirror_offload_port *new_db = malloc(
    +		sizeof(struct rte_mirror_offload_port)*new_size);
    +
    +	if (new_db == NULL) {
    +		MIRROR_LOG(ERR, "Out of memory!!!\n");
    +		return -1;
    +	}
    +
    +	memcpy(new_db, mirror_port_db, sizeof(struct rte_mirror_offload_port)
    +		*mirror_port_db_size);
    +	mirror_db_init(&new_db[mirror_port_db_size], mirror_port_db_size);
    +	mirror_port_db_size = new_size;
    +	mirror_port_db = new_db;
    +
    +	return 0;
    +}
    +
    +/* release db when used count drop to 0 */
    +static void
    +mirror_data_remove(uint16_t port_id, int tx)
    +{
    +	struct rte_mirror_offload_port *target = mirror_data_find(port_id);
    +
    +	if (!target)
    +		MIRROR_LOG(ERR, "Attempt to remove unsaved port, "
    +			"%d, %s callback\n", port_id, tx?"tx" : "rx");
    +
    +	if (tx)
    +		memset(&target->tx, 0, sizeof(struct rte_mirror_param));
    +	else
    +		memset(&target->rx, 0, sizeof(struct rte_mirror_param));
    +
    +	if ((target->rx.mirror_cb == NULL) &&
    +		(target->tx.mirror_cb == NULL)) {
    +		target->port_id = INVALID_PORT_ID;
    +		mirror_port_used--;
    +		if (mirror_port_used == 0) {
    +			free(mirror_port_db);
    +			mirror_port_db = NULL;
    +			mirror_port_db_size = 0;
    +		}
    +	}
    +}
    +
    +static struct rte_mirror_offload_port*
    +mirror_data_add(uint16_t port_id, int tx,
    +		struct rte_mirror_param *new_param)
    +{
    +	struct rte_mirror_offload_port *target = NULL;
    +	struct rte_mirror_param *param;
    +	int i;
    +
    +	if (!mirror_port_db) {
    +		mirror_port_db_size = INIT_MIRROR_DB_SIZE;
    +		mirror_port_db = malloc(sizeof(struct rte_mirror_offload_port)*
    +			mirror_port_db_size);
    +		if (!mirror_port_db) {
    +			MIRROR_LOG(ERR, "Out of memory!!!\n");
    +			return NULL;
    +		}
    +		mirror_db_init(mirror_port_db, mirror_port_db_size);
    +	}
    +	target = mirror_data_find(port_id);
    +	if (target) {
    +		if (tx) {
    +			if (target->tx.mirror_cb) {
    +				MIRROR_LOG(ERR, "Attempt to add ingress mirror "
    +					"offloading on port, %d, "
    +					"while one is outstanding\n", port_id);
    +				return target;
    +			}
    +
    +			if (rte_mirror_param_copy(&target->tx, new_param))
    +				return NULL;
    +
    +		} else {
    +			if (target->rx.mirror_cb) {
    +				MIRROR_LOG(ERR, "Attempt to add egress mirror "
    +					"offloading on port, %d, "
    +					"while one is outstanding\n", port_id);
    +				return target;
    +			}
    +
    +			if (rte_mirror_param_copy(&target->rx, new_param))
    +				return NULL;
    +		}
    +	} else {
    +		/* find an unused spot on db */
    +		for (i = 0; i < mirror_port_db_size; i++) {
    +			if (mirror_port_db[i].port_id == INVALID_PORT_ID)
    +				break;
    +		}
    +		if (i == mirror_port_db_size) {
    +			if (mirror_db_resize())
    +				return NULL;
    +		}
    +
    +		param = tx ? &mirror_port_db[i].tx : &mirror_port_db[i].rx;
    +		if (rte_mirror_param_copy(param, new_param))
    +			return NULL;
    +
    +		target = &mirror_port_db[i];
    +		target->port_id = port_id;
    +		mirror_port_used++;
    +	}
    +	return target;
    +}
    +
    +static inline void
    +mirror_pkt_update(struct rte_mbuf *pkt, uint16_t dst_vlan_id)
    +{
    +	pkt->ol_flags |= VLAN_INSERT_FLAG;
    +	pkt->vlan_tci = dst_vlan_id;
    +	rte_mbuf_refcnt_update(pkt, 1);
    +}
    +
    +int
    +rte_mirror_offload_register(uint16_t src_port,
    +		struct rte_mirror_param *param, int tx_cb)
    +{
    +	int i;
    +	struct rte_mirror_offload_port *port_info;
    +	struct rte_mirror_param *data;
    +	rte_rx_callback_fn rx_fn = NULL;
    +	rte_tx_callback_fn tx_fn = NULL;
    +
    +
    +	port_info = mirror_data_add(src_port, tx_cb, param);
    +	if (!port_info)
    +		return -EINVAL;
    +
    +	data = tx_cb ? &port_info->tx : &port_info->rx;
    +	data->pkt_buf = NULL;
    +	data->mirror_cb = malloc(sizeof(struct rte_eth_rxtx_callbac *) *
    +			data->n_src_queue);
    +	if (!data->mirror_cb) {
    +		MIRROR_LOG(ERR, "Out of memory !!!\n");
    +		return -EINVAL;
    +	}
    +
    +	switch (data->mirror_type) {
    +	default:
    +		MIRROR_LOG(ERR, "Un-supported mirror offloading type!!!\n");
    +		return -ENOTSUP;
    +	}
    +
    +	if (data->mirror_type != rte_mirror_type_port) {
    +		data->pkt_buf = malloc(sizeof(struct rte_mbuf *) *
    +				data->max_burst_size * data->n_src_queue);
    +		if (!data->pkt_buf) {
    +			RTE_ETHDEV_LOG(ERR, "Out of memory !!!");
    +			return -EINVAL;
    +		}
    +	}
    +
    +	if (!tx_cb) {
    +		for (i = 0; i < data->n_src_queue; i++) {
    +			data->mirror_cb[i] = rte_eth_add_rx_callback(src_port,
    +				i, rx_fn, data);
    +		}
    +	} else {
    +		for (i = 0; i < data->n_src_queue; i++) {
    +			data->mirror_cb[i] = rte_eth_add_tx_callback(src_port,
    +				i, tx_fn, data);
    +		}
    +	}
    +
    +	return 0;
    +}
    +
    +int
    +rte_mirror_offload_unregister(uint16_t src_port, int tx_cb)
    +{
    +	/* release both cb and pkt_buf */
    +	int i;
    +	struct rte_mirror_offload_port *port_info;
    +	struct rte_mirror_param *data;
    +
    +	port_info = mirror_data_find(src_port);
    +	if (port_info == NULL) {
    +		MIRROR_LOG(ERR, "Source port %d is not on outstanding "
    +			"port mirror db\n", src_port);
    +		return -1;
    +	}
    +	data = tx_cb ? &port_info->tx : &port_info->rx;
    +
    +	for (i = 0; i < data->n_src_queue; i++) {
    +		if (data->mirror_cb[i]) {
    +			if (tx_cb)
    +				rte_eth_remove_tx_callback(src_port,
    +						i, data->mirror_cb[i]);
    +			else
    +				rte_eth_remove_rx_callback(src_port,
    +						i, data->mirror_cb[i]);
    +		}
    +		data->mirror_cb[i] = 0;
    +	}
    +	free(data->mirror_cb);
    +
    +	if (data->pkt_buf) {
    +		free(data->pkt_buf);
    +		data->pkt_buf = NULL;
    +	}
    +
    +	if (data->extra_data) {
    +		free(data->extra_data);
    +		data->extra_data = NULL;
    +		data->extra_data_size = 0;
    +	}
    +
    +	mirror_data_remove(src_port, tx_cb);
    +	return 0;
    +}
    +
    +RTE_LOG_REGISTER(mirror_logtype, lib.mirror, NOTICE);
    diff --git a/lib/librte_mirror/rte_mirror.h b/lib/librte_mirror/rte_mirror.h
    new file mode 100644
    index 000000000..71f3e1ea1
    --- /dev/null
    +++ b/lib/librte_mirror/rte_mirror.h
    @@ -0,0 +1,111 @@
    +/* SPDX-License-Identifier: BSD-3-Clause
    + * Copyright(c) 2020- Intel Corporation
    + */
    +
    +#ifndef _RTE_MIRROR_H_
    +#define _RTE_MIRROR_H_
    +
    +/**
    + * @file
    + * RTE mirror
    + *
    + * packet mirror offloading library to provide packet mirroring support on dpdk.
    + */
    +
    +#include <stdint.h>
    +#include <rte_ethdev_core.h>
    +#include <rte_mbuf_core.h>
    +#include <rte_spinlock.h>
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +/**
    + * Function type used for mirrored packet header scan.
    + *
    + * The callback function is called on each mirrored packet
    + * to determinate if mirror condition is match.
    + *
    + * @param pkt
    + *   Pointer to one packet data.
    + * @param user_param
    + *   The arbitrary user parameter passed in by the application when the callback
    + *   was originally configured.
    + * @return
    + *   One if the condition matches, else 0.
    + */
    +typedef int (*rte_mirror_scan_fn)(struct rte_mbuf *pkt, void *user_param);
    +
    +typedef enum {
    +	rte_mirror_type_port = 0,	/* port mirror */
    +	rte_mirror_type_flow_mac,	/* mac based flow mirror */
    +	rte_mirror_type_flow_custom,	/* custom flow mirror */
    +	rte_mirror_type_invalid = 0xFF,	/* invalid mirror_type */
    +} rte_mirror_type;
    +
    +struct rte_mirror_param {
    +	uint16_t dst_port_id;
    +	uint16_t dst_vlan_id;
    +	rte_spinlock_t *locks;
    +	int n_src_queue;
    +	int n_dst_queue;
    +	struct rte_mbuf **pkt_buf;
    +	const struct rte_eth_rxtx_callback **mirror_cb;
    +	unsigned int max_burst_size;
    +	rte_mirror_scan_fn custom_scan;
    +	rte_mirror_type mirror_type;
    +	unsigned int extra_data_size;
    +	void *extra_data; /* extra mirror parameter */
    +};
    +
    +struct rte_mirror_offload_port {
    +	uint16_t port_id;
    +	struct rte_mirror_param rx;
    +	struct rte_mirror_param tx;
    +};
    +
    +/**
    + * Add a port mirroring via port offloading
    + *
    + * This function adds traffic (ingress or egress) mirroring from
    + * the specified port
    + *
    + * @param src_port
    + *   The source port where port traffic is to be captured and sent to
    + *   the offload port.
    + * @param param
    + *   The port mirror offloading parameters
    + * @param tx_cb
    + *   1: register tx callback; 0: register rx callback
    + * @return
    + *   0 = success
    + *   N > 0 any error encouter
    + */
    +__rte_experimental
    +int rte_mirror_offload_register(uint16_t src_port,
    +	struct rte_mirror_param *param, int tx_cb);
    +
    +/**
    + * Remove a port mirroring via port offloading
    + *
    + * This function removes traffic (ingress or egress) mirroring from
    + * the specified port
    + *
    + * @param src_port
    + *   The port-id of source port where port traffic is to be captured
    + *   and sent to the offload port.
    + * @param tx_cb
    + *   1: tx callback; 0: rx callback
    + * @return
    + *   0 = success
    + *   N > 0 any error encouter
    + */
    +__rte_experimental
    +int rte_mirror_offload_unregister(uint16_t src_port, int tx_cb);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif /* _RTE_PDUMP_H_ */
    diff --git a/lib/librte_mirror/rte_mirror_version.map b/lib/librte_mirror/rte_mirror_version.map
    new file mode 100644
    index 000000000..e0a4d69d1
    --- /dev/null
    +++ b/lib/librte_mirror/rte_mirror_version.map
    @@ -0,0 +1,7 @@
    +EXPERIMENTAL {
    +	global:
    +
    +	rte_mirror_offload_register;
    +	rte_mirror_offload_unregister;
    +};
    +
    diff --git a/lib/meson.build b/lib/meson.build
    index 3852c0156..6674749dd 100644
    --- a/lib/meson.build
    +++ b/lib/meson.build
    @@ -24,7 +24,7 @@ libraries = [
     	'distributor', 'efd', 'eventdev',
     	'gro', 'gso', 'ip_frag', 'jobstats',
     	'kni', 'latencystats', 'lpm', 'member',
    -	'power', 'pdump', 'rawdev', 'regexdev',
    +	'power', 'pdump', 'rawdev', 'regexdev', 'mirror',
     	'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',
     	# ipsec lib depends on net, crypto and security
     	'ipsec',
    -- 
    2.18.4
    
    


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib
  2020-09-09  0:22 [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Patrick Fu
                   ` (2 preceding siblings ...)
  2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 3/3] lib/mirror: add flow " Patrick Fu
@ 2020-09-22  7:40 ` Thomas Monjalon
  3 siblings, 0 replies; 8+ messages in thread
From: Thomas Monjalon @ 2020-09-22  7:40 UTC (permalink / raw)
  To: Patrick Fu
  Cc: dev, ferruh.yigit, maxime.coquelin, bruce.richardson, mm6021,
	zhihong.wang, liang-min.wang, konstantin.ananyev,
	timothy.miskell, cunming.liang, Jiawei Wang, Ori Kam, jerinj,
	cristian.dumitrescu, arybchenko

Patrick Fu <patrick.fu@intel.com> wrote:
> Network Test Access Point (TAP) is the network monitoring service
> commonly adotpted in SDN-based network infrastructures. When VMs are
> inter-connected over virtual switches, TAP requires vSwitch to mirror
> out network traffics from specific workload VM ports to the TAP
> device/VM ports. Classical mirroring impmentations in vSwitch make an
> extra copy of the source packets, which results in significant degradation
> in the throughput levels vSwitch could normally archieve. Therefore, we
> propose a new set of APIs to support high-throughput packet mirroring
> through hardware offloading.

In the RFC thread, you mentioned you were targetting vhost
where there is no hardware offload.
If it targets hardware offload, it should be in rte_flow.
Even if no device offload, we could implement it in rte_flow.

If you think it does not fit with rte_flow because it is
forwarding traffic between devices, then I think rte_graph
or rte_pipeline may fit.

In general I am against adding a library restricted to some specific
forwarding use cases.



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-09-25  9:16 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-09  0:22 [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Patrick Fu
2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 1/3] lib/mirror: introduce traffic mirror API Patrick Fu
2020-09-09  1:09   ` Wang, Haiyue
2020-09-09  6:02     ` Fu, Patrick
2020-09-21 15:26   ` MEHAN, MUNISH
2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 2/3] lib/mirror: add port based mirroring Patrick Fu
2020-09-09  0:22 ` [dpdk-dev] [PATCH v1 3/3] lib/mirror: add flow " Patrick Fu
2020-09-22  7:40 ` [dpdk-dev] [PATCH v1 0/3] lib: introduce traffic mirroring lib Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).