DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd
@ 2018-09-29 20:07 Ori Kam
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Ori Kam @ 2018-09-29 20:07 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, adrien.mazarguil
  Cc: dev, dekelp, thomas, nelio.laranjeiro, yskoh, orika, shahafs

Currently testpmd have support only for encapsulation and decapsulation
for L2 tunnels.

This series adds commands for L3 tunnels types, L3 tunnel is a tunnel
that the inner packet is missing the L2 part. The encapsulation uses
the encap_l3 command in-order to remove the inner l2.
For decapsulation since the inner packet is missing the L2 there is
a need to supply it to the NIC using the decap_l3.

The tunnels are are implemented are: MPLSoGRE and MPLSoUDP
while the decap can be used for all L3 tunnels.

This series is based on add generic L2/L3 tunnel encapsulation actions [1]

[1] https://mails.dpdk.org/archives/dev/2018-September/111781.html


Ori Kam (3):
  app/testpmd: add MPLSoUDP encapsulation
  app/testpmd: add MPLSoGRE encapsulation
  app/testpmd: add decap l3 command

 app/test-pmd/cmdline.c                      | 434 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 | 317 ++++++++++++++++++++
 app/test-pmd/testpmd.h                      |  42 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 131 +++++++++
 4 files changed, 924 insertions(+)

-- 
1.8.3.1

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

* [dpdk-dev] [PATCH 1/3] app/testpmd: add MPLSoUDP encapsulation
  2018-09-29 20:07 [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ori Kam
@ 2018-09-29 20:07 ` Ori Kam
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 2/3] app/testpmd: add MPLSoGRE encapsulation Ori Kam
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-09-29 20:07 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, adrien.mazarguil
  Cc: dev, dekelp, thomas, nelio.laranjeiro, yskoh, orika, shahafs

MPLSoUDP is an example for L3 tunnel encapsulation.

Due to the complex encapsulation of MPLSoUDP flow action and based on the
fact testpmd does not allocate memory, this patch adds a new command in
testpmd to initialise a global structure containing the necessary
information to make the outer layer of the packet.  This same global
structure will then be used by the flow command line in testpmd when the
action mplsoudp_encap will be parsed, at this point, the conversion into
such action becomes trivial.

This global structure is only used for the encap action.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 app/test-pmd/cmdline.c                      | 175 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 | 123 +++++++++++++++++++
 app/test-pmd/testpmd.h                      |  17 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  50 ++++++++
 4 files changed, 365 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 589121d..10d9489 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -15186,6 +15186,179 @@ static void cmd_set_nvgre_parsed(void *parsed_result,
 	},
 };
 
+/** Set MPLSoUDP encapsulation details */
+struct cmd_set_mplsoudp_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t mplsoudp;
+	cmdline_fixed_string_t pos_token;
+	cmdline_fixed_string_t ip_version;
+	uint32_t vlan_present:1;
+	uint32_t label;
+	uint16_t udp_src;
+	uint16_t udp_dst;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t tci;
+	struct ether_addr eth_src;
+	struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsoudp_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, set, "set");
+cmdline_parse_token_string_t cmd_set_mplsoudp_mplsoudp =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, mplsoudp, "mplsoudp");
+cmdline_parse_token_string_t cmd_set_mplsoudp_mplsoudp_with_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, mplsoudp,
+				 "mplsoudp-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_version =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_version_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, ip_version,
+				 "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsoudp_label =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "label");
+cmdline_parse_token_num_t cmd_set_mplsoudp_label_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, label, UINT32);
+cmdline_parse_token_string_t cmd_set_mplsoudp_udp_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "udp-src");
+cmdline_parse_token_num_t cmd_set_mplsoudp_udp_src_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, udp_src, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_udp_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "udp-dst");
+cmdline_parse_token_num_t cmd_set_mplsoudp_udp_dst_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, udp_dst, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_ip_src_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_ip_dst_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsoudp_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsoudp_vlan_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_eth_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_eth_src_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_result, eth_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_eth_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_eth_dst_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_result, eth_dst);
+
+static void cmd_set_mplsoudp_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_mplsoudp_result *res = parsed_result;
+	union {
+		uint32_t mplsoudp_label;
+		uint8_t label[3];
+	} id = {
+		.mplsoudp_label =
+			rte_cpu_to_be_32(res->label) & RTE_BE32(0x00ffffff),
+	};
+
+	if (strcmp(res->mplsoudp, "mplsoudp") == 0)
+		mplsoudp_encap_conf.select_vlan = 0;
+	else if (strcmp(res->mplsoudp, "mplsoudp-with-vlan") == 0)
+		mplsoudp_encap_conf.select_vlan = 1;
+	if (strcmp(res->ip_version, "ipv4") == 0)
+		mplsoudp_encap_conf.select_ipv4 = 1;
+	else if (strcmp(res->ip_version, "ipv6") == 0)
+		mplsoudp_encap_conf.select_ipv4 = 0;
+	else
+		return;
+	rte_memcpy(mplsoudp_encap_conf.label, &id.label[1], 3);
+	mplsoudp_encap_conf.udp_src = rte_cpu_to_be_16(res->udp_src);
+	mplsoudp_encap_conf.udp_dst = rte_cpu_to_be_16(res->udp_dst);
+	if (mplsoudp_encap_conf.select_ipv4) {
+		IPV4_ADDR_TO_UINT(res->ip_src, mplsoudp_encap_conf.ipv4_src);
+		IPV4_ADDR_TO_UINT(res->ip_dst, mplsoudp_encap_conf.ipv4_dst);
+	} else {
+		IPV6_ADDR_TO_ARRAY(res->ip_src, mplsoudp_encap_conf.ipv6_src);
+		IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsoudp_encap_conf.ipv6_dst);
+	}
+	if (mplsoudp_encap_conf.select_vlan)
+		mplsoudp_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+	rte_memcpy(mplsoudp_encap_conf.eth_src, res->eth_src.addr_bytes,
+		   ETHER_ADDR_LEN);
+	rte_memcpy(mplsoudp_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+		   ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsoudp = {
+	.f = cmd_set_mplsoudp_parsed,
+	.data = NULL,
+	.help_str = "set mplsoudp ip-version ipv4|ipv6 label <label> udp-src"
+		" <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst <ip-dst>"
+		" eth-src <eth-src> eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsoudp_set,
+		(void *)&cmd_set_mplsoudp_mplsoudp,
+		(void *)&cmd_set_mplsoudp_ip_version,
+		(void *)&cmd_set_mplsoudp_ip_version_value,
+		(void *)&cmd_set_mplsoudp_label,
+		(void *)&cmd_set_mplsoudp_label_value,
+		(void *)&cmd_set_mplsoudp_udp_src,
+		(void *)&cmd_set_mplsoudp_udp_src_value,
+		(void *)&cmd_set_mplsoudp_udp_dst,
+		(void *)&cmd_set_mplsoudp_udp_dst_value,
+		(void *)&cmd_set_mplsoudp_ip_src,
+		(void *)&cmd_set_mplsoudp_ip_src_value,
+		(void *)&cmd_set_mplsoudp_ip_dst,
+		(void *)&cmd_set_mplsoudp_ip_dst_value,
+		(void *)&cmd_set_mplsoudp_eth_src,
+		(void *)&cmd_set_mplsoudp_eth_src_value,
+		(void *)&cmd_set_mplsoudp_eth_dst,
+		(void *)&cmd_set_mplsoudp_eth_dst_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_set_mplsoudp_with_vlan = {
+	.f = cmd_set_mplsoudp_parsed,
+	.data = NULL,
+	.help_str = "set mplsoudp-with-vlan ip-version ipv4|ipv6 label <label>"
+		" udp-src <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst"
+		" <ip-dst> vlan-tci <vlan-tci> eth-src <eth-src> eth-dst"
+		" <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsoudp_set,
+		(void *)&cmd_set_mplsoudp_mplsoudp_with_vlan,
+		(void *)&cmd_set_mplsoudp_ip_version,
+		(void *)&cmd_set_mplsoudp_ip_version_value,
+		(void *)&cmd_set_mplsoudp_label,
+		(void *)&cmd_set_mplsoudp_label_value,
+		(void *)&cmd_set_mplsoudp_udp_src,
+		(void *)&cmd_set_mplsoudp_udp_src_value,
+		(void *)&cmd_set_mplsoudp_udp_dst,
+		(void *)&cmd_set_mplsoudp_udp_dst_value,
+		(void *)&cmd_set_mplsoudp_ip_src,
+		(void *)&cmd_set_mplsoudp_ip_src_value,
+		(void *)&cmd_set_mplsoudp_ip_dst,
+		(void *)&cmd_set_mplsoudp_ip_dst_value,
+		(void *)&cmd_set_mplsoudp_vlan,
+		(void *)&cmd_set_mplsoudp_vlan_value,
+		(void *)&cmd_set_mplsoudp_eth_src,
+		(void *)&cmd_set_mplsoudp_eth_src_value,
+		(void *)&cmd_set_mplsoudp_eth_dst,
+		(void *)&cmd_set_mplsoudp_eth_dst_value,
+		NULL,
+	},
+};
+
 /* Strict link priority scheduling mode setting */
 static void
 cmd_strict_link_prio_parsed(
@@ -17814,6 +17987,8 @@ struct cmd_config_per_queue_tx_offload_result {
 	(cmdline_parse_inst_t *)&cmd_set_vxlan_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_set_nvgre,
 	(cmdline_parse_inst_t *)&cmd_set_nvgre_with_vlan,
+	(cmdline_parse_inst_t *)&cmd_set_mplsoudp,
+	(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_ddp_add,
 	(cmdline_parse_inst_t *)&cmd_ddp_del,
 	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 349e822..125d09b 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -243,6 +243,7 @@ enum index {
 	ACTION_VXLAN_DECAP,
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
+	ACTION_MPLSOUDP_ENCAP,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -271,6 +272,12 @@ struct action_tunnel_encap_data {
 	uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
 };
 
+/** Storage for struct rte_flow_action_tunnel_encap including external data. */
+struct action_tunnel_encap_l3_data {
+	struct rte_flow_action_tunnel_encap_l3 conf;
+	uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -792,6 +799,7 @@ struct parse_action_priv {
 	ACTION_VXLAN_DECAP,
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
+	ACTION_MPLSOUDP_ENCAP,
 	ZERO,
 };
 
@@ -928,6 +936,9 @@ static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
 static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
 				       const char *, unsigned int, void *,
 				       unsigned int);
+static int parse_vc_action_mplsoudp_encap(struct context *,
+					  const struct token *, const char *,
+					  unsigned int, void *, unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -2446,6 +2457,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc,
 	},
+	[ACTION_MPLSOUDP_ENCAP] = {
+		.name = "mplsoudp_encap",
+		.help = "mplsoudp encapsulation, uses configuration set by"
+			" \"set vxlan\"",
+		.priv = PRIV_ACTION(TUNNEL_ENCAP_L3,
+				    sizeof(struct action_tunnel_encap_l3_data)),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_mplsoudp_encap,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -3205,6 +3225,109 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 	action->conf = &action_nvgre_encap_data->conf;
 	return ret;
 }
+
+/** Parse MPLSOUDP encap action. */
+static int
+parse_vc_action_mplsoudp_encap(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_tunnel_encap_data *action_encap_data;
+	struct rte_flow_item_eth eth = { .type = 0, };
+	struct rte_flow_item_vlan vlan = {
+		.tci = mplsoudp_encap_conf.vlan_tci,
+		.inner_type = 0,
+	};
+	struct rte_flow_item_ipv4 ipv4 = {
+		.hdr =  {
+			.src_addr = mplsoudp_encap_conf.ipv4_src,
+			.dst_addr = mplsoudp_encap_conf.ipv4_dst,
+			.next_proto_id = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_ipv6 ipv6 = {
+		.hdr =  {
+			.proto = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_udp udp = {
+		.hdr = {
+			.src_port = mplsoudp_encap_conf.udp_src,
+			.dst_port = mplsoudp_encap_conf.udp_dst,
+		},
+	};
+	struct rte_flow_item_mpls mpls;
+	uint8_t *header;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_encap_data = ctx->object;
+	*action_encap_data = (struct action_tunnel_encap_data) {
+		.conf = (struct rte_flow_action_tunnel_encap){
+			.buf = action_encap_data->buf,
+		},
+		.buf = {},
+	};
+	header = action_encap_data->buf;
+	if (mplsoudp_encap_conf.select_vlan)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	else if (mplsoudp_encap_conf.select_ipv4)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	else
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	memcpy(eth.dst.addr_bytes,
+	       mplsoudp_encap_conf.eth_dst, ETHER_ADDR_LEN);
+	memcpy(eth.src.addr_bytes,
+	       mplsoudp_encap_conf.eth_src, ETHER_ADDR_LEN);
+	memcpy(header, &eth, sizeof(eth));
+	header += sizeof(eth);
+	if (mplsoudp_encap_conf.select_vlan) {
+		if (mplsoudp_encap_conf.select_ipv4)
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		else
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		memcpy(header, &vlan, sizeof(vlan));
+		header += sizeof(vlan);
+	}
+	if (mplsoudp_encap_conf.select_ipv4) {
+		memcpy(header, &ipv4, sizeof(ipv4));
+		header += sizeof(ipv4);
+	} else {
+		memcpy(&ipv6.hdr.src_addr,
+		       &mplsoudp_encap_conf.ipv6_src,
+		       sizeof(mplsoudp_encap_conf.ipv6_src));
+		memcpy(&ipv6.hdr.dst_addr,
+		       &mplsoudp_encap_conf.ipv6_dst,
+		       sizeof(mplsoudp_encap_conf.ipv6_dst));
+		memcpy(header, &ipv6, sizeof(ipv6));
+		header += sizeof(ipv6);
+	}
+	memcpy(header, &udp, sizeof(udp));
+	header += sizeof(udp);
+	memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
+	       RTE_DIM(mplsoudp_encap_conf.label));
+	memcpy(header, &mpls, sizeof(mpls));
+	header += sizeof(mpls);
+	action_encap_data->conf.size = header -
+		action_encap_data->buf;
+	action->conf = &action_encap_data->conf;
+	return ret;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index a1f6614..355aa84 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -487,6 +487,23 @@ struct nvgre_encap_conf {
 };
 struct nvgre_encap_conf nvgre_encap_conf;
 
+/* MPLSoUDP encap parameters. */
+struct mplsoudp_encap_conf {
+	uint32_t select_ipv4:1;
+	uint32_t select_vlan:1;
+	uint8_t label[3];
+	rte_be16_t udp_src;
+	rte_be16_t udp_dst;
+	rte_be32_t ipv4_src;
+	rte_be32_t ipv4_dst;
+	uint8_t ipv6_src[16];
+	uint8_t ipv6_dst[16];
+	rte_be16_t vlan_tci;
+	uint8_t eth_src[ETHER_ADDR_LEN];
+	uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct mplsoudp_encap_conf mplsoudp_encap_conf;
+
 static inline unsigned int
 lcore_num(void)
 {
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index dde205a..a374578 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1570,6 +1570,23 @@ flow rule using the action nvgre_encap will use the last configuration set.
 To have a different encapsulation header, one of those commands must be called
 before the flow rule creation.
 
+Config MPLSoUDP Encap outer layers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the outer layer to encapsulate a packet inside a MPLSoUDP tunnel::
+
+ set mplsoudp ip-version (ipv4|ipv6) label (label) udp-src (udp-src) \
+        udp-dst (udp-dst) ip-src (ip-src) ip-dst (ip-dst) \
+        eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) label (label) udp-src (udp-src)
+        udp-dst (udp-dst) ip-src (ip-src) ip-dst (ip-dst) vlan-tci (vlan-tci) \
+        eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action mplsoudp_encap will use the last configuration set.
+To have a different encapsulation header, one of those commands must be called
+before the flow rule creation.
+
 Port Functions
 --------------
 
@@ -3697,6 +3714,9 @@ This section lists supported actions and their attributes, if any.
 - ``nvgre_decap``: Performs a decapsulation action by stripping all headers of
   the NVGRE tunnel network overlay from the matched flow.
 
+- ``mplsoudp_encap``: Performs a MPLSoUDP encapsulation, outer layer
+  configuration is done through `Config MPLSoUDP Encap outer layers`_.
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -4025,6 +4045,36 @@ IPv6 NVGRE outer header::
  testpmd> flow create 0 ingress pattern end actions nvgre_encap /
         queue index 0 / end
 
+Sample MPLSoUDP encapsulation rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MPLSoUDP encapsulation outer layer has default value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv4 label 4 udp-src 5 udp-dst 10
+        ip-src 127.0.0.1 ip-dst 128.0.0.1 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv4 label 4 udp-src 5 udp-dst 10
+        ip-src 127.0.0.1 ip-dst 128.0.0.1 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+IPv6 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv6 mask 4 udp-src 5 udp-dst 10
+        ip-src ::1 ip-dst ::2222 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv6 mask 4 udp-src 5 udp-dst 10
+        ip-src ::1 ip-dst ::2222 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
 BPF Functions
 --------------
 
-- 
1.8.3.1

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

* [dpdk-dev] [PATCH 2/3] app/testpmd: add MPLSoGRE encapsulation
  2018-09-29 20:07 [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ori Kam
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
@ 2018-09-29 20:07 ` Ori Kam
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 3/3] app/testpmd: add decap l3 command Ori Kam
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-09-29 20:07 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, adrien.mazarguil
  Cc: dev, dekelp, thomas, nelio.laranjeiro, yskoh, orika, shahafs

