DPDK patches and discussions
 help / color / mirror / Atom feed
From: Allain Legacy <allain.legacy@windriver.com>
To: <konstantin.ananyev@intel.com>
Cc: <dev@dpdk.org>
Subject: [dpdk-dev] [PATCH] ip_frag: handle MTU sizes not aligned to 8 bytes
Date: Tue, 14 Mar 2017 11:14:47 -0400	[thread overview]
Message-ID: <1489504487-67456-1-git-send-email-allain.legacy@windriver.com> (raw)

The rte_ipv4_fragment_packet API expects that the link/interface MTU value
passed in be divisible by 8 bytes.  Given the name of the parameter is
"mtu" rather than "frag_size" it is not necessarily the case that it will
be divisible by 8.  An MTU of 1500 happens to produce a max fragment size
of 1480 (1500 - sizeof(ipv4_hdr)) which is divisible by 8 but other MTU
values such as 1600 or 9000 do not produce values that are divisible by 8.

Unfortunately, the API checks that the frag_size value produced is
divisible by 8 with a call to RTE_ASSERT which is only enabled when the
RTE_LOG_LEVEL >= RTE_LOG_DEBUG.  In cases where the log level is set
normally the code silently continues and produces IP fragments that have
invalid fragment offset values.

An application may not have control over what MTU a user selects and rather
than have each application adjust the MTU to pass a suitable value to the
fragmentation API this change modifies the fragmentation API to handle
cases where the "mtu" argument is not divisible by 8 and automatically
adjust the internal "frag_size".

Signed-off-by: Allain Legacy <allain.legacy@windriver.com>
---
 lib/librte_ip_frag/rte_ipv4_fragmentation.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/lib/librte_ip_frag/rte_ipv4_fragmentation.c b/lib/librte_ip_frag/rte_ipv4_fragmentation.c
index a2259e8..8c5f5ec 100644
--- a/lib/librte_ip_frag/rte_ipv4_fragmentation.c
+++ b/lib/librte_ip_frag/rte_ipv4_fragmentation.c
@@ -48,7 +48,7 @@
 #define	IPV4_HDR_DF_MASK			(1 << IPV4_HDR_DF_SHIFT)
 #define	IPV4_HDR_MF_MASK			(1 << IPV4_HDR_MF_SHIFT)
 
-#define	IPV4_HDR_FO_MASK			((1 << IPV4_HDR_FO_SHIFT) - 1)
+#define	IPV4_HDR_FO_ALIGN			(1 << IPV4_HDR_FO_SHIFT)
 
 static inline void __fill_ipv4hdr_frag(struct ipv4_hdr *dst,
 		const struct ipv4_hdr *src, uint16_t len, uint16_t fofs,
@@ -103,11 +103,14 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)
 	uint32_t out_pkt_pos, in_seg_data_pos;
 	uint32_t more_in_segs;
 	uint16_t fragment_offset, flag_offset, frag_size;
+	uint16_t frag_bytes_remaining;
 
-	frag_size = (uint16_t)(mtu_size - sizeof(struct ipv4_hdr));
-
-	/* Fragment size should be a multiply of 8. */
-	RTE_ASSERT((frag_size & IPV4_HDR_FO_MASK) == 0);
+	/*
+	 * Ensure the IP payload length of all fragments is aligned to a
+	 * multiple of 8 bytes as per RFC791 section 2.3.
+	 */
+	frag_size = RTE_ALIGN_FLOOR((mtu_size - sizeof(struct ipv4_hdr)),
+				    IPV4_HDR_FO_ALIGN);
 
 	in_hdr = rte_pktmbuf_mtod(pkt_in, struct ipv4_hdr *);
 	flag_offset = rte_cpu_to_be_16(in_hdr->fragment_offset);
@@ -142,6 +145,7 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)
 		/* Reserve space for the IP header that will be built later */
 		out_pkt->data_len = sizeof(struct ipv4_hdr);
 		out_pkt->pkt_len = sizeof(struct ipv4_hdr);
+		frag_bytes_remaining = frag_size;
 
 		out_seg_prev = out_pkt;
 		more_out_segs = 1;
@@ -161,7 +165,7 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)
 
 			/* Prepare indirect buffer */
 			rte_pktmbuf_attach(out_seg, in_seg);
-			len = mtu_size - out_pkt->pkt_len;
+			len = frag_bytes_remaining;
 			if (len > (in_seg->data_len - in_seg_data_pos)) {
 				len = in_seg->data_len - in_seg_data_pos;
 			}
@@ -171,9 +175,10 @@ static inline void __free_fragments(struct rte_mbuf *mb[], uint32_t num)
 			    out_pkt->pkt_len);
 			out_pkt->nb_segs += 1;
 			in_seg_data_pos += len;
+			frag_bytes_remaining -= len;
 
 			/* Current output packet (i.e. fragment) done ? */
-			if (unlikely(out_pkt->pkt_len >= mtu_size))
+			if (unlikely(frag_bytes_remaining == 0))
 				more_out_segs = 0;
 
 			/* Current input segment done ? */
-- 
1.8.3.1

             reply	other threads:[~2017-03-14 15:14 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-14 15:14 Allain Legacy [this message]
2017-06-04 16:55 ` [dpdk-dev] " Ananyev, Konstantin
2017-06-22 16:00   ` Thomas Monjalon

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=1489504487-67456-1-git-send-email-allain.legacy@windriver.com \
    --to=allain.legacy@windriver.com \
    --cc=dev@dpdk.org \
    --cc=konstantin.ananyev@intel.com \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).