DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/3] Support UDP/IPv4 GSO
@ 2018-05-29  7:41 Jiayu Hu
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-05-29  7:41 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Jiayu Hu

With the support of UDP Fragmentation Offload (UFO) and TCP Segmentation
Offload (TSO) in virtio, VMs can exchange large UDP and TCP packets
exceeding MTU between each other, which can greatly reduce per-packet
processing overheads.

When the destination of the large TCP and UDP packets is crossing
machines, the host application needs to call two different libraries,
GSO and IP fragmentation, to split the large packets respectively.
However,the GSO and IP fragmentation library have quite different APIs,
which greatly complicates the host application implementation.

To simplify application development, we propose to support UDP/IPv4
fragmentation in the GSO library. With supporting UDP GSO, host
applicationss can use the unified APIs to split large UDP and TCP packets.

This patchset is to support UDP/IPv4 GSO. The first patch is to provide
UDP GSO function, the second patch is to enable UDP/IPv4 GSO in the
testpmd checksum forwarding engine, and the last patch is to update the
programmer guide.

Jiayu Hu (3):
  gso: support UDP/IPv4 fragmentation
  app/testpmd: enable UDP GSO in the checksum forwarding engine
  gso: add UDP/IPv4 GSO to the programmer guide

 app/test-pmd/cmdline.c                             |  5 +-
 app/test-pmd/csumonly.c                            |  2 +
 app/test-pmd/testpmd.c                             |  2 +-
 .../generic_segmentation_offload_lib.rst           |  6 ++
 lib/librte_gso/Makefile                            |  1 +
 lib/librte_gso/gso_common.h                        |  3 +
 lib/librte_gso/gso_udp4.c                          | 81 ++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h                          | 42 +++++++++++
 lib/librte_gso/rte_gso.c                           | 24 +++++--
 lib/librte_gso/rte_gso.h                           |  6 +-
 10 files changed, 163 insertions(+), 9 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

-- 
2.7.4

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

* [dpdk-dev] [PATCH 1/3] gso: support UDP/IPv4 fragmentation
  2018-05-29  7:41 [dpdk-dev] [PATCH 0/3] Support UDP/IPv4 GSO Jiayu Hu
@ 2018-05-29  7:41 ` Jiayu Hu
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine Jiayu Hu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-05-29  7:41 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Jiayu Hu

This patch adds GSO support for UDP/IPv4 packets. Supported packets
may include a single VLAN tag. UDP/IPv4 GSO doesn't check if input
packets have correct checksums, and doesn't update checksums for
output packets (the responsibility for this lies with the application).
Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.

UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
MBUF, to organize an output packet. The direct MBUF stores the packet
header, while the indirect mbuf simply points to a location within the
original packet's payload. Consequently, use of UDP GSO requires
multi-segment MBUF support in the TX functions of the NIC driver.

If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
result, when all of its GSOed segments are freed, the packet is freed
automatically.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 lib/librte_gso/Makefile     |  1 +
 lib/librte_gso/gso_common.h |  3 ++
 lib/librte_gso/gso_udp4.c   | 81 +++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
 lib/librte_gso/rte_gso.c    | 24 +++++++++++---
 lib/librte_gso/rte_gso.h    |  6 +++-
 6 files changed, 151 insertions(+), 6 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile
index 3648ec0..1fac53a 100644
--- a/lib/librte_gso/Makefile
+++ b/lib/librte_gso/Makefile
@@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
+SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
 
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h
diff --git a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h
index 5ca5974..6cd764f 100644
--- a/lib/librte_gso/gso_common.h
+++ b/lib/librte_gso/gso_common.h
@@ -31,6 +31,9 @@
 		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 | \
 		 PKT_TX_TUNNEL_GRE))
 
+#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4)) == \
+		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
+
 /**
  * Internal function which updates the UDP header of a packet, following
  * segmentation. This is required to update the header's datagram length field.
diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c
new file mode 100644
index 0000000..324cc88
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include "gso_common.h"
+#include "gso_udp4.h"
+
+#define IPV4_HDR_MF_BIT (1U << 13)
+
+static inline void
+update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
+		uint16_t nb_segs)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t frag_offset = 0, is_mf;
+	uint16_t l3_offset = pkt->l2_len, length;
+	uint16_t tail_idx = nb_segs - 1, i;
+
+	/*
+	 * Update IP header fields for output segments. Specifically,
+	 * keep the same IP id, update fragment offset and total
+	 * length.
+	 */
+	for (i = 0; i < nb_segs; i++) {
+		ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(segs[i],
+					char *) + l3_offset);
+		length = segs[i]->pkt_len - l3_offset;
+		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
+
+		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
+		ipv4_hdr->fragment_offset = rte_cpu_to_be_16(frag_offset |
+				is_mf);
+		frag_offset += (length >> 3);
+	}
+}
+
+int
+gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t pyld_unit_size, hdr_offset;
+	uint16_t frag_off;
+	int ret;
+
+	/* Don't process the fragmented packet */
+	ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) +
+			pkt->l2_len);
+	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
+	if (unlikely(IS_FRAGMENTED(frag_off))) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	/*
+	 * UDP fragmentation is the same as IP fragmentation.
+	 * Except the first one, other output packets just have l2
+	 * and l3 headers.
+	 */
+	hdr_offset = pkt->l2_len + pkt->l3_len;
+
+	/* Don't process the packet without data. */
+	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	pyld_unit_size = gso_size - hdr_offset;
+
+	/* Segment the payload */
+	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
+			indirect_pool, pkts_out, nb_pkts_out);
+	if (ret > 1)
+		update_ipv4_udp_headers(pkt, pkts_out, ret);
+
+	return ret;
+}
diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h
new file mode 100644
index 0000000..b2a2908
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _GSO_UDP4_H_
+#define _GSO_UDP4_H_
+
+#include <stdint.h>
+#include <rte_mbuf.h>
+
+/**
+ * Segment an UDP/IPv4 packet. This function doesn't check if the input
+ * packet has correct checksums, and doesn't update checksums for output
+ * GSO segments. Furthermore, it doesn't process IP fragment packets.
+ *
+ * @param pkt
+ *  The packet mbuf to segment.
+ * @param gso_size
+ *  The max length of a GSO segment, measured in bytes.
+ * @param direct_pool
+ *  MBUF pool used for allocating direct buffers for output segments.
+ * @param indirect_pool
+ *  MBUF pool used for allocating indirect buffers for output segments.
+ * @param pkts_out
+ *  Pointer array used to store the MBUF addresses of output GSO
+ *  segments, when the function succeeds. If the memory space in
+ *  pkts_out is insufficient, it fails and returns -EINVAL.
+ * @param nb_pkts_out
+ *  The max number of items that 'pkts_out' can keep.
+ *
+ * @return
+ *   - The number of GSO segments filled in pkts_out on success.
+ *   - Return -ENOMEM if run out of memory in MBUF pools.
+ *   - Return -EINVAL for invalid parameters.
+ */
+int gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out);
+#endif
diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c
index a44e3d4..751b5b6 100644
--- a/lib/librte_gso/rte_gso.c
+++ b/lib/librte_gso/rte_gso.c
@@ -11,6 +11,17 @@
 #include "gso_common.h"
 #include "gso_tcp4.h"
 #include "gso_tunnel_tcp4.h"
+#include "gso_udp4.h"
+
+#define ILLEGAL_UDP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
+	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
+
+#define ILLEGAL_TCP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
+		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
+		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
+		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
 
 int
 rte_gso_segment(struct rte_mbuf *pkt,
@@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
 
 	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
 			nb_pkts_out < 1 ||
-			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
-			((gso_ctx->gso_types & (DEV_TX_OFFLOAD_TCP_TSO |
-			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
+			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
+			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
 		return -EINVAL;
 
 	if (gso_ctx->gso_size >= pkt->pkt_len) {
-		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
+		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
 		pkts_out[0] = pkt;
 		return 1;
 	}
@@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
 		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
 				direct_pool, indirect_pool,
 				pkts_out, nb_pkts_out);
+	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
+			(gso_ctx->gso_types & DEV_TX_OFFLOAD_UDP_TSO)) {
+		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
+		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
+				indirect_pool, pkts_out, nb_pkts_out);
 	} else {
 		/* unsupported packet, skip */
 		pkts_out[0] = pkt;
diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h
index f4abd61..a626a11 100644
--- a/lib/librte_gso/rte_gso.h
+++ b/lib/librte_gso/rte_gso.h
@@ -17,10 +17,14 @@ extern "C" {
 #include <stdint.h>
 #include <rte_mbuf.h>
 
-/* Minimum GSO segment size. */
+/* Minimum GSO segment size for TCP based packets. */
 #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
 		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)
 
+/* Minimum GSO segment size for UDP based packets. */
+#define RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
+		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
+
 /* GSO flags for rte_gso_ctx. */
 #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)
 /**< Use fixed IP ids for output GSO segments. Setting
-- 
2.7.4

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

* [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine
  2018-05-29  7:41 [dpdk-dev] [PATCH 0/3] Support UDP/IPv4 GSO Jiayu Hu
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
@ 2018-05-29  7:41 ` Jiayu Hu
  2018-06-14 14:44   ` Iremonger, Bernard
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide Jiayu Hu
  2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
  3 siblings, 1 reply; 27+ messages in thread
From: Jiayu Hu @ 2018-05-29  7:41 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Jiayu Hu

This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4
packets transmitted over a GSO-enabled port will undergo segmentation.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 app/test-pmd/cmdline.c  | 5 +++--
 app/test-pmd/csumonly.c | 2 ++
 app/test-pmd/testpmd.c  | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8..4239e91 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -4792,8 +4792,9 @@ cmd_gso_show_parsed(void *parsed_result,
 		if (gso_ports[res->cmd_pid].enable) {
 			printf("Max GSO'd packet size: %uB\n"
 					"Supported GSO types: TCP/IPv4, "
-					"VxLAN with inner TCP/IPv4 packet, "
-					"GRE with inner TCP/IPv4  packet\n",
+					"UDP/IPv4, VxLAN with inner "
+					"TCP/IPv4 packet, GRE with inner "
+					"TCP/IPv4 packet\n",
 					gso_max_segment_size);
 		} else
 			printf("GSO is not enabled on Port %u\n", res->cmd_pid);
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index 0bb88cf..4948292 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -411,6 +411,8 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
 						info->ethertype);
 			}
 		}
+		if (info->gso_enable)
+			ol_flags |= PKT_TX_UDP_SEG;
 	} else if (info->l4_proto == IPPROTO_TCP) {
 		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
 		tcp_hdr->cksum = 0;
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 35cf266..b5766ff 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -777,7 +777,7 @@ init_config(void)
 	init_port_config();
 
 	gso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-		DEV_TX_OFFLOAD_GRE_TNL_TSO;
+		DEV_TX_OFFLOAD_GRE_TNL_TSO | DEV_TX_OFFLOAD_UDP_TSO;
 	/*
 	 * Records which Mbuf pool to use by each logical core, if needed.
 	 */
-- 
2.7.4

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

* [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide
  2018-05-29  7:41 [dpdk-dev] [PATCH 0/3] Support UDP/IPv4 GSO Jiayu Hu
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine Jiayu Hu
@ 2018-05-29  7:41 ` Jiayu Hu
  2018-06-27  1:59   ` Zhang, Yuwei1
  2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
  3 siblings, 1 reply; 27+ messages in thread
From: Jiayu Hu @ 2018-05-29  7:41 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, Jiayu Hu

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 doc/guides/prog_guide/generic_segmentation_offload_lib.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
index 9959f0d..cf700c5 100644
--- a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
+++ b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
@@ -43,6 +43,7 @@ Limitations
 #. Currently, the GSO library supports the following IPv4 packet types:
 
  - TCP
+ - UDP
  - VxLAN
  - GRE
 
@@ -146,6 +147,11 @@ TCP/IPv4 GSO
 TCP/IPv4 GSO supports segmentation of suitably large TCP/IPv4 packets, which
 may also contain an optional VLAN tag.
 
+UDP/IPv4 GSO
+~~~~~~~~~~~~
+UDP/IPv4 GSO supports segmentation of suitably large UDP/IPv4 packets, which
+may also contain an optional VLAN tag.
+
 VxLAN GSO
 ~~~~~~~~~
 VxLAN packets GSO supports segmentation of suitably large VxLAN packets,
-- 
2.7.4

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

* Re: [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine Jiayu Hu
@ 2018-06-14 14:44   ` Iremonger, Bernard
  2018-06-16  9:14     ` Hu, Jiayu
  0 siblings, 1 reply; 27+ messages in thread
From: Iremonger, Bernard @ 2018-06-14 14:44 UTC (permalink / raw)
  To: Hu, Jiayu, dev; +Cc: Ananyev, Konstantin, Hu, Jiayu

Hi Jiayu,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> Sent: Tuesday, May 29, 2018 8:41 AM
> To: dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Hu, Jiayu
> <jiayu.hu@intel.com>
> Subject: [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the
> checksum forwarding engine
> 
> This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4 packets
> transmitted over a GSO-enabled port will undergo segmentation.
> 
> Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> ---
>  app/test-pmd/cmdline.c  | 5 +++--
>  app/test-pmd/csumonly.c | 2 ++
>  app/test-pmd/testpmd.c  | 2 +-
>  3 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> 27e2aa8..4239e91 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -4792,8 +4792,9 @@ cmd_gso_show_parsed(void *parsed_result,
>  		if (gso_ports[res->cmd_pid].enable) {
>  			printf("Max GSO'd packet size: %uB\n"
>  					"Supported GSO types: TCP/IPv4, "
> -					"VxLAN with inner TCP/IPv4 packet, "
> -					"GRE with inner TCP/IPv4  packet\n",
> +					"UDP/IPv4, VxLAN with inner "
> +					"TCP/IPv4 packet, GRE with inner "
> +					"TCP/IPv4 packet\n",

This change is giving 3 checkpatch.pl warnings and should be refactored


>  					gso_max_segment_size);
>  		} else
>  			printf("GSO is not enabled on Port %u\n", res-
> >cmd_pid); diff --git a/app/test-pmd/csumonly.c b/app/test-
> pmd/csumonly.c index 0bb88cf..4948292 100644
> --- a/app/test-pmd/csumonly.c
> +++ b/app/test-pmd/csumonly.c
> @@ -411,6 +411,8 @@ process_inner_cksums(void *l3_hdr, const struct
> testpmd_offload_info *info,
>  						info->ethertype);
>  			}
>  		}
> +		if (info->gso_enable)
> +			ol_flags |= PKT_TX_UDP_SEG;
>  	} else if (info->l4_proto == IPPROTO_TCP) {
>  		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
>  		tcp_hdr->cksum = 0;
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index
> 35cf266..b5766ff 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -777,7 +777,7 @@ init_config(void)
>  	init_port_config();
> 
>  	gso_types = DEV_TX_OFFLOAD_TCP_TSO |
> DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
> -		DEV_TX_OFFLOAD_GRE_TNL_TSO;
> +		DEV_TX_OFFLOAD_GRE_TNL_TSO |
> DEV_TX_OFFLOAD_UDP_TSO;
>  	/*
>  	 * Records which Mbuf pool to use by each logical core, if needed.
>  	 */
> --
> 2.7.4

./devtools/check-git-log.sh -1
Headline too long:
        app/testpmd: enable UDP GSO in the checksum forwarding engine

Should the dpdk/doc/guides/testpmd_ap_ug/testpmd_funcs.rst  file be updated?

Regards,

Bernard

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

* Re: [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine
  2018-06-14 14:44   ` Iremonger, Bernard
