DPDK patches and discussions
 help / color / mirror / Atom feed
From: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
To: dev@dpdk.org
Cc: Kamalakannan R <kamalakannan.r@intel.com>
Subject: [PATCH V5 2/6] pipeline: support packet mirroring
Date: Wed,  6 Apr 2022 19:55:31 +0100	[thread overview]
Message-ID: <20220406185535.73084-2-cristian.dumitrescu@intel.com> (raw)
In-Reply-To: <20220406185535.73084-1-cristian.dumitrescu@intel.com>

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 <cristian.dumitrescu@intel.com>
Signed-off-by: Kamalakannan R <kamalakannan.r@intel.com>
---
 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;
-- 
2.17.1


  reply	other threads:[~2022-04-06 18:55 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-04 18:06 [PATCH 1/3] port: " Cristian Dumitrescu
2022-03-04 18:06 ` [PATCH 2/3] pipeline: " Cristian Dumitrescu
2022-03-04 18:06 ` [PATCH 3/3] examples/pipeline: " Cristian Dumitrescu
2022-04-05 12:30 ` [PATCH V2 1/3] port: " Cristian Dumitrescu
2022-04-05 12:30   ` [PATCH V2 2/3] pipeline: " Cristian Dumitrescu
2022-04-05 12:30   ` [PATCH V2 3/3] examples/pipeline: " Cristian Dumitrescu
2022-04-05 21:36   ` [PATCH V3 1/4] port: " Cristian Dumitrescu
2022-04-05 21:36     ` [PATCH V3 2/4] pipeline: " Cristian Dumitrescu
2022-04-05 21:36     ` [PATCH V3 3/4] examples/pipeline: " Cristian Dumitrescu
2022-04-05 21:36     ` [PATCH V3 4/4] pipeline: support packet recirculation Cristian Dumitrescu
2022-04-06 18:48     ` [PATCH V4 1/6] port: support packet mirroring Cristian Dumitrescu
2022-04-06 18:48       ` [PATCH V4 2/6] pipeline: " Cristian Dumitrescu
2022-04-06 18:48       ` [PATCH V4 3/6] examples/pipeline: " Cristian Dumitrescu
2022-04-06 18:48       ` [PATCH V4 4/6] examples/pipeline: add packet mirroring example Cristian Dumitrescu
2022-04-06 18:48       ` [PATCH V4 5/6] pipeline: support packet recirculation Cristian Dumitrescu
2022-04-06 18:48       ` [PATCH V4 6/6] examples/pipeline: add packet recirculation example Cristian Dumitrescu
2022-04-06 18:55       ` [PATCH V5 1/6] port: support packet mirroring Cristian Dumitrescu
2022-04-06 18:55         ` Cristian Dumitrescu [this message]
2022-04-06 18:55         ` [PATCH V5 3/6] examples/pipeline: " Cristian Dumitrescu
2022-04-06 18:55         ` [PATCH V5 4/6] examples/pipeline: add packet mirroring example Cristian Dumitrescu
2022-04-06 18:55         ` [PATCH V5 5/6] pipeline: support packet recirculation Cristian Dumitrescu
2022-04-06 18:55         ` [PATCH V5 6/6] examples/pipeline: add packet recirculation example Cristian Dumitrescu
2022-06-01 12:44         ` [PATCH V5 1/6] port: support packet mirroring Thomas Monjalon
2022-06-01 13:01         ` Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220406185535.73084-2-cristian.dumitrescu@intel.com \
    --to=cristian.dumitrescu@intel.com \
    --cc=dev@dpdk.org \
    --cc=kamalakannan.r@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).