Due to the complex encapsulation of MPLSoGRE flow action and based on
the fact testpmd does not allocate memory, this patch adds a new command
in testpmd to initialise a global structure containing the necessary
information to make the outer layer of the packet.  This same global
structure will then be used by the flow command line in testpmd when
the action mplsoudp_encap will be parsed, at this point, the conversion
into such action becomes trivial.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 app/test-pmd/cmdline.c                      | 153 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 | 113 ++++++++++++++++++++
 app/test-pmd/testpmd.h                      |  15 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  46 +++++++++
 4 files changed, 327 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 10d9489..2428b04 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -15359,6 +15359,157 @@ static void cmd_set_mplsoudp_parsed(void *parsed_result,
 	},
 };
 
+/** Set MPLSoGRE encapsulation details */
+struct cmd_set_mplsogre_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t mplsogre;
+	cmdline_fixed_string_t pos_token;
+	cmdline_fixed_string_t ip_version;
+	uint32_t vlan_present:1;
+	uint32_t label;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t tci;
+	struct ether_addr eth_src;
+	struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsogre_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, set, "set");
+cmdline_parse_token_string_t cmd_set_mplsogre_mplsogre =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, mplsogre,
+				 "mplsogre");
+cmdline_parse_token_string_t cmd_set_mplsogre_mplsogre_with_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, mplsogre,
+				 "mplsogre-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_version =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_version_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, ip_version,
+				 "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsogre_label =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "label");
+cmdline_parse_token_num_t cmd_set_mplsogre_label_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsogre_result, label, UINT32);
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsogre_ip_src_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsogre_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsogre_ip_dst_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsogre_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsogre_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsogre_vlan_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsogre_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsogre_eth_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsogre_eth_src_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsogre_result, eth_src);
+cmdline_parse_token_string_t cmd_set_mplsogre_eth_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsogre_eth_dst_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsogre_result, eth_dst);
+
+static void cmd_set_mplsogre_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_mplsogre_result *res = parsed_result;
+	union {
+		uint32_t mplsogre_label;
+		uint8_t label[3];
+	} id = {
+		.mplsogre_label =
+			rte_cpu_to_be_32(res->label) & RTE_BE32(0x00ffffff),
+	};
+
+	if (strcmp(res->mplsogre, "mplsogre") == 0)
+		mplsogre_encap_conf.select_vlan = 0;
+	else if (strcmp(res->mplsogre, "mplsogre-with-vlan") == 0)
+		mplsogre_encap_conf.select_vlan = 1;
+	if (strcmp(res->ip_version, "ipv4") == 0)
+		mplsogre_encap_conf.select_ipv4 = 1;
+	else if (strcmp(res->ip_version, "ipv6") == 0)
+		mplsogre_encap_conf.select_ipv4 = 0;
+	else
+		return;
+	rte_memcpy(mplsogre_encap_conf.label, &id.label[1], 3);
+	if (mplsogre_encap_conf.select_ipv4) {
+		IPV4_ADDR_TO_UINT(res->ip_src, mplsogre_encap_conf.ipv4_src);
+		IPV4_ADDR_TO_UINT(res->ip_dst, mplsogre_encap_conf.ipv4_dst);
+	} else {
+		IPV6_ADDR_TO_ARRAY(res->ip_src, mplsogre_encap_conf.ipv6_src);
+		IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsogre_encap_conf.ipv6_dst);
+	}
+	if (mplsogre_encap_conf.select_vlan)
+		mplsogre_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+	rte_memcpy(mplsogre_encap_conf.eth_src, res->eth_src.addr_bytes,
+		   ETHER_ADDR_LEN);
+	rte_memcpy(mplsogre_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+		   ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsogre = {
+	.f = cmd_set_mplsogre_parsed,
+	.data = NULL,
+	.help_str = "set mplsogre ip-version ipv4|ipv6 label <label>"
+		" ip-src <ip-src> ip-dst <ip-dst> eth-src <eth-src>"
+		" eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsogre_set,
+		(void *)&cmd_set_mplsogre_mplsogre,
+		(void *)&cmd_set_mplsogre_ip_version,
+		(void *)&cmd_set_mplsogre_ip_version_value,
+		(void *)&cmd_set_mplsogre_label,
+		(void *)&cmd_set_mplsogre_label_value,
+		(void *)&cmd_set_mplsogre_ip_src,
+		(void *)&cmd_set_mplsogre_ip_src_value,
+		(void *)&cmd_set_mplsogre_ip_dst,
+		(void *)&cmd_set_mplsogre_ip_dst_value,
+		(void *)&cmd_set_mplsogre_eth_src,
+		(void *)&cmd_set_mplsogre_eth_src_value,
+		(void *)&cmd_set_mplsogre_eth_dst,
+		(void *)&cmd_set_mplsogre_eth_dst_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_set_mplsogre_with_vlan = {
+	.f = cmd_set_mplsogre_parsed,
+	.data = NULL,
+	.help_str = "set mplsogre-with-vlan ip-version ipv4|ipv6 label <label>"
+		" ip-src <ip-src> ip-dst <ip-dst> vlan-tci <vlan-tci>"
+		" eth-src <eth-src> eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsogre_set,
+		(void *)&cmd_set_mplsogre_mplsogre_with_vlan,
+		(void *)&cmd_set_mplsogre_ip_version,
+		(void *)&cmd_set_mplsogre_ip_version_value,
+		(void *)&cmd_set_mplsogre_label,
+		(void *)&cmd_set_mplsogre_label_value,
+		(void *)&cmd_set_mplsogre_ip_src,
+		(void *)&cmd_set_mplsogre_ip_src_value,
+		(void *)&cmd_set_mplsogre_ip_dst,
+		(void *)&cmd_set_mplsogre_ip_dst_value,
+		(void *)&cmd_set_mplsogre_vlan,
+		(void *)&cmd_set_mplsogre_vlan_value,
+		(void *)&cmd_set_mplsogre_eth_src,
+		(void *)&cmd_set_mplsogre_eth_src_value,
+		(void *)&cmd_set_mplsogre_eth_dst,
+		(void *)&cmd_set_mplsogre_eth_dst_value,
+		NULL,
+	},
+};
+
 /* Strict link priority scheduling mode setting */
 static void
 cmd_strict_link_prio_parsed(
@@ -17989,6 +18140,8 @@ struct cmd_config_per_queue_tx_offload_result {
 	(cmdline_parse_inst_t *)&cmd_set_nvgre_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_set_mplsoudp,
 	(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
+	(cmdline_parse_inst_t *)&cmd_set_mplsogre,
+	(cmdline_parse_inst_t *)&cmd_set_mplsogre_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_ddp_add,
 	(cmdline_parse_inst_t *)&cmd_ddp_del,
 	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 125d09b..bedd152 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -244,6 +244,7 @@ enum index {
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
+	ACTION_MPLSOGRE_ENCAP,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -800,6 +801,7 @@ struct parse_action_priv {
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
+	ACTION_MPLSOGRE_ENCAP,
 	ZERO,
 };
 
@@ -939,6 +941,9 @@ static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
 static int parse_vc_action_mplsoudp_encap(struct context *,
 					  const struct token *, const char *,
 					  unsigned int, void *, unsigned int);
+static int parse_vc_action_mplsogre_encap(struct context *,
+					  const struct token *, const char *,
+					  unsigned int, void *, unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -2466,6 +2471,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc_action_mplsoudp_encap,
 	},
+	[ACTION_MPLSOGRE_ENCAP] = {
+		.name = "mplsogre_encap",
+		.help = "mplsogre encapsulation, uses configuration set by"
+			" \"set vxlan\"",
+		.priv = PRIV_ACTION(TUNNEL_ENCAP_L3,
+				    sizeof(struct action_tunnel_encap_l3_data)),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_mplsogre_encap,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -3328,6 +3342,105 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 	return ret;
 }
 
+/** Parse MPLSoGRE encap action. */
+static int
+parse_vc_action_mplsogre_encap(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_tunnel_encap_data *action_encap_data;
+	struct rte_flow_item_eth eth = { .type = 0, };
+	struct rte_flow_item_vlan vlan = {
+		.tci = mplsogre_encap_conf.vlan_tci,
+		.inner_type = 0,
+	};
+	struct rte_flow_item_ipv4 ipv4 = {
+		.hdr =  {
+			.src_addr = mplsogre_encap_conf.ipv4_src,
+			.dst_addr = mplsogre_encap_conf.ipv4_dst,
+			.next_proto_id = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_ipv6 ipv6 = {
+		.hdr =  {
+			.proto = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_gre gre = {
+		.protocol = rte_cpu_to_be_16(0x8848),
+	};
+	struct rte_flow_item_mpls mpls;
+	uint8_t *header;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_encap_data = ctx->object;
+	*action_encap_data = (struct action_tunnel_encap_data) {
+		.conf = (struct rte_flow_action_tunnel_encap){
+			.buf = action_encap_data->buf,
+		},
+		.buf = {},
+	};
+	header = action_encap_data->buf;
+	if (mplsogre_encap_conf.select_vlan)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	else if (mplsogre_encap_conf.select_ipv4)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	else
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	memcpy(eth.dst.addr_bytes,
+	       mplsogre_encap_conf.eth_dst, ETHER_ADDR_LEN);
+	memcpy(eth.src.addr_bytes,
+	       mplsogre_encap_conf.eth_src, ETHER_ADDR_LEN);
+	memcpy(header, &eth, sizeof(eth));
+	header += sizeof(eth);
+	if (mplsogre_encap_conf.select_vlan) {
+		if (mplsogre_encap_conf.select_ipv4)
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		else
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		memcpy(header, &vlan, sizeof(vlan));
+		header += sizeof(vlan);
+	}
+	if (mplsogre_encap_conf.select_ipv4) {
+		memcpy(header, &ipv4, sizeof(ipv4));
+		header += sizeof(ipv4);
+	} else {
+		memcpy(&ipv6.hdr.src_addr,
+		       &mplsogre_encap_conf.ipv6_src,
+		       sizeof(mplsogre_encap_conf.ipv6_src));
+		memcpy(&ipv6.hdr.dst_addr,
+		       &mplsogre_encap_conf.ipv6_dst,
+		       sizeof(mplsogre_encap_conf.ipv6_dst));
+		memcpy(header, &ipv6, sizeof(ipv6));
+		header += sizeof(ipv6);
+	}
+	memcpy(header, &gre, sizeof(gre));
+	header += sizeof(gre);
+	memcpy(mpls.label_tc_s, mplsogre_encap_conf.label,
+	       RTE_DIM(mplsogre_encap_conf.label));
+	memcpy(header, &mpls, sizeof(mpls));
+	header += sizeof(mpls);
+	action_encap_data->conf.size = header -
+		action_encap_data->buf;
+	action->conf = &action_encap_data->conf;
+	return ret;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 355aa84..fea7418 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -504,6 +504,21 @@ struct mplsoudp_encap_conf {
 };
 struct mplsoudp_encap_conf mplsoudp_encap_conf;
 
+/* MPLSoGRE encap parameters. */
+struct mplsogre_encap_conf {
+	uint32_t select_ipv4:1;
+	uint32_t select_vlan:1;
+	uint8_t label[3];
+	rte_be32_t ipv4_src;
+	rte_be32_t ipv4_dst;
+	uint8_t ipv6_src[16];
+	uint8_t ipv6_dst[16];
+	rte_be16_t vlan_tci;
+	uint8_t eth_src[ETHER_ADDR_LEN];
+	uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct mplsogre_encap_conf mplsogre_encap_conf;
+
 static inline unsigned int
 lcore_num(void)
 {
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index a374578..4308109 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1587,6 +1587,21 @@ flow rule using the action mplsoudp_encap will use the last configuration set.
 To have a different encapsulation header, one of those commands must be called
 before the flow rule creation.
 
+Config MPLSoGRE Encap outer layers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the outer layer to encapsulate a packet inside a MPLSoGRE tunnel::
+
+ set mplsoudp ip-version (ipv4|ipv6) label (label) ip-src (ip-src) \
+        ip-dst (ip-dst) eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) label (label) ip-src (ip-src) \
+        ip-dst (ip-dst) vlan-tci (vlan-tci) eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action mplsogre_encap will use the last configuration set.
+To have a different encapsulation header, one of those commands must be called
+before the flow rule creation.
+
 Port Functions
 --------------
 
@@ -3717,6 +3732,9 @@ This section lists supported actions and their attributes, if any.
 - ``mplsoudp_encap``: Performs a MPLSoUDP encapsulation, outer layer
   configuration is done through `Config MPLSoUDP Encap outer layers`_.
 
+- ``mplsogre_encap``: Performs a MPLSoGRE encapsulation, outer layer
+  configuration is done through `Config MPLSoGRE Encap outer layers`_.
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -4075,6 +4093,34 @@ IPv6 MPLSoUDP outer header::
         eth-dst 22:22:22:22:22:22
  testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
 
+Sample MPLSoGRE encapsulation rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MPLSoGRE encapsulation outer layer has default value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 MPLSoGRE outer header::
+
+ testpmd> set mplsoudp ip-version ipv4 label 4 ip-src 127.0.0.1 ip-dst 128.0.0.1
+        eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv4 label 4 ip-src 127.0.0.1
+        ip-dst 128.0.0.1 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+IPv6 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv6 mask 4 ip-src ::1 ip-dst ::2222
+        eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv6 mask 4 ip-src ::1
+        ip-dst ::2222 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
 BPF Functions
 --------------
 
-- 
1.8.3.1

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

* [dpdk-dev] [PATCH 3/3] app/testpmd: add decap l3 command
  2018-09-29 20:07 [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ori Kam
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 2/3] app/testpmd: add MPLSoGRE encapsulation Ori Kam
@ 2018-09-29 20:07 ` Ori Kam
  2018-10-05 13:35 ` [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit
  2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
  4 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-09-29 20:07 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, adrien.mazarguil
  Cc: dev, dekelp, thomas, nelio.laranjeiro, yskoh, orika, shahafs

This commit introduce the decapsulation of L3 tunnels.
L3 tunnels are tunnels that the inner packet is missing the L3 layer.
This command uses the generic L3 decap command and decapsulate any
tunnel by replacing the outer layers with the supplied L2.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 app/test-pmd/cmdline.c                      | 106 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 |  81 +++++++++++++++++++++
 app/test-pmd/testpmd.h                      |  10 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  35 +++++++++
 4 files changed, 232 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 2428b04..8fa241f 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -15510,6 +15510,110 @@ static void cmd_set_mplsogre_parsed(void *parsed_result,
 	},
 };
 
+/** Set decapsulation L3 details */
+struct cmd_set_decap_l3_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t decap_l3;
+	cmdline_fixed_string_t pos_token;
+	cmdline_fixed_string_t ip_version;
+	uint32_t vlan_present:1;
+	uint16_t tci;
+	struct ether_addr eth_src;
+	struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_decap_l3_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, set, "set");
+cmdline_parse_token_string_t cmd_set_decap_l3_decap_l3 =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, decap_l3,
+				 "decap_l3");
+cmdline_parse_token_string_t cmd_set_decap_l3_decap_l3_with_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, decap_l3,
+				 "decap_l3-with-vlan");
+cmdline_parse_token_string_t cmd_set_decap_l3_ip_version =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "ip-version");
+cmdline_parse_token_string_t cmd_set_decap_l3_ip_version_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, ip_version,
+				 "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_decap_l3_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "vlan-tci");
+cmdline_parse_token_num_t cmd_set_decap_l3_vlan_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_decap_l3_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_decap_l3_eth_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_decap_l3_eth_src_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_decap_l3_result, eth_src);
+cmdline_parse_token_string_t cmd_set_decap_l3_eth_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_decap_l3_eth_dst_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_decap_l3_result, eth_dst);
+
+static void cmd_set_decap_l3_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_decap_l3_result *res = parsed_result;
+
+	if (strcmp(res->decap_l3, "decap_l3") == 0)
+		decap_l3_conf.select_vlan = 0;
+	else if (strcmp(res->decap_l3, "decap_l3-with-vlan") == 0)
+		decap_l3_conf.select_vlan = 1;
+	if (strcmp(res->ip_version, "ipv4") == 0)
+		decap_l3_conf.select_ipv4 = 1;
+	else if (strcmp(res->ip_version, "ipv6") == 0)
+		decap_l3_conf.select_ipv4 = 0;
+	else
+		return;
+	if (decap_l3_conf.select_vlan)
+		decap_l3_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+	rte_memcpy(decap_l3_conf.eth_src, res->eth_src.addr_bytes,
+		   ETHER_ADDR_LEN);
+	rte_memcpy(decap_l3_conf.eth_dst, res->eth_dst.addr_bytes,
+		   ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_decap_l3 = {
+	.f = cmd_set_decap_l3_parsed,
+	.data = NULL,
+	.help_str = "set decap_l3 ip-version ipv4|ipv6 eth-src <eth-src>"
+		" eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_decap_l3_set,
+		(void *)&cmd_set_decap_l3_decap_l3,
+		(void *)&cmd_set_decap_l3_ip_version,
+		(void *)&cmd_set_decap_l3_ip_version_value,
+		(void *)&cmd_set_decap_l3_eth_src,
+		(void *)&cmd_set_decap_l3_eth_src_value,
+		(void *)&cmd_set_decap_l3_eth_dst,
+		(void *)&cmd_set_decap_l3_eth_dst_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_set_decap_l3_with_vlan = {
+	.f = cmd_set_decap_l3_parsed,
+	.data = NULL,
+	.help_str = "set decap_l3-with-vlan ip-version ipv4|ipv6"
+		" vlan-tci <vlan-tci> eth-src <eth-src> eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_decap_l3_set,
+		(void *)&cmd_set_decap_l3_decap_l3_with_vlan,
+		(void *)&cmd_set_decap_l3_ip_version,
+		(void *)&cmd_set_decap_l3_ip_version_value,
+		(void *)&cmd_set_decap_l3_vlan,
+		(void *)&cmd_set_decap_l3_vlan_value,
+		(void *)&cmd_set_decap_l3_eth_src,
+		(void *)&cmd_set_decap_l3_eth_src_value,
+		(void *)&cmd_set_decap_l3_eth_dst,
+		(void *)&cmd_set_decap_l3_eth_dst_value,
+		NULL,
+	},
+};
+
 /* Strict link priority scheduling mode setting */
 static void
 cmd_strict_link_prio_parsed(
@@ -18142,6 +18246,8 @@ struct cmd_config_per_queue_tx_offload_result {
 	(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_set_mplsogre,
 	(cmdline_parse_inst_t *)&cmd_set_mplsogre_with_vlan,
+	(cmdline_parse_inst_t *)&cmd_set_decap_l3,
+	(cmdline_parse_inst_t *)&cmd_set_decap_l3_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_ddp_add,
 	(cmdline_parse_inst_t *)&cmd_ddp_del,
 	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index bedd152..a4f1398 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -245,6 +245,7 @@ enum index {
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
 	ACTION_MPLSOGRE_ENCAP,
+	ACTION_DECAP_L3,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -279,6 +280,16 @@ struct action_tunnel_encap_l3_data {
 	uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
 };
 
+/** Maximum buffer size for the decap L3 data. */
+#define ACTION_TUNNEL_DECAP_L3_MAX_BUFFER_SIZE \
+	(sizeof(struct rte_flow_item_eth) + sizeof(struct rte_flow_item_vlan))
+
+/** Storage for struct rte_flow_action_tunnel_decap_l3 with external data. */
+struct action_tunnel_decap_l3_data {
+	struct rte_flow_action_tunnel_decap_l3 conf;
+	uint8_t buf[ACTION_TUNNEL_DECAP_L3_MAX_BUFFER_SIZE];
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -802,6 +813,7 @@ struct parse_action_priv {
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
 	ACTION_MPLSOGRE_ENCAP,
+	ACTION_DECAP_L3,
 	ZERO,
 };
 
@@ -944,6 +956,9 @@ static int parse_vc_action_mplsoudp_encap(struct context *,
 static int parse_vc_action_mplsogre_encap(struct context *,
 					  const struct token *, const char *,
 					  unsigned int, void *, unsigned int);
+static int parse_vc_action_decap_l3(struct context *, const struct token *,
+				    const char *, unsigned int, void *,
+				    unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -2480,6 +2495,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc_action_mplsogre_encap,
 	},
+	[ACTION_DECAP_L3] = {
+		.name = "decap_l3",
+		.help = "decap l3 packet, uses configuration set by"
+			" \"set decap_l3\"",
+		.priv = PRIV_ACTION(TUNNEL_DECAP_L3,
+				    sizeof(struct action_tunnel_decap_l3_data)),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_decap_l3,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -3441,6 +3465,63 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 	return ret;
 }
 
+/** Parse decap_l3 action. */
+static int
+parse_vc_action_decap_l3(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len,
+			 void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_tunnel_decap_l3_data *action_decap_data;
+	struct rte_flow_item_eth eth = { .type = 0, };
+	struct rte_flow_item_vlan vlan = {
+		.tci = mplsogre_encap_conf.vlan_tci,
+		.inner_type = 0,
+	};
+	uint8_t *header;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_decap_data = ctx->object;
+	*action_decap_data = (struct action_tunnel_decap_l3_data) {
+		.conf = (struct rte_flow_action_tunnel_decap_l3){
+			.buf = action_decap_data->buf,
+		},
+		.buf = {},
+	};
+	header = action_decap_data->buf;
+	if (decap_l3_conf.select_vlan)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	memcpy(eth.dst.addr_bytes, decap_l3_conf.eth_dst, ETHER_ADDR_LEN);
+	memcpy(eth.src.addr_bytes, decap_l3_conf.eth_src, ETHER_ADDR_LEN);
+	memcpy(header, &eth, sizeof(eth));
+	header += sizeof(eth);
+	if (decap_l3_conf.select_vlan) {
+		if (decap_l3_conf.select_ipv4)
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		else
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		memcpy(header, &vlan, sizeof(vlan));
+		header += sizeof(vlan);
+	}
+	action_decap_data->conf.size = header - action_decap_data->buf;
+	action->conf = &action_decap_data->conf;
+	return ret;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index fea7418..e43529f 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -519,6 +519,16 @@ struct mplsogre_encap_conf {
 };
 struct mplsogre_encap_conf mplsogre_encap_conf;
 
+/* decap l3 parameters. */
+struct decap_l3_conf {
+	uint32_t select_ipv4:1;
+	uint32_t select_vlan:1;
+	rte_be16_t vlan_tci;
+	uint8_t eth_src[ETHER_ADDR_LEN];
+	uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct decap_l3_conf decap_l3_conf;
+
 static inline unsigned int
 lcore_num(void)
 {
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 4308109..46a764c 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1602,6 +1602,20 @@ flow rule using the action mplsogre_encap will use the last configuration set.
 To have a different encapsulation header, one of those commands must be called
 before the flow rule creation.
 
+Config decapsulation L3
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the layer 2 header value of the inner packet::
+
+ set decap_l3 ip-version (ipv4|ipv6) eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) vlan-tci (vlan-tci) \
+ eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action decap_l3 will use the last configuration set.
+To have a different decapsulation header, one of those commands must be called
+before the flow rule creation.
+
 Port Functions
 --------------
 
@@ -3735,6 +3749,9 @@ This section lists supported actions and their attributes, if any.
 - ``mplsogre_encap``: Performs a MPLSoGRE encapsulation, outer layer
   configuration is done through `Config MPLSoGRE Encap outer layers`_.
 
+- ``decap_l3``: Performs a decapsulation of l3 tunnel, L2 configuratin
+  is done through `Config decapsulation L3`_.
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -4121,6 +4138,24 @@ IPv6 MPLSoUDP outer header::
         eth-dst 22:22:22:22:22:22
  testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
 
+Sample decapsulation l3 rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Decapsulation of L3 tunnel has default L2 value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 L2 header::
+
+ testpmd> set decap_l3 ip-version ipv4 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 ingress pattern eth / ipv4 / udp / mpls / end actions
+        decap_l3 / end
+
+ testpmd> set decap_l3-with-vlan ip-version ipv4 vlan-tci 34
+        eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 ingress pattern eth / ipv4 / udp / mpls / end actions
+        decap_l3 / end
+
 BPF Functions
 --------------
 
-- 
1.8.3.1

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

* Re: [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd
  2018-09-29 20:07 [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ori Kam
                   ` (2 preceding siblings ...)
  2018-09-29 20:07 ` [dpdk-dev] [PATCH 3/3] app/testpmd: add decap l3 command Ori Kam
@ 2018-10-05 13:35 ` Ferruh Yigit
  2018-10-05 14:00   ` Ori Kam
  2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
  4 siblings, 1 reply; 11+ messages in thread
From: Ferruh Yigit @ 2018-10-05 13:35 UTC (permalink / raw)
  To: Ori Kam, wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	stephen, adrien.mazarguil
  Cc: dev, dekelp, thomas, nelio.laranjeiro, yskoh, shahafs

On 9/29/2018 9:07 PM, Ori Kam wrote:
> Currently testpmd have support only for encapsulation and decapsulation
> for L2 tunnels.
> 
> This series adds commands for L3 tunnels types, L3 tunnel is a tunnel
> that the inner packet is missing the L2 part. The encapsulation uses
> the encap_l3 command in-order to remove the inner l2.
> For decapsulation since the inner packet is missing the L2 there is
> a need to supply it to the NIC using the decap_l3.
> 
> The tunnels are are implemented are: MPLSoGRE and MPLSoUDP
> while the decap can be used for all L3 tunnels.
> 
> This series is based on add generic L2/L3 tunnel encapsulation actions [1]
> 
> [1] https://mails.dpdk.org/archives/dev/2018-September/111781.html
> 
> 
> Ori Kam (3):
>   app/testpmd: add MPLSoUDP encapsulation
>   app/testpmd: add MPLSoGRE encapsulation
>   app/testpmd: add decap l3 command

Same here, can you please rebase on latest next-net. Getting a few old rte_flow
related patch caused conflict with almost all outstanding rte_flow patches...

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

* Re: [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd
  2018-10-05 13:35 ` [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit
@ 2018-10-05 14:00   ` Ori Kam
  0 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-10-05 14:00 UTC (permalink / raw)
  To: Ferruh Yigit, wenzhuo.lu, jingjing.wu, bernard.iremonger,
	arybchenko, stephen, Adrien Mazarguil
  Cc: dev, Dekel Peled, Thomas Monjalon, Nélio Laranjeiro,
	Yongseok Koh, Shahaf Shuler



> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@intel.com>
> Sent: Friday, October 5, 2018 4:35 PM
> To: Ori Kam <orika@mellanox.com>; wenzhuo.lu@intel.com;
> jingjing.wu@intel.com; bernard.iremonger@intel.com;
> arybchenko@solarflare.com; stephen@networkplumber.org; Adrien Mazarguil
> <adrien.mazarguil@6wind.com>
> Cc: dev@dpdk.org; Dekel Peled <dekelp@mellanox.com>; Thomas Monjalon
> <thomas@monjalon.net>; Nélio Laranjeiro <nelio.laranjeiro@6wind.com>;
> Yongseok Koh <yskoh@mellanox.com>; Shahaf Shuler
> <shahafs@mellanox.com>
> Subject: Re: [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd
> 
> On 9/29/2018 9:07 PM, Ori Kam wrote:
> > Currently testpmd have support only for encapsulation and decapsulation
> > for L2 tunnels.
> >
> > This series adds commands for L3 tunnels types, L3 tunnel is a tunnel
> > that the inner packet is missing the L2 part. The encapsulation uses
> > the encap_l3 command in-order to remove the inner l2.
> > For decapsulation since the inner packet is missing the L2 there is
> > a need to supply it to the NIC using the decap_l3.
> >
> > The tunnels are are implemented are: MPLSoGRE and MPLSoUDP
> > while the decap can be used for all L3 tunnels.
> >
> > This series is based on add generic L2/L3 tunnel encapsulation actions [1]
> >
> > [1]
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmails.d
> pdk.org%2Farchives%2Fdev%2F2018-
> September%2F111781.html&amp;data=02%7C01%7Corika%40mellanox.com%7
> C2b9d669ee5d1459c1afe08d62ac76dee%7Ca652971c7d2e4d9ba6a4d149256f4
> 61b%7C0%7C0%7C636743433379968780&amp;sdata=BJPaGlCcjAHeIxNsQ%2B
> 1crdhT3UwDWj1Z931Osy6I4Qo%3D&amp;reserved=0
> >
> >
> > Ori Kam (3):
> >   app/testpmd: add MPLSoUDP encapsulation
> >   app/testpmd: add MPLSoGRE encapsulation
> >   app/testpmd: add decap l3 command
> 
> Same here, can you please rebase on latest next-net. Getting a few old rte_flow
> related patch caused conflict with almost all outstanding rte_flow patches...

Sure I will send a new version.

Ori

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

* [dpdk-dev] [PATCH v2 0/3] app/testpmd: add l3 encap/decap cmd
  2018-09-29 20:07 [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ori Kam
                   ` (3 preceding siblings ...)
  2018-10-05 13:35 ` [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit
@ 2018-10-07 14:41 ` Ori Kam
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
                     ` (3 more replies)
  4 siblings, 4 replies; 11+ messages in thread
From: Ori Kam @ 2018-10-07 14:41 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, Adrien Mazarguil
  Cc: dev, Dekel Peled, Thomas Monjalon, Nélio Laranjeiro,
	Yongseok Koh, Ori Kam, Shahaf Shuler

Currently testpmd have support only for encapsulation and decapsulation
for L2 tunnels.

This series adds commands for L3 tunnels types, L3 tunnel is a tunnel
that the inner packet is missing the L2 part. The encapsulation uses
the encap_l3 command in-order to remove the inner l2.
For decapsulation since the inner packet is missing the L2 there is
a need to supply it to the NIC using the decap_l3.

The tunnels are are implemented are: MPLSoGRE and MPLSoUDP
while the decap can be used for all L3 tunnels.

This series is based on add generic L2/L3 tunnel encapsulation actions [1]

[1] https://mails.dpdk.org/archives/dev/2018-September/111781.html

v2:
 * rebase on tip.


Ori Kam (3):
  app/testpmd: add MPLSoUDP encapsulation
  app/testpmd: add MPLSoGRE encapsulation
  app/testpmd: add decap l3 command

 app/test-pmd/cmdline.c                      | 434 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 | 316 ++++++++++++++++++++
 app/test-pmd/testpmd.h                      |  42 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 131 +++++++++
 4 files changed, 923 insertions(+)

-- 
1.8.3.1

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

* [dpdk-dev] [PATCH v2 1/3] app/testpmd: add MPLSoUDP encapsulation
  2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
@ 2018-10-07 14:41   ` Ori Kam
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: add MPLSoGRE encapsulation Ori Kam
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-10-07 14:41 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, Adrien Mazarguil
  Cc: dev, Dekel Peled, Thomas Monjalon, Nélio Laranjeiro,
	Yongseok Koh, Ori Kam, Shahaf Shuler

MPLSoUDP is an example for L3 tunnel encapsulation.

Due to the complex encapsulation of MPLSoUDP flow action and based on the
fact testpmd does not allocate memory, this patch adds a new command in
testpmd to initialise a global structure containing the necessary
information to make the outer layer of the packet.  This same global
structure will then be used by the flow command line in testpmd when the
action mplsoudp_encap will be parsed, at this point, the conversion into
such action becomes trivial.

This global structure is only used for the encap action.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 app/test-pmd/cmdline.c                      | 175 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 | 122 +++++++++++++++++++
 app/test-pmd/testpmd.h                      |  17 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  50 ++++++++
 4 files changed, 364 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 3376a66..492dc5d 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -15274,6 +15274,179 @@ static void cmd_set_nvgre_parsed(void *parsed_result,
 	},
 };
 
+/** Set MPLSoUDP encapsulation details */
+struct cmd_set_mplsoudp_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t mplsoudp;
+	cmdline_fixed_string_t pos_token;
+	cmdline_fixed_string_t ip_version;
+	uint32_t vlan_present:1;
+	uint32_t label;
+	uint16_t udp_src;
+	uint16_t udp_dst;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t tci;
+	struct ether_addr eth_src;
+	struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsoudp_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, set, "set");
+cmdline_parse_token_string_t cmd_set_mplsoudp_mplsoudp =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, mplsoudp, "mplsoudp");
+cmdline_parse_token_string_t cmd_set_mplsoudp_mplsoudp_with_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, mplsoudp,
+				 "mplsoudp-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_version =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_version_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, ip_version,
+				 "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsoudp_label =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "label");
+cmdline_parse_token_num_t cmd_set_mplsoudp_label_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, label, UINT32);
+cmdline_parse_token_string_t cmd_set_mplsoudp_udp_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "udp-src");
+cmdline_parse_token_num_t cmd_set_mplsoudp_udp_src_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, udp_src, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_udp_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "udp-dst");
+cmdline_parse_token_num_t cmd_set_mplsoudp_udp_dst_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, udp_dst, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_ip_src_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_ip_dst_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsoudp_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsoudp_vlan_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_eth_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_eth_src_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_result, eth_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_eth_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+				 "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_eth_dst_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_result, eth_dst);
+
+static void cmd_set_mplsoudp_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_mplsoudp_result *res = parsed_result;
+	union {
+		uint32_t mplsoudp_label;
+		uint8_t label[3];
+	} id = {
+		.mplsoudp_label =
+			rte_cpu_to_be_32(res->label) & RTE_BE32(0x00ffffff),
+	};
+
+	if (strcmp(res->mplsoudp, "mplsoudp") == 0)
+		mplsoudp_encap_conf.select_vlan = 0;
+	else if (strcmp(res->mplsoudp, "mplsoudp-with-vlan") == 0)
+		mplsoudp_encap_conf.select_vlan = 1;
+	if (strcmp(res->ip_version, "ipv4") == 0)
+		mplsoudp_encap_conf.select_ipv4 = 1;
+	else if (strcmp(res->ip_version, "ipv6") == 0)
+		mplsoudp_encap_conf.select_ipv4 = 0;
+	else
+		return;
+	rte_memcpy(mplsoudp_encap_conf.label, &id.label[1], 3);
+	mplsoudp_encap_conf.udp_src = rte_cpu_to_be_16(res->udp_src);
+	mplsoudp_encap_conf.udp_dst = rte_cpu_to_be_16(res->udp_dst);
+	if (mplsoudp_encap_conf.select_ipv4) {
+		IPV4_ADDR_TO_UINT(res->ip_src, mplsoudp_encap_conf.ipv4_src);
+		IPV4_ADDR_TO_UINT(res->ip_dst, mplsoudp_encap_conf.ipv4_dst);
+	} else {
+		IPV6_ADDR_TO_ARRAY(res->ip_src, mplsoudp_encap_conf.ipv6_src);
+		IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsoudp_encap_conf.ipv6_dst);
+	}
+	if (mplsoudp_encap_conf.select_vlan)
+		mplsoudp_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+	rte_memcpy(mplsoudp_encap_conf.eth_src, res->eth_src.addr_bytes,
+		   ETHER_ADDR_LEN);
+	rte_memcpy(mplsoudp_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+		   ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsoudp = {
+	.f = cmd_set_mplsoudp_parsed,
+	.data = NULL,
+	.help_str = "set mplsoudp ip-version ipv4|ipv6 label <label> udp-src"
+		" <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst <ip-dst>"
+		" eth-src <eth-src> eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsoudp_set,
+		(void *)&cmd_set_mplsoudp_mplsoudp,
+		(void *)&cmd_set_mplsoudp_ip_version,
+		(void *)&cmd_set_mplsoudp_ip_version_value,
+		(void *)&cmd_set_mplsoudp_label,
+		(void *)&cmd_set_mplsoudp_label_value,
+		(void *)&cmd_set_mplsoudp_udp_src,
+		(void *)&cmd_set_mplsoudp_udp_src_value,
+		(void *)&cmd_set_mplsoudp_udp_dst,
+		(void *)&cmd_set_mplsoudp_udp_dst_value,
+		(void *)&cmd_set_mplsoudp_ip_src,
+		(void *)&cmd_set_mplsoudp_ip_src_value,
+		(void *)&cmd_set_mplsoudp_ip_dst,
+		(void *)&cmd_set_mplsoudp_ip_dst_value,
+		(void *)&cmd_set_mplsoudp_eth_src,
+		(void *)&cmd_set_mplsoudp_eth_src_value,
+		(void *)&cmd_set_mplsoudp_eth_dst,
+		(void *)&cmd_set_mplsoudp_eth_dst_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_set_mplsoudp_with_vlan = {
+	.f = cmd_set_mplsoudp_parsed,
+	.data = NULL,
+	.help_str = "set mplsoudp-with-vlan ip-version ipv4|ipv6 label <label>"
+		" udp-src <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst"
+		" <ip-dst> vlan-tci <vlan-tci> eth-src <eth-src> eth-dst"
+		" <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsoudp_set,
+		(void *)&cmd_set_mplsoudp_mplsoudp_with_vlan,
+		(void *)&cmd_set_mplsoudp_ip_version,
+		(void *)&cmd_set_mplsoudp_ip_version_value,
+		(void *)&cmd_set_mplsoudp_label,
+		(void *)&cmd_set_mplsoudp_label_value,
+		(void *)&cmd_set_mplsoudp_udp_src,
+		(void *)&cmd_set_mplsoudp_udp_src_value,
+		(void *)&cmd_set_mplsoudp_udp_dst,
+		(void *)&cmd_set_mplsoudp_udp_dst_value,
+		(void *)&cmd_set_mplsoudp_ip_src,
+		(void *)&cmd_set_mplsoudp_ip_src_value,
+		(void *)&cmd_set_mplsoudp_ip_dst,
+		(void *)&cmd_set_mplsoudp_ip_dst_value,
+		(void *)&cmd_set_mplsoudp_vlan,
+		(void *)&cmd_set_mplsoudp_vlan_value,
+		(void *)&cmd_set_mplsoudp_eth_src,
+		(void *)&cmd_set_mplsoudp_eth_src_value,
+		(void *)&cmd_set_mplsoudp_eth_dst,
+		(void *)&cmd_set_mplsoudp_eth_dst_value,
+		NULL,
+	},
+};
+
 /* Strict link priority scheduling mode setting */
 static void
 cmd_strict_link_prio_parsed(
@@ -17903,6 +18076,8 @@ struct cmd_config_per_queue_tx_offload_result {
 	(cmdline_parse_inst_t *)&cmd_set_vxlan_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_set_nvgre,
 	(cmdline_parse_inst_t *)&cmd_set_nvgre_with_vlan,
+	(cmdline_parse_inst_t *)&cmd_set_mplsoudp,
+	(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_ddp_add,
 	(cmdline_parse_inst_t *)&cmd_ddp_del,
 	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index c9dba79..7e8de1d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -243,6 +243,7 @@ enum index {
 	ACTION_VXLAN_DECAP,
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
+	ACTION_MPLSOUDP_ENCAP,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -271,6 +272,12 @@ struct action_tunnel_encap_data {
 	uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
 };
 
+/** Storage for struct rte_flow_action_tunnel_encap including external data. */
+struct action_tunnel_encap_l3_data {
+	struct rte_flow_action_tunnel_encap_l3 conf;
+	uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -792,6 +799,7 @@ struct parse_action_priv {
 	ACTION_VXLAN_DECAP,
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
+	ACTION_MPLSOUDP_ENCAP,
 	ZERO,
 };
 
@@ -928,6 +936,9 @@ static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
 static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
 				       const char *, unsigned int, void *,
 				       unsigned int);
+static int parse_vc_action_mplsoudp_encap(struct context *,
+					  const struct token *, const char *,
+					  unsigned int, void *, unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -2446,6 +2457,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc,
 	},
+	[ACTION_MPLSOUDP_ENCAP] = {
+		.name = "mplsoudp_encap",
+		.help = "mplsoudp encapsulation, uses configuration set by"
+			" \"set vxlan\"",
+		.priv = PRIV_ACTION(TUNNEL_ENCAP_L3,
+				    sizeof(struct action_tunnel_encap_l3_data)),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_mplsoudp_encap,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -3207,6 +3227,108 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 	return ret;
 }
 
+/** Parse MPLSOUDP encap action. */
+static int
+parse_vc_action_mplsoudp_encap(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_tunnel_encap_data *action_encap_data;
+	struct rte_flow_item_eth eth = { .type = 0, };
+	struct rte_flow_item_vlan vlan = {
+		.tci = mplsoudp_encap_conf.vlan_tci,
+		.inner_type = 0,
+	};
+	struct rte_flow_item_ipv4 ipv4 = {
+		.hdr =  {
+			.src_addr = mplsoudp_encap_conf.ipv4_src,
+			.dst_addr = mplsoudp_encap_conf.ipv4_dst,
+			.next_proto_id = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_ipv6 ipv6 = {
+		.hdr =  {
+			.proto = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_udp udp = {
+		.hdr = {
+			.src_port = mplsoudp_encap_conf.udp_src,
+			.dst_port = mplsoudp_encap_conf.udp_dst,
+		},
+	};
+	struct rte_flow_item_mpls mpls;
+	uint8_t *header;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_encap_data = ctx->object;
+	*action_encap_data = (struct action_tunnel_encap_data) {
+		.conf = (struct rte_flow_action_tunnel_encap){
+			.buf = action_encap_data->buf,
+		},
+		.buf = {},
+	};
+	header = action_encap_data->buf;
+	if (mplsoudp_encap_conf.select_vlan)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	else if (mplsoudp_encap_conf.select_ipv4)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	else
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	memcpy(eth.dst.addr_bytes,
+	       mplsoudp_encap_conf.eth_dst, ETHER_ADDR_LEN);
+	memcpy(eth.src.addr_bytes,
+	       mplsoudp_encap_conf.eth_src, ETHER_ADDR_LEN);
+	memcpy(header, &eth, sizeof(eth));
+	header += sizeof(eth);
+	if (mplsoudp_encap_conf.select_vlan) {
+		if (mplsoudp_encap_conf.select_ipv4)
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		else
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		memcpy(header, &vlan, sizeof(vlan));
+		header += sizeof(vlan);
+	}
+	if (mplsoudp_encap_conf.select_ipv4) {
+		memcpy(header, &ipv4, sizeof(ipv4));
+		header += sizeof(ipv4);
+	} else {
+		memcpy(&ipv6.hdr.src_addr,
+		       &mplsoudp_encap_conf.ipv6_src,
+		       sizeof(mplsoudp_encap_conf.ipv6_src));
+		memcpy(&ipv6.hdr.dst_addr,
+		       &mplsoudp_encap_conf.ipv6_dst,
+		       sizeof(mplsoudp_encap_conf.ipv6_dst));
+		memcpy(header, &ipv6, sizeof(ipv6));
+		header += sizeof(ipv6);
+	}
+	memcpy(header, &udp, sizeof(udp));
+	header += sizeof(udp);
+	memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
+	       RTE_DIM(mplsoudp_encap_conf.label));
+	memcpy(header, &mpls, sizeof(mpls));
+	header += sizeof(mpls);
+	action_encap_data->conf.size = header -
+		action_encap_data->buf;
+	action->conf = &action_encap_data->conf;
+	return ret;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 11afb48..57fc6d1 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -484,6 +484,23 @@ struct nvgre_encap_conf {
 };
 struct nvgre_encap_conf nvgre_encap_conf;
 
+/* MPLSoUDP encap parameters. */
+struct mplsoudp_encap_conf {
+	uint32_t select_ipv4:1;
+	uint32_t select_vlan:1;
+	uint8_t label[3];
+	rte_be16_t udp_src;
+	rte_be16_t udp_dst;
+	rte_be32_t ipv4_src;
+	rte_be32_t ipv4_dst;
+	uint8_t ipv6_src[16];
+	uint8_t ipv6_dst[16];
+	rte_be16_t vlan_tci;
+	uint8_t eth_src[ETHER_ADDR_LEN];
+	uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct mplsoudp_encap_conf mplsoudp_encap_conf;
+
 static inline unsigned int
 lcore_num(void)
 {
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 3a73000..e07a6f8 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1570,6 +1570,23 @@ flow rule using the action nvgre_encap will use the last configuration set.
 To have a different encapsulation header, one of those commands must be called
 before the flow rule creation.
 
+Config MPLSoUDP Encap outer layers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the outer layer to encapsulate a packet inside a MPLSoUDP tunnel::
+
+ set mplsoudp ip-version (ipv4|ipv6) label (label) udp-src (udp-src) \
+        udp-dst (udp-dst) ip-src (ip-src) ip-dst (ip-dst) \
+        eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) label (label) udp-src (udp-src)
+        udp-dst (udp-dst) ip-src (ip-src) ip-dst (ip-dst) vlan-tci (vlan-tci) \
+        eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action mplsoudp_encap will use the last configuration set.
+To have a different encapsulation header, one of those commands must be called
+before the flow rule creation.
+
 Port Functions
 --------------
 
@@ -3704,6 +3721,9 @@ This section lists supported actions and their attributes, if any.
 - ``nvgre_decap``: Performs a decapsulation action by stripping all headers of
   the NVGRE tunnel network overlay from the matched flow.
 
+- ``mplsoudp_encap``: Performs a MPLSoUDP encapsulation, outer layer
+  configuration is done through `Config MPLSoUDP Encap outer layers`_.
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -4032,6 +4052,36 @@ IPv6 NVGRE outer header::
  testpmd> flow create 0 ingress pattern end actions nvgre_encap /
         queue index 0 / end
 
+Sample MPLSoUDP encapsulation rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MPLSoUDP encapsulation outer layer has default value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv4 label 4 udp-src 5 udp-dst 10
+        ip-src 127.0.0.1 ip-dst 128.0.0.1 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv4 label 4 udp-src 5 udp-dst 10
+        ip-src 127.0.0.1 ip-dst 128.0.0.1 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+IPv6 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv6 mask 4 udp-src 5 udp-dst 10
+        ip-src ::1 ip-dst ::2222 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv6 mask 4 udp-src 5 udp-dst 10
+        ip-src ::1 ip-dst ::2222 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
 BPF Functions
 --------------
 
-- 
1.8.3.1

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

* [dpdk-dev] [PATCH v2 2/3] app/testpmd: add MPLSoGRE encapsulation
  2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
@ 2018-10-07 14:41   ` Ori Kam
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 3/3] app/testpmd: add decap l3 command Ori Kam
  2018-10-09 16:48   ` [dpdk-dev] [PATCH v2 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit
  3 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-10-07 14:41 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, Adrien Mazarguil
  Cc: dev, Dekel Peled, Thomas Monjalon, Nélio Laranjeiro,
	Yongseok Koh, Ori Kam, Shahaf Shuler

Due to the complex encapsulation of MPLSoGRE flow action and based on
the fact testpmd does not allocate memory, this patch adds a new command
in testpmd to initialise a global structure containing the necessary
information to make the outer layer of the packet.  This same global
structure will then be used by the flow command line in testpmd when
the action mplsoudp_encap will be parsed, at this point, the conversion
into such action becomes trivial.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 app/test-pmd/cmdline.c                      | 153 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 | 113 ++++++++++++++++++++
 app/test-pmd/testpmd.h                      |  15 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  46 +++++++++
 4 files changed, 327 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 492dc5d..357660b 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -15447,6 +15447,157 @@ static void cmd_set_mplsoudp_parsed(void *parsed_result,
 	},
 };
 
+/** Set MPLSoGRE encapsulation details */
+struct cmd_set_mplsogre_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t mplsogre;
+	cmdline_fixed_string_t pos_token;
+	cmdline_fixed_string_t ip_version;
+	uint32_t vlan_present:1;
+	uint32_t label;
+	cmdline_ipaddr_t ip_src;
+	cmdline_ipaddr_t ip_dst;
+	uint16_t tci;
+	struct ether_addr eth_src;
+	struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsogre_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, set, "set");
+cmdline_parse_token_string_t cmd_set_mplsogre_mplsogre =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, mplsogre,
+				 "mplsogre");
+cmdline_parse_token_string_t cmd_set_mplsogre_mplsogre_with_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, mplsogre,
+				 "mplsogre-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_version =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_version_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, ip_version,
+				 "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsogre_label =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "label");
+cmdline_parse_token_num_t cmd_set_mplsogre_label_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsogre_result, label, UINT32);
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsogre_ip_src_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsogre_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsogre_ip_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsogre_ip_dst_value =
+	TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsogre_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsogre_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsogre_vlan_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_mplsogre_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsogre_eth_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsogre_eth_src_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsogre_result, eth_src);
+cmdline_parse_token_string_t cmd_set_mplsogre_eth_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_mplsogre_result, pos_token,
+				 "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsogre_eth_dst_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsogre_result, eth_dst);
+
+static void cmd_set_mplsogre_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_mplsogre_result *res = parsed_result;
+	union {
+		uint32_t mplsogre_label;
+		uint8_t label[3];
+	} id = {
+		.mplsogre_label =
+			rte_cpu_to_be_32(res->label) & RTE_BE32(0x00ffffff),
+	};
+
+	if (strcmp(res->mplsogre, "mplsogre") == 0)
+		mplsogre_encap_conf.select_vlan = 0;
+	else if (strcmp(res->mplsogre, "mplsogre-with-vlan") == 0)
+		mplsogre_encap_conf.select_vlan = 1;
+	if (strcmp(res->ip_version, "ipv4") == 0)
+		mplsogre_encap_conf.select_ipv4 = 1;
+	else if (strcmp(res->ip_version, "ipv6") == 0)
+		mplsogre_encap_conf.select_ipv4 = 0;
+	else
+		return;
+	rte_memcpy(mplsogre_encap_conf.label, &id.label[1], 3);
+	if (mplsogre_encap_conf.select_ipv4) {
+		IPV4_ADDR_TO_UINT(res->ip_src, mplsogre_encap_conf.ipv4_src);
+		IPV4_ADDR_TO_UINT(res->ip_dst, mplsogre_encap_conf.ipv4_dst);
+	} else {
+		IPV6_ADDR_TO_ARRAY(res->ip_src, mplsogre_encap_conf.ipv6_src);
+		IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsogre_encap_conf.ipv6_dst);
+	}
+	if (mplsogre_encap_conf.select_vlan)
+		mplsogre_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+	rte_memcpy(mplsogre_encap_conf.eth_src, res->eth_src.addr_bytes,
+		   ETHER_ADDR_LEN);
+	rte_memcpy(mplsogre_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+		   ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsogre = {
+	.f = cmd_set_mplsogre_parsed,
+	.data = NULL,
+	.help_str = "set mplsogre ip-version ipv4|ipv6 label <label>"
+		" ip-src <ip-src> ip-dst <ip-dst> eth-src <eth-src>"
+		" eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsogre_set,
+		(void *)&cmd_set_mplsogre_mplsogre,
+		(void *)&cmd_set_mplsogre_ip_version,
+		(void *)&cmd_set_mplsogre_ip_version_value,
+		(void *)&cmd_set_mplsogre_label,
+		(void *)&cmd_set_mplsogre_label_value,
+		(void *)&cmd_set_mplsogre_ip_src,
+		(void *)&cmd_set_mplsogre_ip_src_value,
+		(void *)&cmd_set_mplsogre_ip_dst,
+		(void *)&cmd_set_mplsogre_ip_dst_value,
+		(void *)&cmd_set_mplsogre_eth_src,
+		(void *)&cmd_set_mplsogre_eth_src_value,
+		(void *)&cmd_set_mplsogre_eth_dst,
+		(void *)&cmd_set_mplsogre_eth_dst_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_set_mplsogre_with_vlan = {
+	.f = cmd_set_mplsogre_parsed,
+	.data = NULL,
+	.help_str = "set mplsogre-with-vlan ip-version ipv4|ipv6 label <label>"
+		" ip-src <ip-src> ip-dst <ip-dst> vlan-tci <vlan-tci>"
+		" eth-src <eth-src> eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_mplsogre_set,
+		(void *)&cmd_set_mplsogre_mplsogre_with_vlan,
+		(void *)&cmd_set_mplsogre_ip_version,
+		(void *)&cmd_set_mplsogre_ip_version_value,
+		(void *)&cmd_set_mplsogre_label,
+		(void *)&cmd_set_mplsogre_label_value,
+		(void *)&cmd_set_mplsogre_ip_src,
+		(void *)&cmd_set_mplsogre_ip_src_value,
+		(void *)&cmd_set_mplsogre_ip_dst,
+		(void *)&cmd_set_mplsogre_ip_dst_value,
+		(void *)&cmd_set_mplsogre_vlan,
+		(void *)&cmd_set_mplsogre_vlan_value,
+		(void *)&cmd_set_mplsogre_eth_src,
+		(void *)&cmd_set_mplsogre_eth_src_value,
+		(void *)&cmd_set_mplsogre_eth_dst,
+		(void *)&cmd_set_mplsogre_eth_dst_value,
+		NULL,
+	},
+};
+
 /* Strict link priority scheduling mode setting */
 static void
 cmd_strict_link_prio_parsed(
@@ -18078,6 +18229,8 @@ struct cmd_config_per_queue_tx_offload_result {
 	(cmdline_parse_inst_t *)&cmd_set_nvgre_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_set_mplsoudp,
 	(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
+	(cmdline_parse_inst_t *)&cmd_set_mplsogre,
+	(cmdline_parse_inst_t *)&cmd_set_mplsogre_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_ddp_add,
 	(cmdline_parse_inst_t *)&cmd_ddp_del,
 	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 7e8de1d..9433823 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -244,6 +244,7 @@ enum index {
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
+	ACTION_MPLSOGRE_ENCAP,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -800,6 +801,7 @@ struct parse_action_priv {
 	ACTION_NVGRE_ENCAP,
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
+	ACTION_MPLSOGRE_ENCAP,
 	ZERO,
 };
 
@@ -939,6 +941,9 @@ static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
 static int parse_vc_action_mplsoudp_encap(struct context *,
 					  const struct token *, const char *,
 					  unsigned int, void *, unsigned int);
+static int parse_vc_action_mplsogre_encap(struct context *,
+					  const struct token *, const char *,
+					  unsigned int, void *, unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -2466,6 +2471,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc_action_mplsoudp_encap,
 	},
+	[ACTION_MPLSOGRE_ENCAP] = {
+		.name = "mplsogre_encap",
+		.help = "mplsogre encapsulation, uses configuration set by"
+			" \"set vxlan\"",
+		.priv = PRIV_ACTION(TUNNEL_ENCAP_L3,
+				    sizeof(struct action_tunnel_encap_l3_data)),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_mplsogre_encap,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -3329,6 +3343,105 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 	return ret;
 }
 
+/** Parse MPLSoGRE encap action. */
+static int
+parse_vc_action_mplsogre_encap(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_tunnel_encap_data *action_encap_data;
+	struct rte_flow_item_eth eth = { .type = 0, };
+	struct rte_flow_item_vlan vlan = {
+		.tci = mplsogre_encap_conf.vlan_tci,
+		.inner_type = 0,
+	};
+	struct rte_flow_item_ipv4 ipv4 = {
+		.hdr =  {
+			.src_addr = mplsogre_encap_conf.ipv4_src,
+			.dst_addr = mplsogre_encap_conf.ipv4_dst,
+			.next_proto_id = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_ipv6 ipv6 = {
+		.hdr =  {
+			.proto = IP_PROTO_UDP,
+		},
+	};
+	struct rte_flow_item_gre gre = {
+		.protocol = rte_cpu_to_be_16(0x8848),
+	};
+	struct rte_flow_item_mpls mpls;
+	uint8_t *header;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_encap_data = ctx->object;
+	*action_encap_data = (struct action_tunnel_encap_data) {
+		.conf = (struct rte_flow_action_tunnel_encap){
+			.buf = action_encap_data->buf,
+		},
+		.buf = {},
+	};
+	header = action_encap_data->buf;
+	if (mplsogre_encap_conf.select_vlan)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	else if (mplsogre_encap_conf.select_ipv4)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+	else
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+	memcpy(eth.dst.addr_bytes,
+	       mplsogre_encap_conf.eth_dst, ETHER_ADDR_LEN);
+	memcpy(eth.src.addr_bytes,
+	       mplsogre_encap_conf.eth_src, ETHER_ADDR_LEN);
+	memcpy(header, &eth, sizeof(eth));
+	header += sizeof(eth);
+	if (mplsogre_encap_conf.select_vlan) {
+		if (mplsogre_encap_conf.select_ipv4)
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		else
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		memcpy(header, &vlan, sizeof(vlan));
+		header += sizeof(vlan);
+	}
+	if (mplsogre_encap_conf.select_ipv4) {
+		memcpy(header, &ipv4, sizeof(ipv4));
+		header += sizeof(ipv4);
+	} else {
+		memcpy(&ipv6.hdr.src_addr,
+		       &mplsogre_encap_conf.ipv6_src,
+		       sizeof(mplsogre_encap_conf.ipv6_src));
+		memcpy(&ipv6.hdr.dst_addr,
+		       &mplsogre_encap_conf.ipv6_dst,
+		       sizeof(mplsogre_encap_conf.ipv6_dst));
+		memcpy(header, &ipv6, sizeof(ipv6));
+		header += sizeof(ipv6);
+	}
+	memcpy(header, &gre, sizeof(gre));
+	header += sizeof(gre);
+	memcpy(mpls.label_tc_s, mplsogre_encap_conf.label,
+	       RTE_DIM(mplsogre_encap_conf.label));
+	memcpy(header, &mpls, sizeof(mpls));
+	header += sizeof(mpls);
+	action_encap_data->conf.size = header -
+		action_encap_data->buf;
+	action->conf = &action_encap_data->conf;
+	return ret;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 57fc6d1..6d1b2c3 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -501,6 +501,21 @@ struct mplsoudp_encap_conf {
 };
 struct mplsoudp_encap_conf mplsoudp_encap_conf;
 
+/* MPLSoGRE encap parameters. */
+struct mplsogre_encap_conf {
+	uint32_t select_ipv4:1;
+	uint32_t select_vlan:1;
+	uint8_t label[3];
+	rte_be32_t ipv4_src;
+	rte_be32_t ipv4_dst;
+	uint8_t ipv6_src[16];
+	uint8_t ipv6_dst[16];
+	rte_be16_t vlan_tci;
+	uint8_t eth_src[ETHER_ADDR_LEN];
+	uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct mplsogre_encap_conf mplsogre_encap_conf;
+
 static inline unsigned int
 lcore_num(void)
 {
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index e07a6f8..61280f1 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1587,6 +1587,21 @@ flow rule using the action mplsoudp_encap will use the last configuration set.
 To have a different encapsulation header, one of those commands must be called
 before the flow rule creation.
 
+Config MPLSoGRE Encap outer layers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the outer layer to encapsulate a packet inside a MPLSoGRE tunnel::
+
+ set mplsoudp ip-version (ipv4|ipv6) label (label) ip-src (ip-src) \
+        ip-dst (ip-dst) eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) label (label) ip-src (ip-src) \
+        ip-dst (ip-dst) vlan-tci (vlan-tci) eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action mplsogre_encap will use the last configuration set.
+To have a different encapsulation header, one of those commands must be called
+before the flow rule creation.
+
 Port Functions
 --------------
 
@@ -3724,6 +3739,9 @@ This section lists supported actions and their attributes, if any.
 - ``mplsoudp_encap``: Performs a MPLSoUDP encapsulation, outer layer
   configuration is done through `Config MPLSoUDP Encap outer layers`_.
 
+- ``mplsogre_encap``: Performs a MPLSoGRE encapsulation, outer layer
+  configuration is done through `Config MPLSoGRE Encap outer layers`_.
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -4082,6 +4100,34 @@ IPv6 MPLSoUDP outer header::
         eth-dst 22:22:22:22:22:22
  testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
 
+Sample MPLSoGRE encapsulation rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MPLSoGRE encapsulation outer layer has default value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 MPLSoGRE outer header::
+
+ testpmd> set mplsoudp ip-version ipv4 label 4 ip-src 127.0.0.1 ip-dst 128.0.0.1
+        eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv4 label 4 ip-src 127.0.0.1
+        ip-dst 128.0.0.1 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+IPv6 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv6 mask 4 ip-src ::1 ip-dst ::2222
+        eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv6 mask 4 ip-src ::1
+        ip-dst ::2222 vlan-tci 34 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
 BPF Functions
 --------------
 
-- 
1.8.3.1

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

* [dpdk-dev] [PATCH v2 3/3] app/testpmd: add decap l3 command
  2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: add MPLSoGRE encapsulation Ori Kam
@ 2018-10-07 14:41   ` Ori Kam
  2018-10-09 16:48   ` [dpdk-dev] [PATCH v2 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit
  3 siblings, 0 replies; 11+ messages in thread
From: Ori Kam @ 2018-10-07 14:41 UTC (permalink / raw)
  To: wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	ferruh.yigit, stephen, Adrien Mazarguil
  Cc: dev, Dekel Peled, Thomas Monjalon, Nélio Laranjeiro,
	Yongseok Koh, Ori Kam, Shahaf Shuler

This commit introduce the decapsulation of L3 tunnels.
L3 tunnels are tunnels that the inner packet is missing the L3 layer.
This command uses the generic L3 decap command and decapsulate any
tunnel by replacing the outer layers with the supplied L2.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 app/test-pmd/cmdline.c                      | 106 ++++++++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c                 |  81 +++++++++++++++++++++
 app/test-pmd/testpmd.h                      |  10 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  35 +++++++++
 4 files changed, 232 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 357660b..563a4e1 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -15598,6 +15598,110 @@ static void cmd_set_mplsogre_parsed(void *parsed_result,
 	},
 };
 
+/** Set decapsulation L3 details */
+struct cmd_set_decap_l3_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t decap_l3;
+	cmdline_fixed_string_t pos_token;
+	cmdline_fixed_string_t ip_version;
+	uint32_t vlan_present:1;
+	uint16_t tci;
+	struct ether_addr eth_src;
+	struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_decap_l3_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, set, "set");
+cmdline_parse_token_string_t cmd_set_decap_l3_decap_l3 =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, decap_l3,
+				 "decap_l3");
+cmdline_parse_token_string_t cmd_set_decap_l3_decap_l3_with_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, decap_l3,
+				 "decap_l3-with-vlan");
+cmdline_parse_token_string_t cmd_set_decap_l3_ip_version =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "ip-version");
+cmdline_parse_token_string_t cmd_set_decap_l3_ip_version_value =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, ip_version,
+				 "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_decap_l3_vlan =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "vlan-tci");
+cmdline_parse_token_num_t cmd_set_decap_l3_vlan_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_decap_l3_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_decap_l3_eth_src =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_decap_l3_eth_src_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_decap_l3_result, eth_src);
+cmdline_parse_token_string_t cmd_set_decap_l3_eth_dst =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+				 "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_decap_l3_eth_dst_value =
+	TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_decap_l3_result, eth_dst);
+
+static void cmd_set_decap_l3_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_decap_l3_result *res = parsed_result;
+
+	if (strcmp(res->decap_l3, "decap_l3") == 0)
+		decap_l3_conf.select_vlan = 0;
+	else if (strcmp(res->decap_l3, "decap_l3-with-vlan") == 0)
+		decap_l3_conf.select_vlan = 1;
+	if (strcmp(res->ip_version, "ipv4") == 0)
+		decap_l3_conf.select_ipv4 = 1;
+	else if (strcmp(res->ip_version, "ipv6") == 0)
+		decap_l3_conf.select_ipv4 = 0;
+	else
+		return;
+	if (decap_l3_conf.select_vlan)
+		decap_l3_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+	rte_memcpy(decap_l3_conf.eth_src, res->eth_src.addr_bytes,
+		   ETHER_ADDR_LEN);
+	rte_memcpy(decap_l3_conf.eth_dst, res->eth_dst.addr_bytes,
+		   ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_decap_l3 = {
+	.f = cmd_set_decap_l3_parsed,
+	.data = NULL,
+	.help_str = "set decap_l3 ip-version ipv4|ipv6 eth-src <eth-src>"
+		" eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_decap_l3_set,
+		(void *)&cmd_set_decap_l3_decap_l3,
+		(void *)&cmd_set_decap_l3_ip_version,
+		(void *)&cmd_set_decap_l3_ip_version_value,
+		(void *)&cmd_set_decap_l3_eth_src,
+		(void *)&cmd_set_decap_l3_eth_src_value,
+		(void *)&cmd_set_decap_l3_eth_dst,
+		(void *)&cmd_set_decap_l3_eth_dst_value,
+		NULL,
+	},
+};
+
+cmdline_parse_inst_t cmd_set_decap_l3_with_vlan = {
+	.f = cmd_set_decap_l3_parsed,
+	.data = NULL,
+	.help_str = "set decap_l3-with-vlan ip-version ipv4|ipv6"
+		" vlan-tci <vlan-tci> eth-src <eth-src> eth-dst <eth-dst>",
+	.tokens = {
+		(void *)&cmd_set_decap_l3_set,
+		(void *)&cmd_set_decap_l3_decap_l3_with_vlan,
+		(void *)&cmd_set_decap_l3_ip_version,
+		(void *)&cmd_set_decap_l3_ip_version_value,
+		(void *)&cmd_set_decap_l3_vlan,
+		(void *)&cmd_set_decap_l3_vlan_value,
+		(void *)&cmd_set_decap_l3_eth_src,
+		(void *)&cmd_set_decap_l3_eth_src_value,
+		(void *)&cmd_set_decap_l3_eth_dst,
+		(void *)&cmd_set_decap_l3_eth_dst_value,
+		NULL,
+	},
+};
+
 /* Strict link priority scheduling mode setting */
 static void
 cmd_strict_link_prio_parsed(
@@ -18231,6 +18335,8 @@ struct cmd_config_per_queue_tx_offload_result {
 	(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_set_mplsogre,
 	(cmdline_parse_inst_t *)&cmd_set_mplsogre_with_vlan,
+	(cmdline_parse_inst_t *)&cmd_set_decap_l3,
+	(cmdline_parse_inst_t *)&cmd_set_decap_l3_with_vlan,
 	(cmdline_parse_inst_t *)&cmd_ddp_add,
 	(cmdline_parse_inst_t *)&cmd_ddp_del,
 	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 9433823..cf1374f 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -245,6 +245,7 @@ enum index {
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
 	ACTION_MPLSOGRE_ENCAP,
+	ACTION_DECAP_L3,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -279,6 +280,16 @@ struct action_tunnel_encap_l3_data {
 	uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
 };
 
+/** Maximum buffer size for the decap L3 data. */
+#define ACTION_TUNNEL_DECAP_L3_MAX_BUFFER_SIZE \
+	(sizeof(struct rte_flow_item_eth) + sizeof(struct rte_flow_item_vlan))
+
+/** Storage for struct rte_flow_action_tunnel_decap_l3 with external data. */
+struct action_tunnel_decap_l3_data {
+	struct rte_flow_action_tunnel_decap_l3 conf;
+	uint8_t buf[ACTION_TUNNEL_DECAP_L3_MAX_BUFFER_SIZE];
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -802,6 +813,7 @@ struct parse_action_priv {
 	ACTION_NVGRE_DECAP,
 	ACTION_MPLSOUDP_ENCAP,
 	ACTION_MPLSOGRE_ENCAP,
+	ACTION_DECAP_L3,
 	ZERO,
 };
 
@@ -944,6 +956,9 @@ static int parse_vc_action_mplsoudp_encap(struct context *,
 static int parse_vc_action_mplsogre_encap(struct context *,
 					  const struct token *, const char *,
 					  unsigned int, void *, unsigned int);
+static int parse_vc_action_decap_l3(struct context *, const struct token *,
+				    const char *, unsigned int, void *,
+				    unsigned int);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -2480,6 +2495,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
 		.call = parse_vc_action_mplsogre_encap,
 	},
+	[ACTION_DECAP_L3] = {
+		.name = "decap_l3",
+		.help = "decap l3 packet, uses configuration set by"
+			" \"set decap_l3\"",
+		.priv = PRIV_ACTION(TUNNEL_DECAP_L3,
+				    sizeof(struct action_tunnel_decap_l3_data)),
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_decap_l3,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -3442,6 +3466,63 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
 	return ret;
 }
 
+/** Parse decap_l3 action. */
+static int
+parse_vc_action_decap_l3(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len,
+			 void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_tunnel_decap_l3_data *action_decap_data;
+	struct rte_flow_item_eth eth = { .type = 0, };
+	struct rte_flow_item_vlan vlan = {
+		.tci = mplsogre_encap_conf.vlan_tci,
+		.inner_type = 0,
+	};
+	uint8_t *header;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_decap_data = ctx->object;
+	*action_decap_data = (struct action_tunnel_decap_l3_data) {
+		.conf = (struct rte_flow_action_tunnel_decap_l3){
+			.buf = action_decap_data->buf,
+		},
+		.buf = {},
+	};
+	header = action_decap_data->buf;
+	if (decap_l3_conf.select_vlan)
+		eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+	memcpy(eth.dst.addr_bytes, decap_l3_conf.eth_dst, ETHER_ADDR_LEN);
+	memcpy(eth.src.addr_bytes, decap_l3_conf.eth_src, ETHER_ADDR_LEN);
+	memcpy(header, &eth, sizeof(eth));
+	header += sizeof(eth);
+	if (decap_l3_conf.select_vlan) {
+		if (decap_l3_conf.select_ipv4)
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+		else
+			vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+		memcpy(header, &vlan, sizeof(vlan));
+		header += sizeof(vlan);
+	}
+	action_decap_data->conf.size = header - action_decap_data->buf;
+	action->conf = &action_decap_data->conf;
+	return ret;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 6d1b2c3..377470e 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -516,6 +516,16 @@ struct mplsogre_encap_conf {
 };
 struct mplsogre_encap_conf mplsogre_encap_conf;
 
+/* decap l3 parameters. */
+struct decap_l3_conf {
+	uint32_t select_ipv4:1;
+	uint32_t select_vlan:1;
+	rte_be16_t vlan_tci;
+	uint8_t eth_src[ETHER_ADDR_LEN];
+	uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct decap_l3_conf decap_l3_conf;
+
 static inline unsigned int
 lcore_num(void)
 {
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 61280f1..7183aee 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1602,6 +1602,20 @@ flow rule using the action mplsogre_encap will use the last configuration set.
 To have a different encapsulation header, one of those commands must be called
 before the flow rule creation.
 
+Config decapsulation L3
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the layer 2 header value of the inner packet::
+
+ set decap_l3 ip-version (ipv4|ipv6) eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) vlan-tci (vlan-tci) \
+ eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action decap_l3 will use the last configuration set.
+To have a different decapsulation header, one of those commands must be called
+before the flow rule creation.
+
 Port Functions
 --------------
 
@@ -3742,6 +3756,9 @@ This section lists supported actions and their attributes, if any.
 - ``mplsogre_encap``: Performs a MPLSoGRE encapsulation, outer layer
   configuration is done through `Config MPLSoGRE Encap outer layers`_.
 
+- ``decap_l3``: Performs a decapsulation of l3 tunnel, L2 configuratin
+  is done through `Config decapsulation L3`_.
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -4128,6 +4145,24 @@ IPv6 MPLSoUDP outer header::
         eth-dst 22:22:22:22:22:22
  testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
 
+Sample decapsulation l3 rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Decapsulation of L3 tunnel has default L2 value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 L2 header::
+
+ testpmd> set decap_l3 ip-version ipv4 eth-src 11:11:11:11:11:11
+        eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 ingress pattern eth / ipv4 / udp / mpls / end actions
+        decap_l3 / end
+
+ testpmd> set decap_l3-with-vlan ip-version ipv4 vlan-tci 34
+        eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 ingress pattern eth / ipv4 / udp / mpls / end actions
+        decap_l3 / end
+
 BPF Functions
 --------------
 
-- 
1.8.3.1

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

* Re: [dpdk-dev] [PATCH v2 0/3] app/testpmd: add l3 encap/decap cmd
  2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
                     ` (2 preceding siblings ...)
  2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 3/3] app/testpmd: add decap l3 command Ori Kam
@ 2018-10-09 16:48   ` Ferruh Yigit
  3 siblings, 0 replies; 11+ messages in thread
From: Ferruh Yigit @ 2018-10-09 16:48 UTC (permalink / raw)
  To: Ori Kam, wenzhuo.lu, jingjing.wu, bernard.iremonger, arybchenko,
	stephen, Adrien Mazarguil
  Cc: dev, Dekel Peled, Thomas Monjalon, Nélio Laranjeiro,
	Yongseok Koh, Shahaf Shuler

On 10/7/2018 3:41 PM, Ori Kam wrote:
> Currently testpmd have support only for encapsulation and decapsulation
> for L2 tunnels.
> 
> This series adds commands for L3 tunnels types, L3 tunnel is a tunnel
> that the inner packet is missing the L2 part. The encapsulation uses
> the encap_l3 command in-order to remove the inner l2.
> For decapsulation since the inner packet is missing the L2 there is
> a need to supply it to the NIC using the decap_l3.
> 
> The tunnels are are implemented are: MPLSoGRE and MPLSoUDP
> while the decap can be used for all L3 tunnels.
> 
> This series is based on add generic L2/L3 tunnel encapsulation actions [1]
> 
> [1] https://mails.dpdk.org/archives/dev/2018-September/111781.html
> 
> v2:
>  * rebase on tip.
> 
> 
> Ori Kam (3):
>   app/testpmd: add MPLSoUDP encapsulation
>   app/testpmd: add MPLSoGRE encapsulation
>   app/testpmd: add decap l3 command

Reminder of this patchset, any reviews welcome.

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

end of thread, other threads:[~2018-10-09 16:49 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-29 20:07 [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ori Kam
2018-09-29 20:07 ` [dpdk-dev] [PATCH 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
2018-09-29 20:07 ` [dpdk-dev] [PATCH 2/3] app/testpmd: add MPLSoGRE encapsulation Ori Kam
2018-09-29 20:07 ` [dpdk-dev] [PATCH 3/3] app/testpmd: add decap l3 command Ori Kam
2018-10-05 13:35 ` [dpdk-dev] [PATCH 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit
2018-10-05 14:00   ` Ori Kam
2018-10-07 14:41 ` [dpdk-dev] [PATCH v2 " Ori Kam
2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 1/3] app/testpmd: add MPLSoUDP encapsulation Ori Kam
2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: add MPLSoGRE encapsulation Ori Kam
2018-10-07 14:41   ` [dpdk-dev] [PATCH v2 3/3] app/testpmd: add decap l3 command Ori Kam
2018-10-09 16:48   ` [dpdk-dev] [PATCH v2 0/3] app/testpmd: add l3 encap/decap cmd Ferruh Yigit

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).