@ 2018-06-16  9:14     ` Hu, Jiayu
  0 siblings, 0 replies; 27+ messages in thread
From: Hu, Jiayu @ 2018-06-16  9:14 UTC (permalink / raw)
  To: Iremonger, Bernard, dev; +Cc: Ananyev, Konstantin

Hi Bernard,

> -----Original Message-----
> From: Iremonger, Bernard
> Sent: Thursday, June 14, 2018 10:44 PM
> To: Hu, Jiayu <jiayu.hu@intel.com>; dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Hu, Jiayu
> <jiayu.hu@intel.com>
> Subject: RE: [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the
> checksum forwarding engine
> 
> Hi Jiayu,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> > Sent: Tuesday, May 29, 2018 8:41 AM
> > To: dev@dpdk.org
> > Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Hu, Jiayu
> > <jiayu.hu@intel.com>
> > Subject: [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the
> > checksum forwarding engine
> >
> > This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4
> packets
> > transmitted over a GSO-enabled port will undergo segmentation.
> >
> > Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> > ---
> >  app/test-pmd/cmdline.c  | 5 +++--
> >  app/test-pmd/csumonly.c | 2 ++
> >  app/test-pmd/testpmd.c  | 2 +-
> >  3 files changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> > 27e2aa8..4239e91 100644
> > --- a/app/test-pmd/cmdline.c
> > +++ b/app/test-pmd/cmdline.c
> > @@ -4792,8 +4792,9 @@ cmd_gso_show_parsed(void *parsed_result,
> >  		if (gso_ports[res->cmd_pid].enable) {
> >  			printf("Max GSO'd packet size: %uB\n"
> >  					"Supported GSO types: TCP/IPv4, "
> > -					"VxLAN with inner TCP/IPv4 packet,
> "
> > -					"GRE with inner TCP/IPv4
> packet\n",
> > +					"UDP/IPv4, VxLAN with inner "
> > +					"TCP/IPv4 packet, GRE with inner "
> > +					"TCP/IPv4 packet\n",
> 
> This change is giving 3 checkpatch.pl warnings and should be refactored

The file test-pmd/cmdline.c uses the above coding style to split long strings,
so I think I need to keep this style. But when I use it, there are always some warnings.

> 
> 
> >  					gso_max_segment_size);
> >  		} else
> >  			printf("GSO is not enabled on Port %u\n", res-
> > >cmd_pid); diff --git a/app/test-pmd/csumonly.c b/app/test-
> > pmd/csumonly.c index 0bb88cf..4948292 100644
> > --- a/app/test-pmd/csumonly.c
> > +++ b/app/test-pmd/csumonly.c
> > @@ -411,6 +411,8 @@ process_inner_cksums(void *l3_hdr, const struct
> > testpmd_offload_info *info,
> >  						info->ethertype);
> >  			}
> >  		}
> > +		if (info->gso_enable)
> > +			ol_flags |= PKT_TX_UDP_SEG;
> >  	} else if (info->l4_proto == IPPROTO_TCP) {
> >  		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
> >  		tcp_hdr->cksum = 0;
> > diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index
> > 35cf266..b5766ff 100644
> > --- a/app/test-pmd/testpmd.c
> > +++ b/app/test-pmd/testpmd.c
> > @@ -777,7 +777,7 @@ init_config(void)
> >  	init_port_config();
> >
> >  	gso_types = DEV_TX_OFFLOAD_TCP_TSO |
> > DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
> > -		DEV_TX_OFFLOAD_GRE_TNL_TSO;
> > +		DEV_TX_OFFLOAD_GRE_TNL_TSO |
> > DEV_TX_OFFLOAD_UDP_TSO;
> >  	/*
> >  	 * Records which Mbuf pool to use by each logical core, if needed.
> >  	 */
> > --
> > 2.7.4
> 
> ./devtools/check-git-log.sh -1
> Headline too long:
>         app/testpmd: enable UDP GSO in the checksum forwarding engine

Will change it in the next version.

> 
> Should the dpdk/doc/guides/testpmd_ap_ug/testpmd_funcs.rst  file be
> updated?

I will add some descriptions about UDP/IPv4 GSO usage guide in it.

Thanks,
Jiayu
> 
> Regards,
> 
> Bernard
> 

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

* [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO
  2018-05-29  7:41 [dpdk-dev] [PATCH 0/3] Support UDP/IPv4 GSO Jiayu Hu
                   ` (2 preceding siblings ...)
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide Jiayu Hu
@ 2018-06-17  3:13 ` Jiayu Hu
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
                     ` (3 more replies)
  3 siblings, 4 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-06-17  3:13 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, yuwei1.zhang, bernard.iremonger, Jiayu Hu

With the support of UDP Fragmentation Offload (UFO) and TCP Segmentation
Offload (TSO) in virtio, VMs can exchange large UDP and TCP packets
exceeding MTU between each other, which can greatly reduce per-packet
processing overheads.

When the destination of the large TCP and UDP packets is crossing
machines, the host application needs to call two different libraries,
GSO and IP fragmentation, to split the large packets respectively.
However,the GSO and IP fragmentation library have quite different APIs,
which greatly complicates the host application implementation.

To simplify application development, we propose to support UDP/IPv4
fragmentation in the GSO library. With supporting UDP GSO, host
applicationss can use the unified APIs to split large UDP and TCP packets.

This patchset is to support UDP/IPv4 GSO. The first patch is to provide
UDP GSO function, the second patch is to enable UDP/IPv4 GSO in the
testpmd checksum forwarding engine, and the last patch is to update the
programmer guide and testpmd user guide.

Change log
==========
V2:
- fix fragment offset calculation bug.
- add UDP GSO description in testpmd user guide.
- shorten the second patch name.

Jiayu Hu (3):
  gso: support UDP/IPv4 fragmentation
  app/testpmd: enable UDP GSO in csum engine
  gso: update documents for UDP/IPv4 GSO

 app/test-pmd/cmdline.c                             |  5 +-
 app/test-pmd/csumonly.c                            |  2 +
 app/test-pmd/testpmd.c                             |  2 +-
 .../generic_segmentation_offload_lib.rst           |  6 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst        |  6 ++
 lib/librte_gso/Makefile                            |  1 +
 lib/librte_gso/gso_common.h                        |  3 +
 lib/librte_gso/gso_udp4.c                          | 81 ++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h                          | 42 +++++++++++
 lib/librte_gso/rte_gso.c                           | 24 +++++--
 lib/librte_gso/rte_gso.h                           |  6 +-
 11 files changed, 169 insertions(+), 9 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

-- 
2.7.4

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

* [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
@ 2018-06-17  3:13   ` Jiayu Hu
  2018-06-21  8:24     ` Wang, Xiao W
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 27+ messages in thread
From: Jiayu Hu @ 2018-06-17  3:13 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, yuwei1.zhang, bernard.iremonger, Jiayu Hu

This patch adds GSO support for UDP/IPv4 packets. Supported packets
may include a single VLAN tag. UDP/IPv4 GSO doesn't check if input
packets have correct checksums, and doesn't update checksums for
output packets (the responsibility for this lies with the application).
Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.

UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
MBUF, to organize an output packet. The direct MBUF stores the packet
header, while the indirect mbuf simply points to a location within the
original packet's payload. Consequently, use of UDP GSO requires
multi-segment MBUF support in the TX functions of the NIC driver.

If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
result, when all of its GSOed segments are freed, the packet is freed
automatically.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 lib/librte_gso/Makefile     |  1 +
 lib/librte_gso/gso_common.h |  3 ++
 lib/librte_gso/gso_udp4.c   | 81 +++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
 lib/librte_gso/rte_gso.c    | 24 +++++++++++---
 lib/librte_gso/rte_gso.h    |  6 +++-
 6 files changed, 151 insertions(+), 6 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile
index 3648ec0..1fac53a 100644
--- a/lib/librte_gso/Makefile
+++ b/lib/librte_gso/Makefile
@@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
+SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
 
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h
diff --git a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h
index 5ca5974..6cd764f 100644
--- a/lib/librte_gso/gso_common.h
+++ b/lib/librte_gso/gso_common.h
@@ -31,6 +31,9 @@
 		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 | \
 		 PKT_TX_TUNNEL_GRE))
 
+#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4)) == \
+		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
+
 /**
  * Internal function which updates the UDP header of a packet, following
  * segmentation. This is required to update the header's datagram length field.
diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c
new file mode 100644
index 0000000..a3db329
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include "gso_common.h"
+#include "gso_udp4.h"
+
+#define IPV4_HDR_MF_BIT (1U << 13)
+
+static inline void
+update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
+		uint16_t nb_segs)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t frag_offset = 0, is_mf;
+	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
+	uint16_t tail_idx = nb_segs - 1, length, i;
+
+	/*
+	 * Update IP header fields for output segments. Specifically,
+	 * keep the same IP id, update fragment offset and total
+	 * length.
+	 */
+	for (i = 0; i < nb_segs; i++) {
+		ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(segs[i],
+					char *) + l2_hdrlen);
+		length = segs[i]->pkt_len - l2_hdrlen;
+		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
+
+		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
+		ipv4_hdr->fragment_offset =
+			rte_cpu_to_be_16(frag_offset | is_mf);
+		frag_offset += ((length - l3_hdrlen) >> 3);
+	}
+}
+
+int
+gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t pyld_unit_size, hdr_offset;
+	uint16_t frag_off;
+	int ret;
+
+	/* Don't process the fragmented packet */
+	ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) +
+			pkt->l2_len);
+	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
+	if (unlikely(IS_FRAGMENTED(frag_off))) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	/*
+	 * UDP fragmentation is the same as IP fragmentation.
+	 * Except the first one, other output packets just have l2
+	 * and l3 headers.
+	 */
+	hdr_offset = pkt->l2_len + pkt->l3_len;
+
+	/* Don't process the packet without data. */
+	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	pyld_unit_size = gso_size - hdr_offset;
+
+	/* Segment the payload */
+	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
+			indirect_pool, pkts_out, nb_pkts_out);
+	if (ret > 1)
+		update_ipv4_udp_headers(pkt, pkts_out, ret);
+
+	return ret;
+}
diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h
new file mode 100644
index 0000000..b2a2908
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _GSO_UDP4_H_
+#define _GSO_UDP4_H_
+
+#include <stdint.h>
+#include <rte_mbuf.h>
+
+/**
+ * Segment an UDP/IPv4 packet. This function doesn't check if the input
+ * packet has correct checksums, and doesn't update checksums for output
+ * GSO segments. Furthermore, it doesn't process IP fragment packets.
+ *
+ * @param pkt
+ *  The packet mbuf to segment.
+ * @param gso_size
+ *  The max length of a GSO segment, measured in bytes.
+ * @param direct_pool
+ *  MBUF pool used for allocating direct buffers for output segments.
+ * @param indirect_pool
+ *  MBUF pool used for allocating indirect buffers for output segments.
+ * @param pkts_out
+ *  Pointer array used to store the MBUF addresses of output GSO
+ *  segments, when the function succeeds. If the memory space in
+ *  pkts_out is insufficient, it fails and returns -EINVAL.
+ * @param nb_pkts_out
+ *  The max number of items that 'pkts_out' can keep.
+ *
+ * @return
+ *   - The number of GSO segments filled in pkts_out on success.
+ *   - Return -ENOMEM if run out of memory in MBUF pools.
+ *   - Return -EINVAL for invalid parameters.
+ */
+int gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out);
+#endif
diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c
index a44e3d4..751b5b6 100644
--- a/lib/librte_gso/rte_gso.c
+++ b/lib/librte_gso/rte_gso.c
@@ -11,6 +11,17 @@
 #include "gso_common.h"
 #include "gso_tcp4.h"
 #include "gso_tunnel_tcp4.h"
+#include "gso_udp4.h"
+
+#define ILLEGAL_UDP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
+	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
+
+#define ILLEGAL_TCP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
+		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
+		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
+		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
 
 int
 rte_gso_segment(struct rte_mbuf *pkt,
@@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
 
 	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
 			nb_pkts_out < 1 ||
-			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
-			((gso_ctx->gso_types & (DEV_TX_OFFLOAD_TCP_TSO |
-			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
+			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
+			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
 		return -EINVAL;
 
 	if (gso_ctx->gso_size >= pkt->pkt_len) {
-		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
+		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
 		pkts_out[0] = pkt;
 		return 1;
 	}
@@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
 		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
 				direct_pool, indirect_pool,
 				pkts_out, nb_pkts_out);
+	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
+			(gso_ctx->gso_types & DEV_TX_OFFLOAD_UDP_TSO)) {
+		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
+		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
+				indirect_pool, pkts_out, nb_pkts_out);
 	} else {
 		/* unsupported packet, skip */
 		pkts_out[0] = pkt;
diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h
index f4abd61..a626a11 100644
--- a/lib/librte_gso/rte_gso.h
+++ b/lib/librte_gso/rte_gso.h
@@ -17,10 +17,14 @@ extern "C" {
 #include <stdint.h>
 #include <rte_mbuf.h>
 
-/* Minimum GSO segment size. */
+/* Minimum GSO segment size for TCP based packets. */
 #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
 		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)
 
+/* Minimum GSO segment size for UDP based packets. */
+#define RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
+		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
+
 /* GSO flags for rte_gso_ctx. */
 #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)
 /**< Use fixed IP ids for output GSO segments. Setting
-- 
2.7.4

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

* [dpdk-dev] [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine
  2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
@ 2018-06-17  3:13   ` Jiayu Hu
  2018-06-26  9:46     ` Iremonger, Bernard
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
  3 siblings, 1 reply; 27+ messages in thread
From: Jiayu Hu @ 2018-06-17  3:13 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, yuwei1.zhang, bernard.iremonger, Jiayu Hu

This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4
packets transmitted over a GSO-enabled port will undergo segmentation.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 app/test-pmd/cmdline.c  | 5 +++--
 app/test-pmd/csumonly.c | 2 ++
 app/test-pmd/testpmd.c  | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8..4239e91 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -4792,8 +4792,9 @@ cmd_gso_show_parsed(void *parsed_result,
 		if (gso_ports[res->cmd_pid].enable) {
 			printf("Max GSO'd packet size: %uB\n"
 					"Supported GSO types: TCP/IPv4, "
-					"VxLAN with inner TCP/IPv4 packet, "
-					"GRE with inner TCP/IPv4  packet\n",
+					"UDP/IPv4, VxLAN with inner "
+					"TCP/IPv4 packet, GRE with inner "
+					"TCP/IPv4 packet\n",
 					gso_max_segment_size);
 		} else
 			printf("GSO is not enabled on Port %u\n", res->cmd_pid);
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index 0bb88cf..4948292 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -411,6 +411,8 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
 						info->ethertype);
 			}
 		}
+		if (info->gso_enable)
+			ol_flags |= PKT_TX_UDP_SEG;
 	} else if (info->l4_proto == IPPROTO_TCP) {
 		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
 		tcp_hdr->cksum = 0;
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 35cf266..b5766ff 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -777,7 +777,7 @@ init_config(void)
 	init_port_config();
 
 	gso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-		DEV_TX_OFFLOAD_GRE_TNL_TSO;
+		DEV_TX_OFFLOAD_GRE_TNL_TSO | DEV_TX_OFFLOAD_UDP_TSO;
 	/*
 	 * Records which Mbuf pool to use by each logical core, if needed.
 	 */
-- 
2.7.4

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

* [dpdk-dev] [PATCH v2 3/3] gso: update documents for UDP/IPv4 GSO
  2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
@ 2018-06-17  3:13   ` Jiayu Hu
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
  3 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-06-17  3:13 UTC (permalink / raw)
  To: dev; +Cc: konstantin.ananyev, yuwei1.zhang, bernard.iremonger, Jiayu Hu

This patch updates the programmer guide and testpmd user guide for
UDP/IPv4 GSO.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 doc/guides/prog_guide/generic_segmentation_offload_lib.rst | 6 ++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst                | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
index 9959f0d..cf700c5 100644
--- a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
+++ b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
@@ -43,6 +43,7 @@ Limitations
 #. Currently, the GSO library supports the following IPv4 packet types:
 
  - TCP
+ - UDP
  - VxLAN
  - GRE
 
@@ -146,6 +147,11 @@ TCP/IPv4 GSO
 TCP/IPv4 GSO supports segmentation of suitably large TCP/IPv4 packets, which
 may also contain an optional VLAN tag.
 
+UDP/IPv4 GSO
+~~~~~~~~~~~~
+UDP/IPv4 GSO supports segmentation of suitably large UDP/IPv4 packets, which
+may also contain an optional VLAN tag.
+
 VxLAN GSO
 ~~~~~~~~~
 VxLAN packets GSO supports segmentation of suitably large VxLAN packets,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50..1a9dcd8 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1059,6 +1059,12 @@ By default, GSO is disabled for all ports.
 
    testpmd> csum set tcp hw <port_id>
 
+   UDP GSO is the same as IP fragmentation, which treats the UDP header
+   as the payload and does not modify it during segmentation. That is,
+   after UDP GSO, only the first output fragment has the original UDP
+   header. Therefore, users just need to enable HW IPv4 checksum
+   calculation for GSO-enabled ports, when input packets are UDP/IPv4.
+
 set gso segsz
 ~~~~~~~~~~~~~
 
-- 
2.7.4

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

* Re: [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
@ 2018-06-21  8:24     ` Wang, Xiao W
  2018-06-21  8:26       ` Hu, Jiayu
  0 siblings, 1 reply; 27+ messages in thread
From: Wang, Xiao W @ 2018-06-21  8:24 UTC (permalink / raw)
  To: Hu, Jiayu, dev
  Cc: Ananyev, Konstantin, Zhang, Yuwei1, Iremonger, Bernard, Hu, Jiayu

Hi,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> Sent: Sunday, June 17, 2018 11:13 AM
> To: dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> <yuwei1.zhang@intel.com>; Iremonger, Bernard
> <bernard.iremonger@intel.com>; Hu, Jiayu <jiayu.hu@intel.com>
> Subject: [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation
> 
> This patch adds GSO support for UDP/IPv4 packets. Supported packets
> may include a single VLAN tag. UDP/IPv4 GSO doesn't check if input
> packets have correct checksums, and doesn't update checksums for
> output packets (the responsibility for this lies with the application).
> Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.
> 
> UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
> MBUF, to organize an output packet. The direct MBUF stores the packet
> header, while the indirect mbuf simply points to a location within the
> original packet's payload. Consequently, use of UDP GSO requires
> multi-segment MBUF support in the TX functions of the NIC driver.
> 
> If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
> result, when all of its GSOed segments are freed, the packet is freed
> automatically.
> 
> Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> ---
>  lib/librte_gso/Makefile     |  1 +
>  lib/librte_gso/gso_common.h |  3 ++
>  lib/librte_gso/gso_udp4.c   | 81
> +++++++++++++++++++++++++++++++++++++++++++++
>  lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
>  lib/librte_gso/rte_gso.c    | 24 +++++++++++---
>  lib/librte_gso/rte_gso.h    |  6 +++-
>  6 files changed, 151 insertions(+), 6 deletions(-)
>  create mode 100644 lib/librte_gso/gso_udp4.c
>  create mode 100644 lib/librte_gso/gso_udp4.h
> 
> diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile
> index 3648ec0..1fac53a 100644
> --- a/lib/librte_gso/Makefile
> +++ b/lib/librte_gso/Makefile
> @@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
>  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
>  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
>  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
> +SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
> 

meson should be updated accordingly.

>  # install this header file
>  SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h
> diff --git a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h
> index 5ca5974..6cd764f 100644
> --- a/lib/librte_gso/gso_common.h
> +++ b/lib/librte_gso/gso_common.h
> @@ -31,6 +31,9 @@
>  		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 | \
>  		 PKT_TX_TUNNEL_GRE))
> 
> +#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4)) == \
> +		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
> +
>  /**
>   * Internal function which updates the UDP header of a packet, following
>   * segmentation. This is required to update the header's datagram length field.
> diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c
> new file mode 100644
> index 0000000..a3db329
> --- /dev/null
> +++ b/lib/librte_gso/gso_udp4.c
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation
> + */
> +
> +#include "gso_common.h"
> +#include "gso_udp4.h"
> +
> +#define IPV4_HDR_MF_BIT (1U << 13)
> +
> +static inline void
> +update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
> +		uint16_t nb_segs)
> +{
> +	struct ipv4_hdr *ipv4_hdr;
> +	uint16_t frag_offset = 0, is_mf;
> +	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
> +	uint16_t tail_idx = nb_segs - 1, length, i;
> +
> +	/*
> +	 * Update IP header fields for output segments. Specifically,
> +	 * keep the same IP id, update fragment offset and total
> +	 * length.
> +	 */
> +	for (i = 0; i < nb_segs; i++) {
> +		ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(segs[i],
> +					char *) + l2_hdrlen);

You could use rte_pktmbuf_mtod_offset to simplify the code.

> +		length = segs[i]->pkt_len - l2_hdrlen;
> +		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
> +
> +		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
> +		ipv4_hdr->fragment_offset =
> +			rte_cpu_to_be_16(frag_offset | is_mf);
> +		frag_offset += ((length - l3_hdrlen) >> 3);
> +	}
> +}
> +
> +int
> +gso_udp4_segment(struct rte_mbuf *pkt,
> +		uint16_t gso_size,
> +		struct rte_mempool *direct_pool,
> +		struct rte_mempool *indirect_pool,
> +		struct rte_mbuf **pkts_out,
> +		uint16_t nb_pkts_out)
> +{
> +	struct ipv4_hdr *ipv4_hdr;
> +	uint16_t pyld_unit_size, hdr_offset;
> +	uint16_t frag_off;
> +	int ret;
> +
> +	/* Don't process the fragmented packet */
> +	ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) +
> +			pkt->l2_len);

Ditto.

BRs,
Xiao

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

* Re: [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-21  8:24     ` Wang, Xiao W
@ 2018-06-21  8:26       ` Hu, Jiayu
  0 siblings, 0 replies; 27+ messages in thread
From: Hu, Jiayu @ 2018-06-21  8:26 UTC (permalink / raw)
  To: Wang, Xiao W, dev; +Cc: Ananyev, Konstantin, Zhang, Yuwei1, Iremonger, Bernard

Hi Xiao,

> -----Original Message-----
> From: Wang, Xiao W
> Sent: Thursday, June 21, 2018 4:25 PM
> To: Hu, Jiayu <jiayu.hu@intel.com>; dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> <yuwei1.zhang@intel.com>; Iremonger, Bernard
> <bernard.iremonger@intel.com>; Hu, Jiayu <jiayu.hu@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4
> fragmentation
> 
> Hi,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> > Sent: Sunday, June 17, 2018 11:13 AM
> > To: dev@dpdk.org
> > Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> > <yuwei1.zhang@intel.com>; Iremonger, Bernard
> > <bernard.iremonger@intel.com>; Hu, Jiayu <jiayu.hu@intel.com>
> > Subject: [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation
> >
> > This patch adds GSO support for UDP/IPv4 packets. Supported packets
> > may include a single VLAN tag. UDP/IPv4 GSO doesn't check if input
> > packets have correct checksums, and doesn't update checksums for
> > output packets (the responsibility for this lies with the application).
> > Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.
> >
> > UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
> > MBUF, to organize an output packet. The direct MBUF stores the packet
> > header, while the indirect mbuf simply points to a location within the
> > original packet's payload. Consequently, use of UDP GSO requires
> > multi-segment MBUF support in the TX functions of the NIC driver.
> >
> > If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
> > result, when all of its GSOed segments are freed, the packet is freed
> > automatically.
> >
> > Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> > ---
> >  lib/librte_gso/Makefile     |  1 +
> >  lib/librte_gso/gso_common.h |  3 ++
> >  lib/librte_gso/gso_udp4.c   | 81
> > +++++++++++++++++++++++++++++++++++++++++++++
> >  lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
> >  lib/librte_gso/rte_gso.c    | 24 +++++++++++---
> >  lib/librte_gso/rte_gso.h    |  6 +++-
> >  6 files changed, 151 insertions(+), 6 deletions(-)
> >  create mode 100644 lib/librte_gso/gso_udp4.c
> >  create mode 100644 lib/librte_gso/gso_udp4.h
> >
> > diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile
> > index 3648ec0..1fac53a 100644
> > --- a/lib/librte_gso/Makefile
> > +++ b/lib/librte_gso/Makefile
> > @@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
> > +SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
> >
> 
> meson should be updated accordingly.

Thanks a lot. Update later.
> 
> >  # install this header file
> >  SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h
> > diff --git a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h
> > index 5ca5974..6cd764f 100644
> > --- a/lib/librte_gso/gso_common.h
> > +++ b/lib/librte_gso/gso_common.h
> > @@ -31,6 +31,9 @@
> >  		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 |
> \
> >  		 PKT_TX_TUNNEL_GRE))
> >
> > +#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4))
> == \
> > +		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
> > +
> >  /**
> >   * Internal function which updates the UDP header of a packet, following
> >   * segmentation. This is required to update the header's datagram length
> field.
> > diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c
> > new file mode 100644
> > index 0000000..a3db329
> > --- /dev/null
> > +++ b/lib/librte_gso/gso_udp4.c
> > @@ -0,0 +1,81 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2018 Intel Corporation
> > + */
> > +
> > +#include "gso_common.h"
> > +#include "gso_udp4.h"
> > +
> > +#define IPV4_HDR_MF_BIT (1U << 13)
> > +
> > +static inline void
> > +update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
> > +		uint16_t nb_segs)
> > +{
> > +	struct ipv4_hdr *ipv4_hdr;
> > +	uint16_t frag_offset = 0, is_mf;
> > +	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
> > +	uint16_t tail_idx = nb_segs - 1, length, i;
> > +
> > +	/*
> > +	 * Update IP header fields for output segments. Specifically,
> > +	 * keep the same IP id, update fragment offset and total
> > +	 * length.
> > +	 */
> > +	for (i = 0; i < nb_segs; i++) {
> > +		ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(segs[i],
> > +					char *) + l2_hdrlen);
> 
> You could use rte_pktmbuf_mtod_offset to simplify the code.

Yes, you are right. Update later.

> 
> > +		length = segs[i]->pkt_len - l2_hdrlen;
> > +		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
> > +
> > +		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
> > +		ipv4_hdr->fragment_offset =
> > +			rte_cpu_to_be_16(frag_offset | is_mf);
> > +		frag_offset += ((length - l3_hdrlen) >> 3);
> > +	}
> > +}
> > +
> > +int
> > +gso_udp4_segment(struct rte_mbuf *pkt,
> > +		uint16_t gso_size,
> > +		struct rte_mempool *direct_pool,
> > +		struct rte_mempool *indirect_pool,
> > +		struct rte_mbuf **pkts_out,
> > +		uint16_t nb_pkts_out)
> > +{
> > +	struct ipv4_hdr *ipv4_hdr;
> > +	uint16_t pyld_unit_size, hdr_offset;
> > +	uint16_t frag_off;
> > +	int ret;
> > +
> > +	/* Don't process the fragmented packet */
> > +	ipv4_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(pkt, char *) +
> > +			pkt->l2_len);
> 
> Ditto.
> 
> BRs,
> Xiao

Thanks,
Jiayu

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

* [dpdk-dev] [PATCH v3 0/3] Support UDP/IPv4 GSO
  2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
                     ` (2 preceding siblings ...)
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
@ 2018-06-22  5:54   ` Jiayu Hu
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
                       ` (4 more replies)
  3 siblings, 5 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-06-22  5:54 UTC (permalink / raw)
  To: dev
  Cc: xiao.w.wang, konstantin.ananyev, yuwei1.zhang, bernard.iremonger,
	thomas, Jiayu Hu

With the support of UDP Fragmentation Offload (UFO) and TCP Segmentation
Offload (TSO) in virtio, VMs can exchange large UDP and TCP packets
exceeding MTU between each other, which can greatly reduce per-packet
processing overheads.

When the destination of the large TCP and UDP packets is crossing
machines, the host application needs to call two different libraries,
GSO and IP fragmentation, to split the large packets respectively.
However,the GSO and IP fragmentation library have quite different APIs,
which greatly complicates the host application implementation.

To simplify application development, we propose to support UDP/IPv4
fragmentation in the GSO library. With supporting UDP GSO, host
applicationss can use the unified APIs to split large UDP and TCP packets.

This patchset is to support UDP/IPv4 GSO. The first patch is to provide
UDP GSO function, the second patch is to enable UDP/IPv4 GSO in the
testpmd checksum forwarding engine, and the last patch is to update the
programmer guide and testpmd user guide.

Change log
==========
v3:
- replace rte_pktmbuf_mtod() with rte_pktmbuf_mtod_offset().
- fix meson build.
- add updates to document for better explaining how UDP GSO works.
V2:
- fix fragment offset calculation bug.
- add UDP GSO description in testpmd user guide.
- shorten the second patch name.

Jiayu Hu (3):
  gso: support UDP/IPv4 fragmentation
  app/testpmd: enable UDP GSO in csum engine
  gso: update documents for UDP/IPv4 GSO

 app/test-pmd/cmdline.c                             |  5 +-
 app/test-pmd/csumonly.c                            |  2 +
 app/test-pmd/testpmd.c                             |  2 +-
 .../generic_segmentation_offload_lib.rst           | 10 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst        |  7 ++
 lib/librte_gso/Makefile                            |  1 +
 lib/librte_gso/gso_common.h                        |  3 +
 lib/librte_gso/gso_udp4.c                          | 81 ++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h                          | 42 +++++++++++
 lib/librte_gso/meson.build                         |  2 +-
 lib/librte_gso/rte_gso.c                           | 24 +++++--
 lib/librte_gso/rte_gso.h                           |  6 +-
 12 files changed, 175 insertions(+), 10 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

-- 
2.7.4

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

* [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
@ 2018-06-22  5:54     ` Jiayu Hu
  2018-06-26 23:58       ` Ophir Munk
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 27+ messages in thread
From: Jiayu Hu @ 2018-06-22  5:54 UTC (permalink / raw)
  To: dev
  Cc: xiao.w.wang, konstantin.ananyev, yuwei1.zhang, bernard.iremonger,
	thomas, Jiayu Hu

This patch adds GSO support for UDP/IPv4 packets. Supported packets
may include a single VLAN tag. UDP/IPv4 GSO doesn't check if input
packets have correct checksums, and doesn't update checksums for
output packets (the responsibility for this lies with the application).
Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.

UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
MBUF, to organize an output packet. The direct MBUF stores the packet
header, while the indirect mbuf simply points to a location within the
original packet's payload. Consequently, use of UDP GSO requires
multi-segment MBUF support in the TX functions of the NIC driver.

If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
result, when all of its GSOed segments are freed, the packet is freed
automatically.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 lib/librte_gso/Makefile     |  1 +
 lib/librte_gso/gso_common.h |  3 ++
 lib/librte_gso/gso_udp4.c   | 81 +++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
 lib/librte_gso/meson.build  |  2 +-
 lib/librte_gso/rte_gso.c    | 24 +++++++++++---
 lib/librte_gso/rte_gso.h    |  6 +++-
 7 files changed, 152 insertions(+), 7 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile
index 3648ec0..1fac53a 100644
--- a/lib/librte_gso/Makefile
+++ b/lib/librte_gso/Makefile
@@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
+SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
 
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h
diff --git a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h
index 5ca5974..6cd764f 100644
--- a/lib/librte_gso/gso_common.h
+++ b/lib/librte_gso/gso_common.h
@@ -31,6 +31,9 @@
 		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 | \
 		 PKT_TX_TUNNEL_GRE))
 
+#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4)) == \
+		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
+
 /**
  * Internal function which updates the UDP header of a packet, following
  * segmentation. This is required to update the header's datagram length field.
diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c
new file mode 100644
index 0000000..927dee1
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include "gso_common.h"
+#include "gso_udp4.h"
+
+#define IPV4_HDR_MF_BIT (1U << 13)
+
+static inline void
+update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
+		uint16_t nb_segs)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t frag_offset = 0, is_mf;
+	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
+	uint16_t tail_idx = nb_segs - 1, length, i;
+
+	/*
+	 * Update IP header fields for output segments. Specifically,
+	 * keep the same IP id, update fragment offset and total
+	 * length.
+	 */
+	for (i = 0; i < nb_segs; i++) {
+		ipv4_hdr = rte_pktmbuf_mtod_offset(segs[i], struct ipv4_hdr *,
+			l2_hdrlen);
+		length = segs[i]->pkt_len - l2_hdrlen;
+		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
+
+		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
+		ipv4_hdr->fragment_offset =
+			rte_cpu_to_be_16(frag_offset | is_mf);
+		frag_offset += ((length - l3_hdrlen) >> 3);
+	}
+}
+
+int
+gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t pyld_unit_size, hdr_offset;
+	uint16_t frag_off;
+	int ret;
+
+	/* Don't process the fragmented packet */
+	ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,
+			pkt->l2_len);
+	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
+	if (unlikely(IS_FRAGMENTED(frag_off))) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	/*
+	 * UDP fragmentation is the same as IP fragmentation.
+	 * Except the first one, other output packets just have l2
+	 * and l3 headers.
+	 */
+	hdr_offset = pkt->l2_len + pkt->l3_len;
+
+	/* Don't process the packet without data. */
+	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	pyld_unit_size = gso_size - hdr_offset;
+
+	/* Segment the payload */
+	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
+			indirect_pool, pkts_out, nb_pkts_out);
+	if (ret > 1)
+		update_ipv4_udp_headers(pkt, pkts_out, ret);
+
+	return ret;
+}
diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h
new file mode 100644
index 0000000..b2a2908
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _GSO_UDP4_H_
+#define _GSO_UDP4_H_
+
+#include <stdint.h>
+#include <rte_mbuf.h>
+
+/**
+ * Segment an UDP/IPv4 packet. This function doesn't check if the input
+ * packet has correct checksums, and doesn't update checksums for output
+ * GSO segments. Furthermore, it doesn't process IP fragment packets.
+ *
+ * @param pkt
+ *  The packet mbuf to segment.
+ * @param gso_size
+ *  The max length of a GSO segment, measured in bytes.
+ * @param direct_pool
+ *  MBUF pool used for allocating direct buffers for output segments.
+ * @param indirect_pool
+ *  MBUF pool used for allocating indirect buffers for output segments.
+ * @param pkts_out
+ *  Pointer array used to store the MBUF addresses of output GSO
+ *  segments, when the function succeeds. If the memory space in
+ *  pkts_out is insufficient, it fails and returns -EINVAL.
+ * @param nb_pkts_out
+ *  The max number of items that 'pkts_out' can keep.
+ *
+ * @return
+ *   - The number of GSO segments filled in pkts_out on success.
+ *   - Return -ENOMEM if run out of memory in MBUF pools.
+ *   - Return -EINVAL for invalid parameters.
+ */
+int gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out);
+#endif
diff --git a/lib/librte_gso/meson.build b/lib/librte_gso/meson.build
index 056534f..ad8dd85 100644
--- a/lib/librte_gso/meson.build
+++ b/lib/librte_gso/meson.build
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-sources = files('gso_common.c', 'gso_tcp4.c',
+sources = files('gso_common.c', 'gso_tcp4.c', 'gso_udp4.c',
  		'gso_tunnel_tcp4.c', 'rte_gso.c')
 headers = files('rte_gso.h')
 deps += ['ethdev']
diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c
index a44e3d4..751b5b6 100644
--- a/lib/librte_gso/rte_gso.c
+++ b/lib/librte_gso/rte_gso.c
@@ -11,6 +11,17 @@
 #include "gso_common.h"
 #include "gso_tcp4.h"
 #include "gso_tunnel_tcp4.h"
+#include "gso_udp4.h"
+
+#define ILLEGAL_UDP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
+	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
+
+#define ILLEGAL_TCP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
+		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
+		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
+		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
 
 int
 rte_gso_segment(struct rte_mbuf *pkt,
@@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
 
 	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
 			nb_pkts_out < 1 ||
-			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
-			((gso_ctx->gso_types & (DEV_TX_OFFLOAD_TCP_TSO |
-			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
+			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
+			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
 		return -EINVAL;
 
 	if (gso_ctx->gso_size >= pkt->pkt_len) {
-		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
+		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
 		pkts_out[0] = pkt;
 		return 1;
 	}
@@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
 		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
 				direct_pool, indirect_pool,
 				pkts_out, nb_pkts_out);
+	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
+			(gso_ctx->gso_types & DEV_TX_OFFLOAD_UDP_TSO)) {
+		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
+		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
+				indirect_pool, pkts_out, nb_pkts_out);
 	} else {
 		/* unsupported packet, skip */
 		pkts_out[0] = pkt;
diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h
index f4abd61..a626a11 100644
--- a/lib/librte_gso/rte_gso.h
+++ b/lib/librte_gso/rte_gso.h
@@ -17,10 +17,14 @@ extern "C" {
 #include <stdint.h>
 #include <rte_mbuf.h>
 
-/* Minimum GSO segment size. */
+/* Minimum GSO segment size for TCP based packets. */
 #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
 		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)
 
+/* Minimum GSO segment size for UDP based packets. */
+#define RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
+		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
+
 /* GSO flags for rte_gso_ctx. */
 #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)
 /**< Use fixed IP ids for output GSO segments. Setting
-- 
2.7.4

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

* [dpdk-dev] [PATCH v3 2/3] app/testpmd: enable UDP GSO in csum engine
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
@ 2018-06-22  5:54     ` Jiayu Hu
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-06-22  5:54 UTC (permalink / raw)
  To: dev
  Cc: xiao.w.wang, konstantin.ananyev, yuwei1.zhang, bernard.iremonger,
	thomas, Jiayu Hu

This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4
packets transmitted over a GSO-enabled port will undergo segmentation.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 app/test-pmd/cmdline.c  | 5 +++--
 app/test-pmd/csumonly.c | 2 ++
 app/test-pmd/testpmd.c  | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8..4239e91 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -4792,8 +4792,9 @@ cmd_gso_show_parsed(void *parsed_result,
 		if (gso_ports[res->cmd_pid].enable) {
 			printf("Max GSO'd packet size: %uB\n"
 					"Supported GSO types: TCP/IPv4, "
-					"VxLAN with inner TCP/IPv4 packet, "
-					"GRE with inner TCP/IPv4  packet\n",
+					"UDP/IPv4, VxLAN with inner "
+					"TCP/IPv4 packet, GRE with inner "
+					"TCP/IPv4 packet\n",
 					gso_max_segment_size);
 		} else
 			printf("GSO is not enabled on Port %u\n", res->cmd_pid);
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index 0bb88cf..4948292 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -411,6 +411,8 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
 						info->ethertype);
 			}
 		}
+		if (info->gso_enable)
+			ol_flags |= PKT_TX_UDP_SEG;
 	} else if (info->l4_proto == IPPROTO_TCP) {
 		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
 		tcp_hdr->cksum = 0;
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 24c1998..fa9208d 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -777,7 +777,7 @@ init_config(void)
 	init_port_config();
 
 	gso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-		DEV_TX_OFFLOAD_GRE_TNL_TSO;
+		DEV_TX_OFFLOAD_GRE_TNL_TSO | DEV_TX_OFFLOAD_UDP_TSO;
 	/*
 	 * Records which Mbuf pool to use by each logical core, if needed.
 	 */
-- 
2.7.4

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

* [dpdk-dev] [PATCH v3 3/3] gso: update documents for UDP/IPv4 GSO
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
@ 2018-06-22  5:54     ` Jiayu Hu
  2018-06-25  4:13     ` [dpdk-dev] [PATCH v3 0/3] Support " Wang, Xiao W
  2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
  4 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-06-22  5:54 UTC (permalink / raw)
  To: dev
  Cc: xiao.w.wang, konstantin.ananyev, yuwei1.zhang, bernard.iremonger,
	thomas, Jiayu Hu

This patch updates the programmer guide and testpmd user guide for
UDP/IPv4 GSO.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 doc/guides/prog_guide/generic_segmentation_offload_lib.rst | 10 ++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst                |  7 +++++++
 2 files changed, 17 insertions(+)

diff --git a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
index 9959f0d..0cfc119 100644
--- a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
+++ b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
@@ -43,6 +43,7 @@ Limitations
 #. Currently, the GSO library supports the following IPv4 packet types:
 
  - TCP
+ - UDP
  - VxLAN
  - GRE
 
@@ -146,6 +147,15 @@ TCP/IPv4 GSO
 TCP/IPv4 GSO supports segmentation of suitably large TCP/IPv4 packets, which
 may also contain an optional VLAN tag.
 
+UDP/IPv4 GSO
+~~~~~~~~~~~~
+UDP/IPv4 GSO supports segmentation of suitably large UDP/IPv4 packets, which
+may also contain an optional VLAN tag. UDP GSO is the same as IP fragmentation.
+Specifically, UDP GSO treats the UDP header as a part of the payload and
+does not modify it during segmentation. Therefore, after UDP GSO, only the
+first output packet has the original UDP header, and others just have l2
+and l3 headers.
+
 VxLAN GSO
 ~~~~~~~~~
 VxLAN packets GSO supports segmentation of suitably large VxLAN packets,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50..6f2de24 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1059,6 +1059,13 @@ By default, GSO is disabled for all ports.
 
    testpmd> csum set tcp hw <port_id>
 
+   UDP GSO is the same as IP fragmentation, which treats the UDP header
+   as the payload and does not modify it during segmentation. That is,
+   after UDP GSO, only the first output fragment has the original UDP
+   header. Therefore, users need to enable HW IP checksum calculation
+   and SW UDP checksum calculation for GSO-enabled ports, if they want
+   correct checksums for UDP/IPv4 packets.
+
 set gso segsz
 ~~~~~~~~~~~~~
 
-- 
2.7.4

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

* Re: [dpdk-dev] [PATCH v3 0/3] Support UDP/IPv4 GSO
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
                       ` (2 preceding siblings ...)
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
@ 2018-06-25  4:13     ` Wang, Xiao W
  2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
  4 siblings, 0 replies; 27+ messages in thread
From: Wang, Xiao W @ 2018-06-25  4:13 UTC (permalink / raw)
  To: Hu, Jiayu, dev
  Cc: Ananyev, Konstantin, Zhang, Yuwei1, Iremonger, Bernard, thomas

Hi,

> -----Original Message-----
> From: Hu, Jiayu
> Sent: Friday, June 22, 2018 1:54 PM
> To: dev@dpdk.org
> Cc: Wang, Xiao W <xiao.w.wang@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>; Zhang, Yuwei1 <yuwei1.zhang@intel.com>;
> Iremonger, Bernard <bernard.iremonger@intel.com>; thomas@monjalon.net;
> Hu, Jiayu <jiayu.hu@intel.com>
> Subject: [PATCH v3 0/3] Support UDP/IPv4 GSO
> 
> With the support of UDP Fragmentation Offload (UFO) and TCP Segmentation
> Offload (TSO) in virtio, VMs can exchange large UDP and TCP packets
> exceeding MTU between each other, which can greatly reduce per-packet
> processing overheads.
> 
> When the destination of the large TCP and UDP packets is crossing
> machines, the host application needs to call two different libraries,
> GSO and IP fragmentation, to split the large packets respectively.
> However,the GSO and IP fragmentation library have quite different APIs,
> which greatly complicates the host application implementation.
> 
> To simplify application development, we propose to support UDP/IPv4
> fragmentation in the GSO library. With supporting UDP GSO, host
> applicationss can use the unified APIs to split large UDP and TCP packets.
> 
> This patchset is to support UDP/IPv4 GSO. The first patch is to provide
> UDP GSO function, the second patch is to enable UDP/IPv4 GSO in the
> testpmd checksum forwarding engine, and the last patch is to update the
> programmer guide and testpmd user guide.
> 
> Change log
> ==========
> v3:
> - replace rte_pktmbuf_mtod() with rte_pktmbuf_mtod_offset().
> - fix meson build.
> - add updates to document for better explaining how UDP GSO works.
> V2:
> - fix fragment offset calculation bug.
> - add UDP GSO description in testpmd user guide.
> - shorten the second patch name.
> 
> Jiayu Hu (3):
>   gso: support UDP/IPv4 fragmentation
>   app/testpmd: enable UDP GSO in csum engine
>   gso: update documents for UDP/IPv4 GSO
> 
>  app/test-pmd/cmdline.c                             |  5 +-
>  app/test-pmd/csumonly.c                            |  2 +
>  app/test-pmd/testpmd.c                             |  2 +-
>  .../generic_segmentation_offload_lib.rst           | 10 +++
>  doc/guides/testpmd_app_ug/testpmd_funcs.rst        |  7 ++
>  lib/librte_gso/Makefile                            |  1 +
>  lib/librte_gso/gso_common.h                        |  3 +
>  lib/librte_gso/gso_udp4.c                          | 81 ++++++++++++++++++++++
>  lib/librte_gso/gso_udp4.h                          | 42 +++++++++++
>  lib/librte_gso/meson.build                         |  2 +-
>  lib/librte_gso/rte_gso.c                           | 24 +++++--
>  lib/librte_gso/rte_gso.h                           |  6 +-
>  12 files changed, 175 insertions(+), 10 deletions(-)
>  create mode 100644 lib/librte_gso/gso_udp4.c
>  create mode 100644 lib/librte_gso/gso_udp4.h
> 
> --
> 2.7.4

Series Acked-by: Xiao Wang <xiao.w.wang@intel.com>

BRs,
Xiao

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

* Re: [dpdk-dev] [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine
  2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
@ 2018-06-26  9:46     ` Iremonger, Bernard
  0 siblings, 0 replies; 27+ messages in thread
From: Iremonger, Bernard @ 2018-06-26  9:46 UTC (permalink / raw)
  To: Hu, Jiayu, dev; +Cc: Ananyev, Konstantin, Zhang, Yuwei1

> -----Original Message-----
> From: Hu, Jiayu
> Sent: Sunday, June 17, 2018 4:13 AM
> To: dev@dpdk.org
> Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> <yuwei1.zhang@intel.com>; Iremonger, Bernard
> <bernard.iremonger@intel.com>; Hu, Jiayu <jiayu.hu@intel.com>
> Subject: [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine
> 
> This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4 packets
> transmitted over a GSO-enabled port will undergo segmentation.
> 
> Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> ---
Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>

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

* Re: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
@ 2018-06-26 23:58       ` Ophir Munk
  2018-06-27  2:28         ` Hu, Jiayu
  0 siblings, 1 reply; 27+ messages in thread
From: Ophir Munk @ 2018-06-26 23:58 UTC (permalink / raw)
  To: Jiayu Hu, dev
  Cc: xiao.w.wang, konstantin.ananyev, yuwei1.zhang, bernard.iremonger,
	Thomas Monjalon

Hi,
Please find some comments below.

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> Sent: Friday, June 22, 2018 8:54 AM
> To: dev@dpdk.org
> Cc: xiao.w.wang@intel.com; konstantin.ananyev@intel.com;
> yuwei1.zhang@intel.com; bernard.iremonger@intel.com; Thomas Monjalon
> <thomas@monjalon.net>; Jiayu Hu <jiayu.hu@intel.com>
> Subject: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation
> 
> This patch adds GSO support for UDP/IPv4 packets. Supported packets may
> include a single VLAN tag. UDP/IPv4 GSO doesn't check if input packets have
> correct checksums, and doesn't update checksums for output packets (the
> responsibility for this lies with the application).
> Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.
> 
> UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
> MBUF, to organize an output packet. The direct MBUF stores the packet
> header, while the indirect mbuf simply points to a location within the original
> packet's payload. Consequently, use of UDP GSO requires multi-segment
> MBUF support in the TX functions of the NIC driver.
> 
> If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a result,
> when all of its GSOed segments are freed, the packet is freed automatically.
> 
> Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> ---
>  lib/librte_gso/Makefile     |  1 +
>  lib/librte_gso/gso_common.h |  3 ++
>  lib/librte_gso/gso_udp4.c   | 81
> +++++++++++++++++++++++++++++++++++++++++++++
>  lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
>  lib/librte_gso/meson.build  |  2 +-
>  lib/librte_gso/rte_gso.c    | 24 +++++++++++---
>  lib/librte_gso/rte_gso.h    |  6 +++-
>  7 files changed, 152 insertions(+), 7 deletions(-)  create mode 100644
> lib/librte_gso/gso_udp4.c  create mode 100644 lib/librte_gso/gso_udp4.h
> 
> diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile index
> 3648ec0..1fac53a 100644
> --- a/lib/librte_gso/Makefile
> +++ b/lib/librte_gso/Makefile
> @@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
>  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
>  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
>  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
> +SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
> 
>  # install this header file
>  SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h diff --git
> a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h index
> 5ca5974..6cd764f 100644
> --- a/lib/librte_gso/gso_common.h
> +++ b/lib/librte_gso/gso_common.h
> @@ -31,6 +31,9 @@
>  		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 | \
>  		 PKT_TX_TUNNEL_GRE))
> 
> +#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4)) ==
> \
> +		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
> +
>  /**
>   * Internal function which updates the UDP header of a packet, following
>   * segmentation. This is required to update the header's datagram length
> field.
> diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c new file
> mode 100644 index 0000000..927dee1
> --- /dev/null
> +++ b/lib/librte_gso/gso_udp4.c

File gso_upd4.c could be very similar to file gso_tcp4.c and that would avoid code duplication.
In a unified file you could use a tcp vs. udp flag to distinguish between them when necessary.
The files are short (~75 lines) so it is not a critical issue.

> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation
> + */
> +
> +#include "gso_common.h"
> +#include "gso_udp4.h"
> +
> +#define IPV4_HDR_MF_BIT (1U << 13)
> +
> +static inline void
> +update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
> +		uint16_t nb_segs)
> +{
> +	struct ipv4_hdr *ipv4_hdr;
> +	uint16_t frag_offset = 0, is_mf;
> +	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
> +	uint16_t tail_idx = nb_segs - 1, length, i;
> +
> +	/*
> +	 * Update IP header fields for output segments. Specifically,
> +	 * keep the same IP id, update fragment offset and total
> +	 * length.
> +	 */
> +	for (i = 0; i < nb_segs; i++) {
> +		ipv4_hdr = rte_pktmbuf_mtod_offset(segs[i], struct ipv4_hdr
> *,
> +			l2_hdrlen);
> +		length = segs[i]->pkt_len - l2_hdrlen;
> +		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
> +
> +		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
> +		ipv4_hdr->fragment_offset =
> +			rte_cpu_to_be_16(frag_offset | is_mf);
> +		frag_offset += ((length - l3_hdrlen) >> 3);
> +	}
> +}
> +
> +int
> +gso_udp4_segment(struct rte_mbuf *pkt,
> +		uint16_t gso_size,
> +		struct rte_mempool *direct_pool,
> +		struct rte_mempool *indirect_pool,
> +		struct rte_mbuf **pkts_out,
> +		uint16_t nb_pkts_out)
> +{
> +	struct ipv4_hdr *ipv4_hdr;
> +	uint16_t pyld_unit_size, hdr_offset;
> +	uint16_t frag_off;
> +	int ret;
> +
> +	/* Don't process the fragmented packet */
> +	ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,
> +			pkt->l2_len);
> +	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
> +	if (unlikely(IS_FRAGMENTED(frag_off))) {
> +		pkts_out[0] = pkt;
> +		return 1;
> +	}
> +
> +	/*
> +	 * UDP fragmentation is the same as IP fragmentation.
> +	 * Except the first one, other output packets just have l2
> +	 * and l3 headers.
> +	 */
> +	hdr_offset = pkt->l2_len + pkt->l3_len;
> +
> +	/* Don't process the packet without data. */
> +	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
> +		pkts_out[0] = pkt;
> +		return 1;
> +	}
> +
> +	pyld_unit_size = gso_size - hdr_offset;
> +
> +	/* Segment the payload */
> +	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
> +			indirect_pool, pkts_out, nb_pkts_out);
> +	if (ret > 1)
> +		update_ipv4_udp_headers(pkt, pkts_out, ret);
> +
> +	return ret;
> +}
> diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h new file
> mode 100644 index 0000000..b2a2908

File gso_upd4.h is almost identical to file gso_tcp4.h so both files (although short ~40 lines) could have been unified into one file.

> --- /dev/null
> +++ b/lib/librte_gso/gso_udp4.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation
> + */
> +
> +#ifndef _GSO_UDP4_H_
> +#define _GSO_UDP4_H_
> +
> +#include <stdint.h>
> +#include <rte_mbuf.h>
> +
> +/**
> + * Segment an UDP/IPv4 packet. This function doesn't check if the input
> + * packet has correct checksums, and doesn't update checksums for
> +output
> + * GSO segments. Furthermore, it doesn't process IP fragment packets.
> + *
> + * @param pkt
> + *  The packet mbuf to segment.
> + * @param gso_size
> + *  The max length of a GSO segment, measured in bytes.
> + * @param direct_pool
> + *  MBUF pool used for allocating direct buffers for output segments.
> + * @param indirect_pool
> + *  MBUF pool used for allocating indirect buffers for output segments.
> + * @param pkts_out
> + *  Pointer array used to store the MBUF addresses of output GSO
> + *  segments, when the function succeeds. If the memory space in
> + *  pkts_out is insufficient, it fails and returns -EINVAL.
> + * @param nb_pkts_out
> + *  The max number of items that 'pkts_out' can keep.
> + *
> + * @return
> + *   - The number of GSO segments filled in pkts_out on success.
> + *   - Return -ENOMEM if run out of memory in MBUF pools.
> + *   - Return -EINVAL for invalid parameters.
> + */
> +int gso_udp4_segment(struct rte_mbuf *pkt,
> +		uint16_t gso_size,
> +		struct rte_mempool *direct_pool,
> +		struct rte_mempool *indirect_pool,
> +		struct rte_mbuf **pkts_out,
> +		uint16_t nb_pkts_out);
> +#endif
> diff --git a/lib/librte_gso/meson.build b/lib/librte_gso/meson.build index
> 056534f..ad8dd85 100644
> --- a/lib/librte_gso/meson.build
> +++ b/lib/librte_gso/meson.build
> @@ -1,7 +1,7 @@
>  # SPDX-License-Identifier: BSD-3-Clause  # Copyright(c) 2017 Intel
> Corporation
> 
> -sources = files('gso_common.c', 'gso_tcp4.c',
> +sources = files('gso_common.c', 'gso_tcp4.c', 'gso_udp4.c',
>   		'gso_tunnel_tcp4.c', 'rte_gso.c')
>  headers = files('rte_gso.h')
>  deps += ['ethdev']
> diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c index
> a44e3d4..751b5b6 100644
> --- a/lib/librte_gso/rte_gso.c
> +++ b/lib/librte_gso/rte_gso.c
> @@ -11,6 +11,17 @@
>  #include "gso_common.h"
>  #include "gso_tcp4.h"
>  #include "gso_tunnel_tcp4.h"
> +#include "gso_udp4.h"
> +
> +#define ILLEGAL_UDP_GSO_CTX(ctx) \
> +	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
> +	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
> +
> +#define ILLEGAL_TCP_GSO_CTX(ctx) \
> +	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
> +		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
> +		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
> +		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)

Can you please explain why it is correct that the min len for VXLAN_TNL or GRE_TNL is that of TCP MIN size (RTE_GSO_SEG_SIZE_MIN)

> 

To make the macros above and their usage below clearer:

1. I would change the || with &&. and == with != 

#define ILLEGAL_UDP_GSO_CTX(ctx) \
	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) != 0) && \
	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)

#define ILLEGAL_TCP_GSO_CTX(ctx) \
	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
		DEV_TX_OFFLOAD_GRE_TNL_TSO)) != 0) && \
		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)

2. Then later I would change the && with || 

Changing original:
			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))

With this:
			ILLEGAL_UDP_GSO_CTX(gso_ctx) ||
			 ILLEGAL_TCP_GSO_CTX(gso_ctx))


>  int
>  rte_gso_segment(struct rte_mbuf *pkt,
> @@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
> 
>  	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
>  			nb_pkts_out < 1 ||
> -			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
> -			((gso_ctx->gso_types &
> (DEV_TX_OFFLOAD_TCP_TSO |
> -			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
> -			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
> +			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
> +			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
>  		return -EINVAL;
> 
>  	if (gso_ctx->gso_size >= pkt->pkt_len) {
> -		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
> +		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
>  		pkts_out[0] = pkt;
>  		return 1;
>  	}
> @@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
>  		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
>  				direct_pool, indirect_pool,
>  				pkts_out, nb_pkts_out);
> +	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
> +			(gso_ctx->gso_types &
> DEV_TX_OFFLOAD_UDP_TSO)) {
> +		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
> +		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
> +				indirect_pool, pkts_out, nb_pkts_out);
>  	} else {
>  		/* unsupported packet, skip */
>  		pkts_out[0] = pkt;
> diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h index
> f4abd61..a626a11 100644
> --- a/lib/librte_gso/rte_gso.h
> +++ b/lib/librte_gso/rte_gso.h
> @@ -17,10 +17,14 @@ extern "C" {
>  #include <stdint.h>
>  #include <rte_mbuf.h>
> 
> -/* Minimum GSO segment size. */
> +/* Minimum GSO segment size for TCP based packets. */
>  #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
>  		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)

RTE_GSO_SEG_SIZE_MIN is actually TCP min size. Can you name this macro as
RTE_GSO_TCP_SEG_SIZE_MIN (symmetrically to the UDP macro below)?

> 
> +/* Minimum GSO segment size for UDP based packets. */ #define
> +RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
> +		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
> +
>  /* GSO flags for rte_gso_ctx. */
>  #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)  /**< Use fixed IP ids for
> output GSO segments. Setting
> --
> 2.7.4

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

* Re: [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide
  2018-05-29  7:41 ` [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide Jiayu Hu
@ 2018-06-27  1:59   ` Zhang, Yuwei1
  0 siblings, 0 replies; 27+ messages in thread
From: Zhang, Yuwei1 @ 2018-06-27  1:59 UTC (permalink / raw)
  To: Hu, Jiayu, dev; +Cc: Ananyev, Konstantin, Hu, Jiayu

Tested-by: Yuwei Zhang<yuwei1.zhang@intel.com>

-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
Sent: Tuesday, May 29, 2018 3:41 PM
To: dev@dpdk.org
Cc: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Hu, Jiayu <jiayu.hu@intel.com>
Subject: [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
---
 doc/guides/prog_guide/generic_segmentation_offload_lib.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
index 9959f0d..cf700c5 100644
--- a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
+++ b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
@@ -43,6 +43,7 @@ Limitations
 #. Currently, the GSO library supports the following IPv4 packet types:
 
  - TCP
+ - UDP
  - VxLAN
  - GRE
 
@@ -146,6 +147,11 @@ TCP/IPv4 GSO
 TCP/IPv4 GSO supports segmentation of suitably large TCP/IPv4 packets, which  may also contain an optional VLAN tag.
 
+UDP/IPv4 GSO
+~~~~~~~~~~~~
+UDP/IPv4 GSO supports segmentation of suitably large UDP/IPv4 packets, 
+which may also contain an optional VLAN tag.
+
 VxLAN GSO
 ~~~~~~~~~
 VxLAN packets GSO supports segmentation of suitably large VxLAN packets,
--
2.7.4

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

* Re: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-26 23:58       ` Ophir Munk
@ 2018-06-27  2:28         ` Hu, Jiayu
  2018-06-27  5:05           ` Hu, Jiayu
  0 siblings, 1 reply; 27+ messages in thread
From: Hu, Jiayu @ 2018-06-27  2:28 UTC (permalink / raw)
  To: Ophir Munk, dev
  Cc: Wang, Xiao W, Ananyev, Konstantin, Zhang, Yuwei1, Iremonger,
	Bernard, Thomas Monjalon

Hi Ophir,

Replies are inline.

> -----Original Message-----
> From: Ophir Munk [mailto:ophirmu@mellanox.com]
> Sent: Wednesday, June 27, 2018 7:59 AM
> To: Hu, Jiayu <jiayu.hu@intel.com>; dev@dpdk.org
> Cc: Wang, Xiao W <xiao.w.wang@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> <yuwei1.zhang@intel.com>; Iremonger, Bernard
> <bernard.iremonger@intel.com>; Thomas Monjalon
> <thomas@monjalon.net>
> Subject: RE: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4
> fragmentation
> 
> Hi,
> Please find some comments below.
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> > Sent: Friday, June 22, 2018 8:54 AM
> > To: dev@dpdk.org
> > Cc: xiao.w.wang@intel.com; konstantin.ananyev@intel.com;
> > yuwei1.zhang@intel.com; bernard.iremonger@intel.com; Thomas
> Monjalon
> > <thomas@monjalon.net>; Jiayu Hu <jiayu.hu@intel.com>
> > Subject: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation
> >
> > This patch adds GSO support for UDP/IPv4 packets. Supported packets
> may
> > include a single VLAN tag. UDP/IPv4 GSO doesn't check if input packets
> have
> > correct checksums, and doesn't update checksums for output packets (the
> > responsibility for this lies with the application).
> > Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.
> >
> > UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
> > MBUF, to organize an output packet. The direct MBUF stores the packet
> > header, while the indirect mbuf simply points to a location within the
> original
> > packet's payload. Consequently, use of UDP GSO requires multi-segment
> > MBUF support in the TX functions of the NIC driver.
> >
> > If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
> result,
> > when all of its GSOed segments are freed, the packet is freed
> automatically.
> >
> > Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> > ---
> >  lib/librte_gso/Makefile     |  1 +
> >  lib/librte_gso/gso_common.h |  3 ++
> >  lib/librte_gso/gso_udp4.c   | 81
> > +++++++++++++++++++++++++++++++++++++++++++++
> >  lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
> >  lib/librte_gso/meson.build  |  2 +-
> >  lib/librte_gso/rte_gso.c    | 24 +++++++++++---
> >  lib/librte_gso/rte_gso.h    |  6 +++-
> >  7 files changed, 152 insertions(+), 7 deletions(-)  create mode 100644
> > lib/librte_gso/gso_udp4.c  create mode 100644 lib/librte_gso/gso_udp4.h
> >
> > diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile index
> > 3648ec0..1fac53a 100644
> > --- a/lib/librte_gso/Makefile
> > +++ b/lib/librte_gso/Makefile
> > @@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
> > +SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
> >
> >  # install this header file
> >  SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h diff --git
> > a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h index
> > 5ca5974..6cd764f 100644
> > --- a/lib/librte_gso/gso_common.h
> > +++ b/lib/librte_gso/gso_common.h
> > @@ -31,6 +31,9 @@
> >  		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 |
> \
> >  		 PKT_TX_TUNNEL_GRE))
> >
> > +#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4))
> ==
> > \
> > +		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
> > +
> >  /**
> >   * Internal function which updates the UDP header of a packet, following
> >   * segmentation. This is required to update the header's datagram length
> > field.
> > diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c new file
> > mode 100644 index 0000000..927dee1
> > --- /dev/null
> > +++ b/lib/librte_gso/gso_udp4.c
> 
> File gso_upd4.c could be very similar to file gso_tcp4.c and that would
> avoid code duplication.
> In a unified file you could use a tcp vs. udp flag to distinguish between them
> when necessary.
> The files are short (~75 lines) so it is not a critical issue.

The function gso_tcp4_segment and gso_udp4_segment have different prototype,
and their GSO rules are different. They are two different basic GSO types.

The GSO library gives each GSO type (TCP, tunnel) an internal .c and .h file, and their name
represents their content. The rte_gso_segment calls different function according to the GSO type.
This style is very clear for developers or users to understand. In addition, as you said, the code
is short. So I think it's better to keep this style for UDP/IPv4 GSO.

> 
> > @@ -0,0 +1,81 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2018 Intel Corporation
> > + */
> > +
> > +#include "gso_common.h"
> > +#include "gso_udp4.h"
> > +
> > +#define IPV4_HDR_MF_BIT (1U << 13)
> > +
> > +static inline void
> > +update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
> > +		uint16_t nb_segs)
> > +{
> > +	struct ipv4_hdr *ipv4_hdr;
> > +	uint16_t frag_offset = 0, is_mf;
> > +	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
> > +	uint16_t tail_idx = nb_segs - 1, length, i;
> > +
> > +	/*
> > +	 * Update IP header fields for output segments. Specifically,
> > +	 * keep the same IP id, update fragment offset and total
> > +	 * length.
> > +	 */
> > +	for (i = 0; i < nb_segs; i++) {
> > +		ipv4_hdr = rte_pktmbuf_mtod_offset(segs[i], struct
> ipv4_hdr
> > *,
> > +			l2_hdrlen);
> > +		length = segs[i]->pkt_len - l2_hdrlen;
> > +		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
> > +
> > +		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
> > +		ipv4_hdr->fragment_offset =
> > +			rte_cpu_to_be_16(frag_offset | is_mf);
> > +		frag_offset += ((length - l3_hdrlen) >> 3);
> > +	}
> > +}
> > +
> > +int
> > +gso_udp4_segment(struct rte_mbuf *pkt,
> > +		uint16_t gso_size,
> > +		struct rte_mempool *direct_pool,
> > +		struct rte_mempool *indirect_pool,
> > +		struct rte_mbuf **pkts_out,
> > +		uint16_t nb_pkts_out)
> > +{
> > +	struct ipv4_hdr *ipv4_hdr;
> > +	uint16_t pyld_unit_size, hdr_offset;
> > +	uint16_t frag_off;
> > +	int ret;
> > +
> > +	/* Don't process the fragmented packet */
> > +	ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,
> > +			pkt->l2_len);
> > +	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
> > +	if (unlikely(IS_FRAGMENTED(frag_off))) {
> > +		pkts_out[0] = pkt;
> > +		return 1;
> > +	}
> > +
> > +	/*
> > +	 * UDP fragmentation is the same as IP fragmentation.
> > +	 * Except the first one, other output packets just have l2
> > +	 * and l3 headers.
> > +	 */
> > +	hdr_offset = pkt->l2_len + pkt->l3_len;
> > +
> > +	/* Don't process the packet without data. */
> > +	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
> > +		pkts_out[0] = pkt;
> > +		return 1;
> > +	}
> > +
> > +	pyld_unit_size = gso_size - hdr_offset;
> > +
> > +	/* Segment the payload */
> > +	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
> > +			indirect_pool, pkts_out, nb_pkts_out);
> > +	if (ret > 1)
> > +		update_ipv4_udp_headers(pkt, pkts_out, ret);
> > +
> > +	return ret;
> > +}
> > diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h new file
> > mode 100644 index 0000000..b2a2908
> 
> File gso_upd4.h is almost identical to file gso_tcp4.h so both files (although
> short ~40 lines) could have been unified into one file.

Ditto.

> 
> > --- /dev/null
> > +++ b/lib/librte_gso/gso_udp4.h
> > @@ -0,0 +1,42 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2018 Intel Corporation
> > + */
> > +
> > +#ifndef _GSO_UDP4_H_
> > +#define _GSO_UDP4_H_
> > +
> > +#include <stdint.h>
> > +#include <rte_mbuf.h>
> > +
> > +/**
> > + * Segment an UDP/IPv4 packet. This function doesn't check if the input
> > + * packet has correct checksums, and doesn't update checksums for
> > +output
> > + * GSO segments. Furthermore, it doesn't process IP fragment packets.
> > + *
> > + * @param pkt
> > + *  The packet mbuf to segment.
> > + * @param gso_size
> > + *  The max length of a GSO segment, measured in bytes.
> > + * @param direct_pool
> > + *  MBUF pool used for allocating direct buffers for output segments.
> > + * @param indirect_pool
> > + *  MBUF pool used for allocating indirect buffers for output segments.
> > + * @param pkts_out
> > + *  Pointer array used to store the MBUF addresses of output GSO
> > + *  segments, when the function succeeds. If the memory space in
> > + *  pkts_out is insufficient, it fails and returns -EINVAL.
> > + * @param nb_pkts_out
> > + *  The max number of items that 'pkts_out' can keep.
> > + *
> > + * @return
> > + *   - The number of GSO segments filled in pkts_out on success.
> > + *   - Return -ENOMEM if run out of memory in MBUF pools.
> > + *   - Return -EINVAL for invalid parameters.
> > + */
> > +int gso_udp4_segment(struct rte_mbuf *pkt,
> > +		uint16_t gso_size,
> > +		struct rte_mempool *direct_pool,
> > +		struct rte_mempool *indirect_pool,
> > +		struct rte_mbuf **pkts_out,
> > +		uint16_t nb_pkts_out);
> > +#endif
> > diff --git a/lib/librte_gso/meson.build b/lib/librte_gso/meson.build index
> > 056534f..ad8dd85 100644
> > --- a/lib/librte_gso/meson.build
> > +++ b/lib/librte_gso/meson.build
> > @@ -1,7 +1,7 @@
> >  # SPDX-License-Identifier: BSD-3-Clause  # Copyright(c) 2017 Intel
> > Corporation
> >
> > -sources = files('gso_common.c', 'gso_tcp4.c',
> > +sources = files('gso_common.c', 'gso_tcp4.c', 'gso_udp4.c',
> >   		'gso_tunnel_tcp4.c', 'rte_gso.c')
> >  headers = files('rte_gso.h')
> >  deps += ['ethdev']
> > diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c index
> > a44e3d4..751b5b6 100644
> > --- a/lib/librte_gso/rte_gso.c
> > +++ b/lib/librte_gso/rte_gso.c
> > @@ -11,6 +11,17 @@
> >  #include "gso_common.h"
> >  #include "gso_tcp4.h"
> >  #include "gso_tunnel_tcp4.h"
> > +#include "gso_udp4.h"
> > +
> > +#define ILLEGAL_UDP_GSO_CTX(ctx) \
> > +	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
> > +	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
> > +
> > +#define ILLEGAL_TCP_GSO_CTX(ctx) \
> > +	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
> > +		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
> > +		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
> > +		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
> 
> Can you please explain why it is correct that the min len for VXLAN_TNL or
> GRE_TNL is that of TCP MIN size (RTE_GSO_SEG_SIZE_MIN)

The logic here is a little complicated. First, we have two GSO types, i.e. TCP and UDP,
and they have different requirements for min lengths and gso_types flags. In the code,
we use ILLEGAL_UDP_GSO_CTX() and ILLEGAL_TCP_GSO_CTX() to check if the input packet
doesn't meet the requirements. Rte_gso_segment() starts to process the input packet only
when it meets UDP or TCP requirement. In other words, rte_gso_segment() stops if the
packet doesn't meet both requirements at the same time. This is why I use
" ILLEGAL_UDP_GSO_CTX(gso_ctx) && ILLEGAL_TCP_GSO_CTX(gso_ctx))" as the exit
condition.

RTE_GSO_SEG_SIZE_MIN is not used to decide if input tunnel packets meet length
requirement, but just checks a min length. In fact, we cannot decide a real correct min
length for a packet type, since it may have vlan header or not. The original GSO code
leverages this macro for tunnel packets to do a minimal check, so I think we can keep it
here.

> 
> >
> 
> To make the macros above and their usage below clearer:
> 
> 1. I would change the || with &&. and == with !=
> 
> #define ILLEGAL_UDP_GSO_CTX(ctx) \
> 	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) != 0) && \
> 	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)

This macro doesn't check all conditions for illegal UDP GSO. For example,
if we input a UDP/IPv4 packet with setting gso_size to 1500 and without setting
DEV_TX_OFFLOAD_UDP_TSO in gso_types, this macro returns 0, which means
it's a legal UDP GSO packet.

If you mean we'd better use LEGAL rather than ILLEGAL as the check in the code,
the exit condition should be: 

#define LEGAL_UDP_GSO_CTX(ctx) \
	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) != 0) && \
	(ctx)->gso_size >= RTE_GSO_UDP_SEG_SIZE_MIN)

if (~(LEGAL_UDP_GSO_CTX(..) || LEGAL_TCP_GSO_CTX(..)))
	return -EINVAL;

But in fact, it's the same as current implementation. I can add some
explanations to the code for users to better understand the logic, if you
think it's OK.

> 
> #define ILLEGAL_TCP_GSO_CTX(ctx) \
> 	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
> 		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
> 		DEV_TX_OFFLOAD_GRE_TNL_TSO)) != 0) && \
> 		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
> 

Ditto.

> 2. Then later I would change the && with ||
> 
> Changing original:
> 			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
> 			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
> 
> With this:
> 			ILLEGAL_UDP_GSO_CTX(gso_ctx) ||
> 			 ILLEGAL_TCP_GSO_CTX(gso_ctx))

Ditto.

> 
> 
> >  int
> >  rte_gso_segment(struct rte_mbuf *pkt,
> > @@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
> >
> >  	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
> >  			nb_pkts_out < 1 ||
> > -			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
> > -			((gso_ctx->gso_types &
> > (DEV_TX_OFFLOAD_TCP_TSO |
> > -			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
> > -			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
> > +			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
> > +			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
> >  		return -EINVAL;
> >
> >  	if (gso_ctx->gso_size >= pkt->pkt_len) {
> > -		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
> > +		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
> >  		pkts_out[0] = pkt;
> >  		return 1;
> >  	}
> > @@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
> >  		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
> >  				direct_pool, indirect_pool,
> >  				pkts_out, nb_pkts_out);
> > +	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
> > +			(gso_ctx->gso_types &
> > DEV_TX_OFFLOAD_UDP_TSO)) {
> > +		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
> > +		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
> > +				indirect_pool, pkts_out, nb_pkts_out);
> >  	} else {
> >  		/* unsupported packet, skip */
> >  		pkts_out[0] = pkt;
> > diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h index
> > f4abd61..a626a11 100644
> > --- a/lib/librte_gso/rte_gso.h
> > +++ b/lib/librte_gso/rte_gso.h
> > @@ -17,10 +17,14 @@ extern "C" {
> >  #include <stdint.h>
> >  #include <rte_mbuf.h>
> >
> > -/* Minimum GSO segment size. */
> > +/* Minimum GSO segment size for TCP based packets. */
> >  #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
> >  		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)
> 
> RTE_GSO_SEG_SIZE_MIN is actually TCP min size. Can you name this macro
> as
> RTE_GSO_TCP_SEG_SIZE_MIN (symmetrically to the UDP macro below)?
> 

Yes, you are right. The name is not good. But I don't know if changing name
will introduce ABI change, so I select this name as a workaround.

Thanks,
Jiayu

> >
> > +/* Minimum GSO segment size for UDP based packets. */ #define
> > +RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
> > +		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
> > +
> >  /* GSO flags for rte_gso_ctx. */
> >  #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)  /**< Use fixed IP ids for
> > output GSO segments. Setting
> > --
> > 2.7.4

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

* Re: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation
  2018-06-27  2:28         ` Hu, Jiayu
@ 2018-06-27  5:05           ` Hu, Jiayu
  0 siblings, 0 replies; 27+ messages in thread
From: Hu, Jiayu @ 2018-06-27  5:05 UTC (permalink / raw)
  To: 'Ophir Munk', 'dev@dpdk.org'
  Cc: Wang, Xiao W, Ananyev, Konstantin, Zhang, Yuwei1, Iremonger,
	Bernard, 'Thomas Monjalon'



> -----Original Message-----
> From: Hu, Jiayu
> Sent: Wednesday, June 27, 2018 10:29 AM
> To: Ophir Munk <ophirmu@mellanox.com>; dev@dpdk.org
> Cc: Wang, Xiao W <xiao.w.wang@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> <yuwei1.zhang@intel.com>; Iremonger, Bernard
> <bernard.iremonger@intel.com>; Thomas Monjalon
> <thomas@monjalon.net>
> Subject: RE: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4
> fragmentation
> 
> Hi Ophir,
> 
> Replies are inline.
> 
> > -----Original Message-----
> > From: Ophir Munk [mailto:ophirmu@mellanox.com]
> > Sent: Wednesday, June 27, 2018 7:59 AM
> > To: Hu, Jiayu <jiayu.hu@intel.com>; dev@dpdk.org
> > Cc: Wang, Xiao W <xiao.w.wang@intel.com>; Ananyev, Konstantin
> > <konstantin.ananyev@intel.com>; Zhang, Yuwei1
> > <yuwei1.zhang@intel.com>; Iremonger, Bernard
> > <bernard.iremonger@intel.com>; Thomas Monjalon
> > <thomas@monjalon.net>
> > Subject: RE: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4
> > fragmentation
> >
> > Hi,
> > Please find some comments below.
> >
> > > -----Original Message-----
> > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jiayu Hu
> > > Sent: Friday, June 22, 2018 8:54 AM
> > > To: dev@dpdk.org
> > > Cc: xiao.w.wang@intel.com; konstantin.ananyev@intel.com;
> > > yuwei1.zhang@intel.com; bernard.iremonger@intel.com; Thomas
> > Monjalon
> > > <thomas@monjalon.net>; Jiayu Hu <jiayu.hu@intel.com>
> > > Subject: [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4
> fragmentation
> > >
> > > This patch adds GSO support for UDP/IPv4 packets. Supported packets
> > may
> > > include a single VLAN tag. UDP/IPv4 GSO doesn't check if input packets
> > have
> > > correct checksums, and doesn't update checksums for output packets
> (the
> > > responsibility for this lies with the application).
> > > Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.
> > >
> > > UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one
> indrect
> > > MBUF, to organize an output packet. The direct MBUF stores the packet
> > > header, while the indirect mbuf simply points to a location within the
> > original
> > > packet's payload. Consequently, use of UDP GSO requires multi-segment
> > > MBUF support in the TX functions of the NIC driver.
> > >
> > > If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
> > result,
> > > when all of its GSOed segments are freed, the packet is freed
> > automatically.
> > >
> > > Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
> > > ---
> > >  lib/librte_gso/Makefile     |  1 +
> > >  lib/librte_gso/gso_common.h |  3 ++
> > >  lib/librte_gso/gso_udp4.c   | 81
> > > +++++++++++++++++++++++++++++++++++++++++++++
> > >  lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
> > >  lib/librte_gso/meson.build  |  2 +-
> > >  lib/librte_gso/rte_gso.c    | 24 +++++++++++---
> > >  lib/librte_gso/rte_gso.h    |  6 +++-
> > >  7 files changed, 152 insertions(+), 7 deletions(-)  create mode 100644
> > > lib/librte_gso/gso_udp4.c  create mode 100644
> lib/librte_gso/gso_udp4.h
> > >
> > > diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile index
> > > 3648ec0..1fac53a 100644
> > > --- a/lib/librte_gso/Makefile
> > > +++ b/lib/librte_gso/Makefile
> > > @@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
> > >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
> > >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
> > >  SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
> > > +SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
> > >
> > >  # install this header file
> > >  SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h diff --git
> > > a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h index
> > > 5ca5974..6cd764f 100644
> > > --- a/lib/librte_gso/gso_common.h
> > > +++ b/lib/librte_gso/gso_common.h
> > > @@ -31,6 +31,9 @@
> > >  		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 |
> > \
> > >  		 PKT_TX_TUNNEL_GRE))
> > >
> > > +#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4))
> > ==
> > > \
> > > +		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
> > > +
> > >  /**
> > >   * Internal function which updates the UDP header of a packet,
> following
> > >   * segmentation. This is required to update the header's datagram
> length
> > > field.
> > > diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c new
> file
> > > mode 100644 index 0000000..927dee1
> > > --- /dev/null
> > > +++ b/lib/librte_gso/gso_udp4.c
> >
> > File gso_upd4.c could be very similar to file gso_tcp4.c and that would
> > avoid code duplication.
> > In a unified file you could use a tcp vs. udp flag to distinguish between
> them
> > when necessary.
> > The files are short (~75 lines) so it is not a critical issue.
> 
> The function gso_tcp4_segment and gso_udp4_segment have different
> prototype,
> and their GSO rules are different. They are two different basic GSO types.
> 
> The GSO library gives each GSO type (TCP, tunnel) an internal .c and .h file,
> and their name
> represents their content. The rte_gso_segment calls different function
> according to the GSO type.
> This style is very clear for developers or users to understand. In addition, as
> you said, the code
> is short. So I think it's better to keep this style for UDP/IPv4 GSO.
> 
> >
> > > @@ -0,0 +1,81 @@
> > > +/* SPDX-License-Identifier: BSD-3-Clause
> > > + * Copyright(c) 2018 Intel Corporation
> > > + */
> > > +
> > > +#include "gso_common.h"
> > > +#include "gso_udp4.h"
> > > +
> > > +#define IPV4_HDR_MF_BIT (1U << 13)
> > > +
> > > +static inline void
> > > +update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf
> **segs,
> > > +		uint16_t nb_segs)
> > > +{
> > > +	struct ipv4_hdr *ipv4_hdr;
> > > +	uint16_t frag_offset = 0, is_mf;
> > > +	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
> > > +	uint16_t tail_idx = nb_segs - 1, length, i;
> > > +
> > > +	/*
> > > +	 * Update IP header fields for output segments. Specifically,
> > > +	 * keep the same IP id, update fragment offset and total
> > > +	 * length.
> > > +	 */
> > > +	for (i = 0; i < nb_segs; i++) {
> > > +		ipv4_hdr = rte_pktmbuf_mtod_offset(segs[i], struct
> > ipv4_hdr
> > > *,
> > > +			l2_hdrlen);
> > > +		length = segs[i]->pkt_len - l2_hdrlen;
> > > +		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
> > > +
> > > +		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
> > > +		ipv4_hdr->fragment_offset =
> > > +			rte_cpu_to_be_16(frag_offset | is_mf);
> > > +		frag_offset += ((length - l3_hdrlen) >> 3);
> > > +	}
> > > +}
> > > +
> > > +int
> > > +gso_udp4_segment(struct rte_mbuf *pkt,
> > > +		uint16_t gso_size,
> > > +		struct rte_mempool *direct_pool,
> > > +		struct rte_mempool *indirect_pool,
> > > +		struct rte_mbuf **pkts_out,
> > > +		uint16_t nb_pkts_out)
> > > +{
> > > +	struct ipv4_hdr *ipv4_hdr;
> > > +	uint16_t pyld_unit_size, hdr_offset;
> > > +	uint16_t frag_off;
> > > +	int ret;
> > > +
> > > +	/* Don't process the fragmented packet */
> > > +	ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,
> > > +			pkt->l2_len);
> > > +	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
> > > +	if (unlikely(IS_FRAGMENTED(frag_off))) {
> > > +		pkts_out[0] = pkt;
> > > +		return 1;
> > > +	}
> > > +
> > > +	/*
> > > +	 * UDP fragmentation is the same as IP fragmentation.
> > > +	 * Except the first one, other output packets just have l2
> > > +	 * and l3 headers.
> > > +	 */
> > > +	hdr_offset = pkt->l2_len + pkt->l3_len;
> > > +
> > > +	/* Don't process the packet without data. */
> > > +	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
> > > +		pkts_out[0] = pkt;
> > > +		return 1;
> > > +	}
> > > +
> > > +	pyld_unit_size = gso_size - hdr_offset;
> > > +
> > > +	/* Segment the payload */
> > > +	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
> > > +			indirect_pool, pkts_out, nb_pkts_out);
> > > +	if (ret > 1)
> > > +		update_ipv4_udp_headers(pkt, pkts_out, ret);
> > > +
> > > +	return ret;
> > > +}
> > > diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h new
> file
> > > mode 100644 index 0000000..b2a2908
> >
> > File gso_upd4.h is almost identical to file gso_tcp4.h so both files
> (although
> > short ~40 lines) could have been unified into one file.
> 
> Ditto.
> 
> >
> > > --- /dev/null
> > > +++ b/lib/librte_gso/gso_udp4.h
> > > @@ -0,0 +1,42 @@
> > > +/* SPDX-License-Identifier: BSD-3-Clause
> > > + * Copyright(c) 2018 Intel Corporation
> > > + */
> > > +
> > > +#ifndef _GSO_UDP4_H_
> > > +#define _GSO_UDP4_H_
> > > +
> > > +#include <stdint.h>
> > > +#include <rte_mbuf.h>
> > > +
> > > +/**
> > > + * Segment an UDP/IPv4 packet. This function doesn't check if the
> input
> > > + * packet has correct checksums, and doesn't update checksums for
> > > +output
> > > + * GSO segments. Furthermore, it doesn't process IP fragment packets.
> > > + *
> > > + * @param pkt
> > > + *  The packet mbuf to segment.
> > > + * @param gso_size
> > > + *  The max length of a GSO segment, measured in bytes.
> > > + * @param direct_pool
> > > + *  MBUF pool used for allocating direct buffers for output segments.
> > > + * @param indirect_pool
> > > + *  MBUF pool used for allocating indirect buffers for output segments.
> > > + * @param pkts_out
> > > + *  Pointer array used to store the MBUF addresses of output GSO
> > > + *  segments, when the function succeeds. If the memory space in
> > > + *  pkts_out is insufficient, it fails and returns -EINVAL.
> > > + * @param nb_pkts_out
> > > + *  The max number of items that 'pkts_out' can keep.
> > > + *
> > > + * @return
> > > + *   - The number of GSO segments filled in pkts_out on success.
> > > + *   - Return -ENOMEM if run out of memory in MBUF pools.
> > > + *   - Return -EINVAL for invalid parameters.
> > > + */
> > > +int gso_udp4_segment(struct rte_mbuf *pkt,
> > > +		uint16_t gso_size,
> > > +		struct rte_mempool *direct_pool,
> > > +		struct rte_mempool *indirect_pool,
> > > +		struct rte_mbuf **pkts_out,
> > > +		uint16_t nb_pkts_out);
> > > +#endif
> > > diff --git a/lib/librte_gso/meson.build b/lib/librte_gso/meson.build
> index
> > > 056534f..ad8dd85 100644
> > > --- a/lib/librte_gso/meson.build
> > > +++ b/lib/librte_gso/meson.build
> > > @@ -1,7 +1,7 @@
> > >  # SPDX-License-Identifier: BSD-3-Clause  # Copyright(c) 2017 Intel
> > > Corporation
> > >
> > > -sources = files('gso_common.c', 'gso_tcp4.c',
> > > +sources = files('gso_common.c', 'gso_tcp4.c', 'gso_udp4.c',
> > >   		'gso_tunnel_tcp4.c', 'rte_gso.c')
> > >  headers = files('rte_gso.h')
> > >  deps += ['ethdev']
> > > diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c index
> > > a44e3d4..751b5b6 100644
> > > --- a/lib/librte_gso/rte_gso.c
> > > +++ b/lib/librte_gso/rte_gso.c
> > > @@ -11,6 +11,17 @@
> > >  #include "gso_common.h"
> > >  #include "gso_tcp4.h"
> > >  #include "gso_tunnel_tcp4.h"
> > > +#include "gso_udp4.h"
> > > +
> > > +#define ILLEGAL_UDP_GSO_CTX(ctx) \
> > > +	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
> > > +	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
> > > +
> > > +#define ILLEGAL_TCP_GSO_CTX(ctx) \
> > > +	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
> > > +		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
> > > +		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
> > > +		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
> >
> > Can you please explain why it is correct that the min len for VXLAN_TNL
> or
> > GRE_TNL is that of TCP MIN size (RTE_GSO_SEG_SIZE_MIN)
> 
> The logic here is a little complicated. First, we have two GSO types, i.e. TCP
> and UDP,
> and they have different requirements for min lengths and gso_types flags.
> In the code,
> we use ILLEGAL_UDP_GSO_CTX() and ILLEGAL_TCP_GSO_CTX() to check if
> the input packet
> doesn't meet the requirements. Rte_gso_segment() starts to process the
> input packet only
> when it meets UDP or TCP requirement. In other words, rte_gso_segment()
> stops if the
> packet doesn't meet both requirements at the same time. This is why I use
> " ILLEGAL_UDP_GSO_CTX(gso_ctx) && ILLEGAL_TCP_GSO_CTX(gso_ctx))"
> as the exit
> condition.
> 
> RTE_GSO_SEG_SIZE_MIN is not used to decide if input tunnel packets meet
> length
> requirement, but just checks a min length. In fact, we cannot decide a real
> correct min
> length for a packet type, since it may have vlan header or not. The original
> GSO code
> leverages this macro for tunnel packets to do a minimal check, so I think we
> can keep it
> here.
> 
> >
> > >
> >
> > To make the macros above and their usage below clearer:
> >
> > 1. I would change the || with &&. and == with !=
> >
> > #define ILLEGAL_UDP_GSO_CTX(ctx) \
> > 	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) != 0) && \
> > 	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
> 
> This macro doesn't check all conditions for illegal UDP GSO. For example,
> if we input a UDP/IPv4 packet with setting gso_size to 1500 and without
> setting
> DEV_TX_OFFLOAD_UDP_TSO in gso_types, this macro returns 0, which
> means
> it's a legal UDP GSO packet.
> 
> If you mean we'd better use LEGAL rather than ILLEGAL as the check in the
> code,
> the exit condition should be:
> 
> #define LEGAL_UDP_GSO_CTX(ctx) \
> 	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) != 0) && \
> 	(ctx)->gso_size >= RTE_GSO_UDP_SEG_SIZE_MIN)
> 
> if (~(LEGAL_UDP_GSO_CTX(..) || LEGAL_TCP_GSO_CTX(..)))
> 	return -EINVAL;
> 
> But in fact, it's the same as current implementation. I can add some
> explanations to the code for users to better understand the logic, if you
> think it's OK.
> 
> >
> > #define ILLEGAL_TCP_GSO_CTX(ctx) \
> > 	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
> > 		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
> > 		DEV_TX_OFFLOAD_GRE_TNL_TSO)) != 0) && \
> > 		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
> >
> 
> Ditto.
> 
> > 2. Then later I would change the && with ||
> >
> > Changing original:
> > 			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
> > 			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
> >
> > With this:
> > 			ILLEGAL_UDP_GSO_CTX(gso_ctx) ||
> > 			 ILLEGAL_TCP_GSO_CTX(gso_ctx))
> 
> Ditto.
> 
> >
> >
> > >  int
> > >  rte_gso_segment(struct rte_mbuf *pkt,
> > > @@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
> > >
> > >  	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
> > >  			nb_pkts_out < 1 ||
> > > -			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
> > > -			((gso_ctx->gso_types &
> > > (DEV_TX_OFFLOAD_TCP_TSO |
> > > -			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
> > > -			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
> > > +			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
> > > +			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
> > >  		return -EINVAL;
> > >
> > >  	if (gso_ctx->gso_size >= pkt->pkt_len) {
> > > -		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
> > > +		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
> > >  		pkts_out[0] = pkt;
> > >  		return 1;
> > >  	}
> > > @@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
> > >  		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
> > >  				direct_pool, indirect_pool,
> > >  				pkts_out, nb_pkts_out);
> > > +	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
> > > +			(gso_ctx->gso_types &
> > > DEV_TX_OFFLOAD_UDP_TSO)) {
> > > +		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
> > > +		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
> > > +				indirect_pool, pkts_out, nb_pkts_out);
> > >  	} else {
> > >  		/* unsupported packet, skip */
> > >  		pkts_out[0] = pkt;
> > > diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h index
> > > f4abd61..a626a11 100644
> > > --- a/lib/librte_gso/rte_gso.h
> > > +++ b/lib/librte_gso/rte_gso.h
> > > @@ -17,10 +17,14 @@ extern "C" {
> > >  #include <stdint.h>
> > >  #include <rte_mbuf.h>
> > >
> > > -/* Minimum GSO segment size. */
> > > +/* Minimum GSO segment size for TCP based packets. */
> > >  #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
> > >  		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)
> >
> > RTE_GSO_SEG_SIZE_MIN is actually TCP min size. Can you name this
> macro
> > as
> > RTE_GSO_TCP_SEG_SIZE_MIN (symmetrically to the UDP macro below)?
> >
> 
> Yes, you are right. The name is not good. But I don't know if changing name
> will introduce ABI change, so I select this name as a workaround.

Sorry, it will not cause ABI change but will influence the applications
which have already used the GSO library, if we rename RTE_GSO_SEG_SIZE_MIN.
This is because this macro is an external macro. From my perspective, I prefer to
 introduce a new macro for UDP based GSO, instead of renaming it.

Jiayu
> 
> Thanks,
> Jiayu
> 
> > >
> > > +/* Minimum GSO segment size for UDP based packets. */ #define
> > > +RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
> > > +		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
> > > +
> > >  /* GSO flags for rte_gso_ctx. */
> > >  #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)  /**< Use fixed IP ids
> for
> > > output GSO segments. Setting
> > > --
> > > 2.7.4

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

* [dpdk-dev] [PATCH v4 0/3] Support UDP/IPv4 GSO
  2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
                       ` (3 preceding siblings ...)
  2018-06-25  4:13     ` [dpdk-dev] [PATCH v3 0/3] Support " Wang, Xiao W
@ 2018-07-06  1:02     ` Jiayu Hu
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
                         ` (3 more replies)
  4 siblings, 4 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-07-06  1:02 UTC (permalink / raw)
  To: dev; +Cc: thomas, Jiayu Hu

With the support of UDP Fragmentation Offload (UFO) and TCP Segmentation
Offload (TSO) in virtio, VMs can exchange large UDP and TCP packets
exceeding MTU between each other, which can greatly reduce per-packet
processing overheads.

When the destination of the large TCP and UDP packets is crossing
machines, the host application needs to call two different libraries,
GSO and IP fragmentation, to split the large packets respectively.
However,the GSO and IP fragmentation library have quite different APIs,
which greatly complicates the host application implementation.

To simplify application development, we propose to support UDP/IPv4
fragmentation in the GSO library. With supporting UDP GSO, host
applicationss can use the unified APIs to split large UDP and TCP packets.

This patchset is to support UDP/IPv4 GSO. The first patch is to provide
UDP GSO function, the second patch is to enable UDP/IPv4 GSO in the
testpmd checksum forwarding engine, and the last patch is to update the
programmer guide and testpmd user guide.

Change log
==========
v4:
- update Acked-by and Tested-by information to commit log.
v3:
- replace rte_pktmbuf_mtod() with rte_pktmbuf_mtod_offset().
- fix meson build.
- add updates to document for better explaining how UDP GSO works.
V2:
- fix fragment offset calculation bug.
- add UDP GSO description in testpmd user guide.
- shorten the second patch name.

Jiayu Hu (3):
  gso: support UDP/IPv4 fragmentation
  app/testpmd: enable UDP GSO in csum engine
  gso: update documents for UDP/IPv4 GSO

 app/test-pmd/cmdline.c                             |  5 +-
 app/test-pmd/csumonly.c                            |  2 +
 app/test-pmd/testpmd.c                             |  2 +-
 .../generic_segmentation_offload_lib.rst           | 10 +++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst        |  7 ++
 lib/librte_gso/Makefile                            |  1 +
 lib/librte_gso/gso_common.h                        |  3 +
 lib/librte_gso/gso_udp4.c                          | 81 ++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h                          | 42 +++++++++++
 lib/librte_gso/meson.build                         |  2 +-
 lib/librte_gso/rte_gso.c                           | 24 +++++--
 lib/librte_gso/rte_gso.h                           |  6 +-
 12 files changed, 175 insertions(+), 10 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

-- 
2.7.4

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

* [dpdk-dev] [PATCH v4 1/3] gso: support UDP/IPv4 fragmentation
  2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
@ 2018-07-06  1:02       ` Jiayu Hu
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-07-06  1:02 UTC (permalink / raw)
  To: dev; +Cc: thomas, Jiayu Hu

This patch adds GSO support for UDP/IPv4 packets. Supported packets
may include a single VLAN tag. UDP/IPv4 GSO doesn't check if input
packets have correct checksums, and doesn't update checksums for
output packets (the responsibility for this lies with the application).
Additionally, UDP/IPv4 GSO doesn't process IP fragmented packets.

UDP/IPv4 GSO uses two chained MBUFs, one direct MBUF and one indrect
MBUF, to organize an output packet. The direct MBUF stores the packet
header, while the indirect mbuf simply points to a location within the
original packet's payload. Consequently, use of UDP GSO requires
multi-segment MBUF support in the TX functions of the NIC driver.

If a packet is GSO'd, UDP/IPv4 GSO reduces its MBUF refcnt by 1. As a
result, when all of its GSOed segments are freed, the packet is freed
automatically.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
Acked-by: Xiao Wang <xiao.w.wang@intel.com>
---
 lib/librte_gso/Makefile     |  1 +
 lib/librte_gso/gso_common.h |  3 ++
 lib/librte_gso/gso_udp4.c   | 81 +++++++++++++++++++++++++++++++++++++++++++++
 lib/librte_gso/gso_udp4.h   | 42 +++++++++++++++++++++++
 lib/librte_gso/meson.build  |  2 +-
 lib/librte_gso/rte_gso.c    | 24 +++++++++++---
 lib/librte_gso/rte_gso.h    |  6 +++-
 7 files changed, 152 insertions(+), 7 deletions(-)
 create mode 100644 lib/librte_gso/gso_udp4.c
 create mode 100644 lib/librte_gso/gso_udp4.h

diff --git a/lib/librte_gso/Makefile b/lib/librte_gso/Makefile
index 3648ec0..1fac53a 100644
--- a/lib/librte_gso/Makefile
+++ b/lib/librte_gso/Makefile
@@ -19,6 +19,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GSO) += rte_gso.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tcp4.c
 SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_tunnel_tcp4.c
+SRCS-$(CONFIG_RTE_LIBRTE_GSO) += gso_udp4.c
 
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_GSO)-include += rte_gso.h
diff --git a/lib/librte_gso/gso_common.h b/lib/librte_gso/gso_common.h
index 5ca5974..6cd764f 100644
--- a/lib/librte_gso/gso_common.h
+++ b/lib/librte_gso/gso_common.h
@@ -31,6 +31,9 @@
 		(PKT_TX_TCP_SEG | PKT_TX_IPV4 | PKT_TX_OUTER_IPV4 | \
 		 PKT_TX_TUNNEL_GRE))
 
+#define IS_IPV4_UDP(flag) (((flag) & (PKT_TX_UDP_SEG | PKT_TX_IPV4)) == \
+		(PKT_TX_UDP_SEG | PKT_TX_IPV4))
+
 /**
  * Internal function which updates the UDP header of a packet, following
  * segmentation. This is required to update the header's datagram length field.
diff --git a/lib/librte_gso/gso_udp4.c b/lib/librte_gso/gso_udp4.c
new file mode 100644
index 0000000..927dee1
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.c
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include "gso_common.h"
+#include "gso_udp4.h"
+
+#define IPV4_HDR_MF_BIT (1U << 13)
+
+static inline void
+update_ipv4_udp_headers(struct rte_mbuf *pkt, struct rte_mbuf **segs,
+		uint16_t nb_segs)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t frag_offset = 0, is_mf;
+	uint16_t l2_hdrlen = pkt->l2_len, l3_hdrlen = pkt->l3_len;
+	uint16_t tail_idx = nb_segs - 1, length, i;
+
+	/*
+	 * Update IP header fields for output segments. Specifically,
+	 * keep the same IP id, update fragment offset and total
+	 * length.
+	 */
+	for (i = 0; i < nb_segs; i++) {
+		ipv4_hdr = rte_pktmbuf_mtod_offset(segs[i], struct ipv4_hdr *,
+			l2_hdrlen);
+		length = segs[i]->pkt_len - l2_hdrlen;
+		ipv4_hdr->total_length = rte_cpu_to_be_16(length);
+
+		is_mf = i < tail_idx ? IPV4_HDR_MF_BIT : 0;
+		ipv4_hdr->fragment_offset =
+			rte_cpu_to_be_16(frag_offset | is_mf);
+		frag_offset += ((length - l3_hdrlen) >> 3);
+	}
+}
+
+int
+gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out)
+{
+	struct ipv4_hdr *ipv4_hdr;
+	uint16_t pyld_unit_size, hdr_offset;
+	uint16_t frag_off;
+	int ret;
+
+	/* Don't process the fragmented packet */
+	ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct ipv4_hdr *,
+			pkt->l2_len);
+	frag_off = rte_be_to_cpu_16(ipv4_hdr->fragment_offset);
+	if (unlikely(IS_FRAGMENTED(frag_off))) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	/*
+	 * UDP fragmentation is the same as IP fragmentation.
+	 * Except the first one, other output packets just have l2
+	 * and l3 headers.
+	 */
+	hdr_offset = pkt->l2_len + pkt->l3_len;
+
+	/* Don't process the packet without data. */
+	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
+		pkts_out[0] = pkt;
+		return 1;
+	}
+
+	pyld_unit_size = gso_size - hdr_offset;
+
+	/* Segment the payload */
+	ret = gso_do_segment(pkt, hdr_offset, pyld_unit_size, direct_pool,
+			indirect_pool, pkts_out, nb_pkts_out);
+	if (ret > 1)
+		update_ipv4_udp_headers(pkt, pkts_out, ret);
+
+	return ret;
+}
diff --git a/lib/librte_gso/gso_udp4.h b/lib/librte_gso/gso_udp4.h
new file mode 100644
index 0000000..b2a2908
--- /dev/null
+++ b/lib/librte_gso/gso_udp4.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef _GSO_UDP4_H_
+#define _GSO_UDP4_H_
+
+#include <stdint.h>
+#include <rte_mbuf.h>
+
+/**
+ * Segment an UDP/IPv4 packet. This function doesn't check if the input
+ * packet has correct checksums, and doesn't update checksums for output
+ * GSO segments. Furthermore, it doesn't process IP fragment packets.
+ *
+ * @param pkt
+ *  The packet mbuf to segment.
+ * @param gso_size
+ *  The max length of a GSO segment, measured in bytes.
+ * @param direct_pool
+ *  MBUF pool used for allocating direct buffers for output segments.
+ * @param indirect_pool
+ *  MBUF pool used for allocating indirect buffers for output segments.
+ * @param pkts_out
+ *  Pointer array used to store the MBUF addresses of output GSO
+ *  segments, when the function succeeds. If the memory space in
+ *  pkts_out is insufficient, it fails and returns -EINVAL.
+ * @param nb_pkts_out
+ *  The max number of items that 'pkts_out' can keep.
+ *
+ * @return
+ *   - The number of GSO segments filled in pkts_out on success.
+ *   - Return -ENOMEM if run out of memory in MBUF pools.
+ *   - Return -EINVAL for invalid parameters.
+ */
+int gso_udp4_segment(struct rte_mbuf *pkt,
+		uint16_t gso_size,
+		struct rte_mempool *direct_pool,
+		struct rte_mempool *indirect_pool,
+		struct rte_mbuf **pkts_out,
+		uint16_t nb_pkts_out);
+#endif
diff --git a/lib/librte_gso/meson.build b/lib/librte_gso/meson.build
index 056534f..ad8dd85 100644
--- a/lib/librte_gso/meson.build
+++ b/lib/librte_gso/meson.build
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-sources = files('gso_common.c', 'gso_tcp4.c',
+sources = files('gso_common.c', 'gso_tcp4.c', 'gso_udp4.c',
  		'gso_tunnel_tcp4.c', 'rte_gso.c')
 headers = files('rte_gso.h')
 deps += ['ethdev']
diff --git a/lib/librte_gso/rte_gso.c b/lib/librte_gso/rte_gso.c
index a44e3d4..751b5b6 100644
--- a/lib/librte_gso/rte_gso.c
+++ b/lib/librte_gso/rte_gso.c
@@ -11,6 +11,17 @@
 #include "gso_common.h"
 #include "gso_tcp4.h"
 #include "gso_tunnel_tcp4.h"
+#include "gso_udp4.h"
+
+#define ILLEGAL_UDP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & DEV_TX_OFFLOAD_UDP_TSO) == 0) || \
+	 (ctx)->gso_size < RTE_GSO_UDP_SEG_SIZE_MIN)
+
+#define ILLEGAL_TCP_GSO_CTX(ctx) \
+	((((ctx)->gso_types & (DEV_TX_OFFLOAD_TCP_TSO | \
+		DEV_TX_OFFLOAD_VXLAN_TNL_TSO | \
+		DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0) || \
+		(ctx)->gso_size < RTE_GSO_SEG_SIZE_MIN)
 
 int
 rte_gso_segment(struct rte_mbuf *pkt,
@@ -27,14 +38,12 @@ rte_gso_segment(struct rte_mbuf *pkt,
 
 	if (pkt == NULL || pkts_out == NULL || gso_ctx == NULL ||
 			nb_pkts_out < 1 ||
-			gso_ctx->gso_size < RTE_GSO_SEG_SIZE_MIN ||
-			((gso_ctx->gso_types & (DEV_TX_OFFLOAD_TCP_TSO |
-			DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-			DEV_TX_OFFLOAD_GRE_TNL_TSO)) == 0))
+			(ILLEGAL_UDP_GSO_CTX(gso_ctx) &&
+			 ILLEGAL_TCP_GSO_CTX(gso_ctx)))
 		return -EINVAL;
 
 	if (gso_ctx->gso_size >= pkt->pkt_len) {
-		pkt->ol_flags &= (~PKT_TX_TCP_SEG);
+		pkt->ol_flags &= (~(PKT_TX_TCP_SEG | PKT_TX_UDP_SEG));
 		pkts_out[0] = pkt;
 		return 1;
 	}
@@ -59,6 +68,11 @@ rte_gso_segment(struct rte_mbuf *pkt,
 		ret = gso_tcp4_segment(pkt, gso_size, ipid_delta,
 				direct_pool, indirect_pool,
 				pkts_out, nb_pkts_out);
+	} else if (IS_IPV4_UDP(pkt->ol_flags) &&
+			(gso_ctx->gso_types & DEV_TX_OFFLOAD_UDP_TSO)) {
+		pkt->ol_flags &= (~PKT_TX_UDP_SEG);
+		ret = gso_udp4_segment(pkt, gso_size, direct_pool,
+				indirect_pool, pkts_out, nb_pkts_out);
 	} else {
 		/* unsupported packet, skip */
 		pkts_out[0] = pkt;
diff --git a/lib/librte_gso/rte_gso.h b/lib/librte_gso/rte_gso.h
index f4abd61..a626a11 100644
--- a/lib/librte_gso/rte_gso.h
+++ b/lib/librte_gso/rte_gso.h
@@ -17,10 +17,14 @@ extern "C" {
 #include <stdint.h>
 #include <rte_mbuf.h>
 
-/* Minimum GSO segment size. */
+/* Minimum GSO segment size for TCP based packets. */
 #define RTE_GSO_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
 		sizeof(struct ipv4_hdr) + sizeof(struct tcp_hdr) + 1)
 
+/* Minimum GSO segment size for UDP based packets. */
+#define RTE_GSO_UDP_SEG_SIZE_MIN (sizeof(struct ether_hdr) + \
+		sizeof(struct ipv4_hdr) + sizeof(struct udp_hdr) + 1)
+
 /* GSO flags for rte_gso_ctx. */
 #define RTE_GSO_FLAG_IPID_FIXED (1ULL << 0)
 /**< Use fixed IP ids for output GSO segments. Setting
-- 
2.7.4

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

* [dpdk-dev] [PATCH v4 2/3] app/testpmd: enable UDP GSO in csum engine
  2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
@ 2018-07-06  1:02       ` Jiayu Hu
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
  2018-07-11 21:51       ` [dpdk-dev] [PATCH v4 0/3] Support " Thomas Monjalon
  3 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-07-06  1:02 UTC (permalink / raw)
  To: dev; +Cc: thomas, Jiayu Hu

This patch enables GSO for UDP/IPv4 packets. Oversized UDP/IPv4
packets transmitted over a GSO-enabled port will undergo segmentation.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
Acked-by: Xiao Wang <xiao.w.wang@intel.com>
Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>
Tested-by: Yuwei Zhang <yuwei1.zhang@intel.com>
---
 app/test-pmd/cmdline.c  | 5 +++--
 app/test-pmd/csumonly.c | 2 ++
 app/test-pmd/testpmd.c  | 2 +-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8..4239e91 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -4792,8 +4792,9 @@ cmd_gso_show_parsed(void *parsed_result,
 		if (gso_ports[res->cmd_pid].enable) {
 			printf("Max GSO'd packet size: %uB\n"
 					"Supported GSO types: TCP/IPv4, "
-					"VxLAN with inner TCP/IPv4 packet, "
-					"GRE with inner TCP/IPv4  packet\n",
+					"UDP/IPv4, VxLAN with inner "
+					"TCP/IPv4 packet, GRE with inner "
+					"TCP/IPv4 packet\n",
 					gso_max_segment_size);
 		} else
 			printf("GSO is not enabled on Port %u\n", res->cmd_pid);
diff --git a/app/test-pmd/csumonly.c b/app/test-pmd/csumonly.c
index 0bb88cf..4948292 100644
--- a/app/test-pmd/csumonly.c
+++ b/app/test-pmd/csumonly.c
@@ -411,6 +411,8 @@ process_inner_cksums(void *l3_hdr, const struct testpmd_offload_info *info,
 						info->ethertype);
 			}
 		}
+		if (info->gso_enable)
+			ol_flags |= PKT_TX_UDP_SEG;
 	} else if (info->l4_proto == IPPROTO_TCP) {
 		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
 		tcp_hdr->cksum = 0;
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 24c1998..fa9208d 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -777,7 +777,7 @@ init_config(void)
 	init_port_config();
 
 	gso_types = DEV_TX_OFFLOAD_TCP_TSO | DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
-		DEV_TX_OFFLOAD_GRE_TNL_TSO;
+		DEV_TX_OFFLOAD_GRE_TNL_TSO | DEV_TX_OFFLOAD_UDP_TSO;
 	/*
 	 * Records which Mbuf pool to use by each logical core, if needed.
 	 */
-- 
2.7.4

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

* [dpdk-dev] [PATCH v4 3/3] gso: update documents for UDP/IPv4 GSO
  2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
@ 2018-07-06  1:02       ` Jiayu Hu
  2018-07-11 21:51       ` [dpdk-dev] [PATCH v4 0/3] Support " Thomas Monjalon
  3 siblings, 0 replies; 27+ messages in thread
From: Jiayu Hu @ 2018-07-06  1:02 UTC (permalink / raw)
  To: dev; +Cc: thomas, Jiayu Hu

This patch updates the programmer guide and testpmd user guide for
UDP/IPv4 GSO.

Signed-off-by: Jiayu Hu <jiayu.hu@intel.com>
Acked-by: Xiao Wang <xiao.w.wang@intel.com>
---
 doc/guides/prog_guide/generic_segmentation_offload_lib.rst | 10 ++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst                |  7 +++++++
 2 files changed, 17 insertions(+)

diff --git a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
index 9959f0d..0cfc119 100644
--- a/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
+++ b/doc/guides/prog_guide/generic_segmentation_offload_lib.rst
@@ -43,6 +43,7 @@ Limitations
 #. Currently, the GSO library supports the following IPv4 packet types:
 
  - TCP
+ - UDP
  - VxLAN
  - GRE
 
@@ -146,6 +147,15 @@ TCP/IPv4 GSO
 TCP/IPv4 GSO supports segmentation of suitably large TCP/IPv4 packets, which
 may also contain an optional VLAN tag.
 
+UDP/IPv4 GSO
+~~~~~~~~~~~~
+UDP/IPv4 GSO supports segmentation of suitably large UDP/IPv4 packets, which
+may also contain an optional VLAN tag. UDP GSO is the same as IP fragmentation.
+Specifically, UDP GSO treats the UDP header as a part of the payload and
+does not modify it during segmentation. Therefore, after UDP GSO, only the
+first output packet has the original UDP header, and others just have l2
+and l3 headers.
+
 VxLAN GSO
 ~~~~~~~~~
 VxLAN packets GSO supports segmentation of suitably large VxLAN packets,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50..6f2de24 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1059,6 +1059,13 @@ By default, GSO is disabled for all ports.
 
    testpmd> csum set tcp hw <port_id>
 
+   UDP GSO is the same as IP fragmentation, which treats the UDP header
+   as the payload and does not modify it during segmentation. That is,
+   after UDP GSO, only the first output fragment has the original UDP
+   header. Therefore, users need to enable HW IP checksum calculation
+   and SW UDP checksum calculation for GSO-enabled ports, if they want
+   correct checksums for UDP/IPv4 packets.
+
 set gso segsz
 ~~~~~~~~~~~~~
 
-- 
2.7.4

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

* Re: [dpdk-dev] [PATCH v4 0/3] Support UDP/IPv4 GSO
  2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
                         ` (2 preceding siblings ...)
  2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
@ 2018-07-11 21:51       ` Thomas Monjalon
  3 siblings, 0 replies; 27+ messages in thread
From: Thomas Monjalon @ 2018-07-11 21:51 UTC (permalink / raw)
  To: Jiayu Hu; +Cc: dev

> Jiayu Hu (3):
>   gso: support UDP/IPv4 fragmentation
>   app/testpmd: enable UDP GSO in csum engine
>   gso: update documents for UDP/IPv4 GSO

Applied, thanks

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

end of thread, other threads:[~2018-07-11 21:51 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-29  7:41 [dpdk-dev] [PATCH 0/3] Support UDP/IPv4 GSO Jiayu Hu
2018-05-29  7:41 ` [dpdk-dev] [PATCH 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
2018-05-29  7:41 ` [dpdk-dev] [PATCH 2/3] app/testpmd: enable UDP GSO in the checksum forwarding engine Jiayu Hu
2018-06-14 14:44   ` Iremonger, Bernard
2018-06-16  9:14     ` Hu, Jiayu
2018-05-29  7:41 ` [dpdk-dev] [PATCH 3/3] gso: add UDP/IPv4 GSO to the programmer guide Jiayu Hu
2018-06-27  1:59   ` Zhang, Yuwei1
2018-06-17  3:13 ` [dpdk-dev] [PATCH v2 0/3] Support UDP/IPv4 GSO Jiayu Hu
2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
2018-06-21  8:24     ` Wang, Xiao W
2018-06-21  8:26       ` Hu, Jiayu
2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
2018-06-26  9:46     ` Iremonger, Bernard
2018-06-17  3:13   ` [dpdk-dev] [PATCH v2 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
2018-06-22  5:54   ` [dpdk-dev] [PATCH v3 0/3] Support " Jiayu Hu
2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
2018-06-26 23:58       ` Ophir Munk
2018-06-27  2:28         ` Hu, Jiayu
2018-06-27  5:05           ` Hu, Jiayu
2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
2018-06-22  5:54     ` [dpdk-dev] [PATCH v3 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
2018-06-25  4:13     ` [dpdk-dev] [PATCH v3 0/3] Support " Wang, Xiao W
2018-07-06  1:02     ` [dpdk-dev] [PATCH v4 " Jiayu Hu
2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 1/3] gso: support UDP/IPv4 fragmentation Jiayu Hu
2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 2/3] app/testpmd: enable UDP GSO in csum engine Jiayu Hu
2018-07-06  1:02       ` [dpdk-dev] [PATCH v4 3/3] gso: update documents for UDP/IPv4 GSO Jiayu Hu
2018-07-11 21:51       ` [dpdk-dev] [PATCH v4 0/3] Support " Thomas Monjalon

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