diff mbox

[ovs-dev,v6,4/5] datapath-windows: Updated OvsTcpSegmentNBL to handle IP fragments.

Message ID 20170324205117.8524-5-kumaranand@vmware.com
State Superseded
Headers show

Commit Message

Anand Kumar March 24, 2017, 8:51 p.m. UTC
With this patch, OvsTcpSegmentNBL not only supports fragmenting NBL
to TCP segments but also Ipv4 fragments.

To reflect the new changes, renamed function name from OvsTcpSegmentNBL
to OvsFragmentNBL and created a wrapper for OvsTcpSegmentNBL.

Signed-off-by: Anand Kumar <kumaranand@vmware.com>
---
v5->v6: No Change
v4->v5: Changed a variable mss to fragmentSize.
v3->v4: No Change
v2->v3:
	- Updated log message and function summary
v1->v2:
	- Fix compile error for release mode.
---
 datapath-windows/ovsext/BufferMgmt.c | 194 +++++++++++++++++++++++++----------
 datapath-windows/ovsext/BufferMgmt.h |  10 +-
 datapath-windows/ovsext/Geneve.c     |   2 +-
 datapath-windows/ovsext/Gre.c        |   2 +-
 datapath-windows/ovsext/Stt.c        |   2 +-
 datapath-windows/ovsext/User.c       |   2 +-
 datapath-windows/ovsext/Vxlan.c      |   2 +-
 7 files changed, 152 insertions(+), 62 deletions(-)

Comments

Sairam Venugopal April 6, 2017, 4:57 p.m. UTC | #1
Acked-by: Sairam Venugopal <vsairam@vmware.com>





On 3/24/17, 1:51 PM, "ovs-dev-bounces@openvswitch.org on behalf of Anand Kumar" <ovs-dev-bounces@openvswitch.org on behalf of kumaranand@vmware.com> wrote:

>With this patch, OvsTcpSegmentNBL not only supports fragmenting NBL
>to TCP segments but also Ipv4 fragments.
>
>To reflect the new changes, renamed function name from OvsTcpSegmentNBL
>to OvsFragmentNBL and created a wrapper for OvsTcpSegmentNBL.
>
>Signed-off-by: Anand Kumar <kumaranand@vmware.com>
>---
>v5->v6: No Change
>v4->v5: Changed a variable mss to fragmentSize.
>v3->v4: No Change
>v2->v3:
>	- Updated log message and function summary
>v1->v2:
>	- Fix compile error for release mode.
>---
> datapath-windows/ovsext/BufferMgmt.c | 194 +++++++++++++++++++++++++----------
> datapath-windows/ovsext/BufferMgmt.h |  10 +-
> datapath-windows/ovsext/Geneve.c     |   2 +-
> datapath-windows/ovsext/Gre.c        |   2 +-
> datapath-windows/ovsext/Stt.c        |   2 +-
> datapath-windows/ovsext/User.c       |   2 +-
> datapath-windows/ovsext/Vxlan.c      |   2 +-
> 7 files changed, 152 insertions(+), 62 deletions(-)
>
>diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c
>index d99052d..0011c10 100644
>--- a/datapath-windows/ovsext/BufferMgmt.c
>+++ b/datapath-windows/ovsext/BufferMgmt.c
>@@ -1084,6 +1084,31 @@ nblcopy_error:
>     return NULL;
> }
> 
>+NDIS_STATUS
>+GetIpHeaderInfo(PNET_BUFFER_LIST curNbl,
>+                UINT32 *hdrSize)
>+{
>+    CHAR *ethBuf[sizeof(EthHdr)];
>+    EthHdr *eth;
>+    IPHdr *ipHdr;
>+    PNET_BUFFER curNb;
>+
>+    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
>+    ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
>+
>+    eth = (EthHdr *)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH,
>+                                      (PVOID)&ethBuf, 1, 0);
>+    if (eth == NULL) {
>+        return NDIS_STATUS_INVALID_PACKET;
>+    }
>+    ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH);
>+    if (ipHdr == NULL) {
>+        return NDIS_STATUS_INVALID_PACKET;
>+    }
>+    *hdrSize = (UINT32)(ETH_HEADER_LENGTH + (ipHdr->ihl * 4));
>+    return NDIS_STATUS_SUCCESS;
>+}
>+
> /*
>  * --------------------------------------------------------------------------
>  * GetSegmentHeaderInfo
>@@ -1113,15 +1138,16 @@ GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
> 
> /*
>  * --------------------------------------------------------------------------
>- * FixSegmentHeader
>+ * FixPacketHeader
>  *
>- *    Fix IP length, IP checksum, TCP sequence number and TCP checksum
>- *    in the segment.
>+ *    Fix IP length, Offset, IP checksum, TCP sequence number and TCP checksum
>+ *    in the netbuffer if applicable.
>  * --------------------------------------------------------------------------
>  */
> static NDIS_STATUS
>-FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
>-                 BOOLEAN lastPacket, UINT16 packetCounter)
>+FixPacketHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
>+                BOOLEAN lastPacket, UINT16 packetCounter, UINT16 offset,
>+                BOOLEAN isFragment)
> {
>     EthHdr *dstEth = NULL;
>     TCPHdr *dstTCP = NULL;
>@@ -1140,41 +1166,55 @@ FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
>     case ETH_TYPE_IPV4_NBO:
>     {
>         IPHdr *dstIP = NULL;
>-
>-        ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
>+        if (!isFragment) {
>+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
>                 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
>-        dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
>-        dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
>-        ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
>+            dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
>+            dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
>+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
>                 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
> 
>-        /* Fix IP length and checksum */
>-        ASSERT(dstIP->protocol == IPPROTO_TCP);
>-        dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
>-        dstIP->id += packetCounter;
>+            /* Fix IP length and checksum */
>+            ASSERT(dstIP->protocol == IPPROTO_TCP);
>+            dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
>+            dstIP->id += packetCounter;
>+            dstTCP->seq = htonl(seqNumber);
>+
>+            /*
>+             * Set the TCP FIN and PSH bit only for the last packet
>+             * More information can be found under:
>+             * https://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en-2Dus_library_windows_hardware_ff568840-2528v-3Dvs.85-2529.aspx&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=pPaSVPWdJHWOLbOlgin3udisf19xvEAzICVuCAqHxxI&s=LF-JRd87lSW9A3BlaL_LmO1I0ZQ2vekutezo9LaQqLU&e= 
>+             */
>+            if (dstTCP->fin) {
>+                dstTCP->fin = lastPacket;
>+            }
>+            if (dstTCP->psh) {
>+                dstTCP->psh = lastPacket;
>+            }
>+            UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
>+            dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
>+                                             &dstIP->daddr,
>+                                             IPPROTO_TCP,
>+                                             csumLength);
>+            dstTCP->check = CalculateChecksumNB(nb,
>+                                                csumLength,
>+                                                sizeof(*dstEth) + dstIP->ihl * 4);
>+        } else {
>+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
>+                >= sizeof(EthHdr) + sizeof(IPHdr));
>+
>+            dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
>+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
>+                >= sizeof(EthHdr) + dstIP->ihl * 4);
>+            dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4);
>+            if (lastPacket) {
>+                dstIP->frag_off = htons(offset & IP_OFFSET);
>+            } else {
>+                dstIP->frag_off = htons((offset & IP_OFFSET) | IP_MF);
>+            }
>+        }
>         dstIP->check = 0;
>         dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
>-        dstTCP->seq = htonl(seqNumber);
>-
>-        /*
>-         * Set the TCP FIN and PSH bit only for the last packet
>-         * More information can be found under:
>-         * https://urldefense.proofpoint.com/v2/url?u=https-3A__msdn.microsoft.com_en-2Dus_library_windows_hardware_ff568840-2528v-3Dvs.85-2529.aspx&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=pPaSVPWdJHWOLbOlgin3udisf19xvEAzICVuCAqHxxI&s=LF-JRd87lSW9A3BlaL_LmO1I0ZQ2vekutezo9LaQqLU&e= 
>-         */
>-        if (dstTCP->fin) {
>-            dstTCP->fin = lastPacket;
>-        }
>-        if (dstTCP->psh) {
>-            dstTCP->psh = lastPacket;
>-        }
>-        UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
>-        dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
>-                                         &dstIP->daddr,
>-                                         IPPROTO_TCP,
>-                                         csumLength);
>-        dstTCP->check = CalculateChecksumNB(nb,
>-                                            csumLength,
>-                                            sizeof(*dstEth) + dstIP->ihl * 4);
>         break;
>     }
>     case ETH_TYPE_IPV6_NBO:
>@@ -1218,11 +1258,29 @@ FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
>     return STATUS_SUCCESS;
> }
> 
>+ /*
>+  * --------------------------------------------------------------------------
>+ * OvsTcpSegmentNBL --
>+ *      Wrapper function to Fragment a given NBL based on MSS
>+ * --------------------------------------------------------------------------
>+ */
>+PNET_BUFFER_LIST
>+OvsTcpSegmentNBL(PVOID ovsContext,
>+                 PNET_BUFFER_LIST nbl,
>+                 POVS_PACKET_HDR_INFO hdrInfo,
>+                 UINT32 mss,
>+                 UINT32 headRoom,
>+                 BOOLEAN isIpFragment)
>+{
>+    return OvsFragmentNBL(ovsContext, nbl, hdrInfo, mss, headRoom, isIpFragment);
>+}
>+
>+
> /*
>  * --------------------------------------------------------------------------
>- * OvsTcpSegmentNBL --
>+ * OvsFragmentNBL --
>  *
>- *    Segment TCP payload, and prepend each segment with ether/IP/TCP header.
>+ *    Fragment NBL payload, and prepend each segment with either/IP/TCP header.
>  *    Leave headRoom for additional encap.
>  *
>  *    Please note,
>@@ -1235,24 +1293,25 @@ FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
>  * --------------------------------------------------------------------------
>  */
> PNET_BUFFER_LIST
>-OvsTcpSegmentNBL(PVOID ovsContext,
>-                 PNET_BUFFER_LIST nbl,
>-                 POVS_PACKET_HDR_INFO hdrInfo,
>-                 UINT32 mss,
>-                 UINT32 headRoom)
>+OvsFragmentNBL(PVOID ovsContext,
>+               PNET_BUFFER_LIST nbl,
>+               POVS_PACKET_HDR_INFO hdrInfo,
>+               UINT32 fragmentSize,
>+               UINT32 headRoom,
>+               BOOLEAN isIpFragment)
> {
>     POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
> #ifdef DBG
>     POVS_NBL_POOL ovsPool = &context->ovsPool;
> #endif
>     POVS_BUFFER_CONTEXT dstCtx, srcCtx;
>-    UINT32 size, hdrSize, seqNumber;
>+    UINT32 size, hdrSize, nblSize, seqNumber = 0;
>     PNET_BUFFER_LIST newNbl;
>     PNET_BUFFER nb, newNb;
>     NDIS_STATUS status;
>     UINT16 segmentSize;
>     ULONG copiedSize;
>-    UINT16 packetCounter = 0;
>+    UINT16 offset = 0, packetCounter = 0;
> 
>     srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
>     if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
>@@ -1264,18 +1323,28 @@ OvsTcpSegmentNBL(PVOID ovsContext,
>     nb = NET_BUFFER_LIST_FIRST_NB(nbl);
>     ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
> 
>-    /* Figure out the segment header size */
>-    status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
>+    /* Figure out the header size */
>+    if (isIpFragment) {
>+        status = GetIpHeaderInfo(nbl, &hdrSize);
>+    } else {
>+        status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
>+    }
>     if (status != NDIS_STATUS_SUCCESS) {
>         OVS_LOG_INFO("Cannot parse NBL header");
>         return NULL;
>     }
>-
>+    /* Get the NBL size. */
>+    if (isIpFragment) {
>+        nblSize = fragmentSize - hdrSize;
>+    } else {
>+        nblSize = fragmentSize;
>+    }
>     size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
> 
>     /* XXX add to ovsPool counters? */
>-    newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL,
>-            NULL, hdrSize, mss, hdrSize + headRoom , 0, 0);
>+    newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
>+                                               nblSize, hdrSize + headRoom ,
>+                                               0, 0);
>     if (newNbl == NULL) {
>         return NULL;
>     }
>@@ -1283,7 +1352,7 @@ OvsTcpSegmentNBL(PVOID ovsContext,
>     /* Now deal with TCP payload */
>     for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
>             newNb = NET_BUFFER_NEXT_NB(newNb)) {
>-        segmentSize = (size > mss ? mss : size) & 0xffff;
>+        segmentSize = (size > nblSize ? nblSize : size) & 0xffff;
>         if (headRoom) {
>             NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
>         }
>@@ -1295,17 +1364,21 @@ OvsTcpSegmentNBL(PVOID ovsContext,
>             goto nblcopy_error;
>         }
> 
>-        status = FixSegmentHeader(newNb, segmentSize, seqNumber,
>-                                  NET_BUFFER_NEXT_NB(newNb) == NULL,
>-                                  packetCounter);
>+        status = FixPacketHeader(newNb, segmentSize, seqNumber,
>+                                 NET_BUFFER_NEXT_NB(newNb) == NULL,
>+                                 packetCounter, offset, isIpFragment);
>+
>         if (status != NDIS_STATUS_SUCCESS) {
>             goto nblcopy_error;
>         }
> 
>-
>         /* Move on to the next segment */
>+        if (isIpFragment) {
>+            offset += (segmentSize) / 8;
>+        } else {
>+            seqNumber += segmentSize;
>+        }
>         size -= segmentSize;
>-        seqNumber += segmentSize;
>         packetCounter++;
>     }
> 
>@@ -1319,6 +1392,15 @@ OvsTcpSegmentNBL(PVOID ovsContext,
>         goto nbl_context_error;
>     }
> 
>+    if (isIpFragment) {
>+        /* Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS. */
>+        status = context->NdisSwitchHandlers.
>+            CopyNetBufferListInfo(context->ovsPool.ndisContext, newNbl, nbl, 1);
>+
>+        if (status != NDIS_STATUS_SUCCESS) {
>+            goto nbl_context_error;
>+        }
>+    }
>     newNbl->ParentNetBufferList = nbl;
> 
>     /* Remember it's a fragment NBL so we can free it properly */
>@@ -1340,7 +1422,7 @@ OvsTcpSegmentNBL(PVOID ovsContext,
>     OvsDumpNetBufferList(newNbl);
>     OvsDumpForwardingDetails(newNbl);
> #endif
>-    OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl);
>+    OVS_LOG_TRACE("Fragmnet nbl %p to newNbl: %p", nbl, newNbl);
>     return newNbl;
> 
> nbl_context_error:
>diff --git a/datapath-windows/ovsext/BufferMgmt.h b/datapath-windows/ovsext/BufferMgmt.h
>index 77b2854..52fe532 100644
>--- a/datapath-windows/ovsext/BufferMgmt.h
>+++ b/datapath-windows/ovsext/BufferMgmt.h
>@@ -116,7 +116,15 @@ PNET_BUFFER_LIST OvsTcpSegmentNBL(PVOID context,
>                                   PNET_BUFFER_LIST nbl,
>                                   POVS_PACKET_HDR_INFO hdrInfo,
>                                   UINT32 MSS,
>-                                  UINT32 headRoom);
>+                                  UINT32 headRoom,
>+                                  BOOLEAN isIpFragment);
>+
>+PNET_BUFFER_LIST OvsFragmentNBL(PVOID context,
>+                                PNET_BUFFER_LIST nbl,
>+                                POVS_PACKET_HDR_INFO hdrInfo,
>+                                UINT32 MSS,
>+                                UINT32 headRoom,
>+                                BOOLEAN isIpFragment);
> 
> PNET_BUFFER_LIST OvsAllocateNBLFromBuffer(PVOID context,
>                                           PVOID buffer,
>diff --git a/datapath-windows/ovsext/Geneve.c b/datapath-windows/ovsext/Geneve.c
>index 1938aaa..43374e2 100644
>--- a/datapath-windows/ovsext/Geneve.c
>+++ b/datapath-windows/ovsext/Geneve.c
>@@ -118,7 +118,7 @@ NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
>         if (mss) {
>             OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
>             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
>-                                       mss, headRoom);
>+                                       mss, headRoom, FALSE);
>             if (*newNbl == NULL) {
>                 OVS_LOG_ERROR("Unable to segment NBL");
>                 return NDIS_STATUS_FAILURE;
>diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
>index c5da064..f095742 100644
>--- a/datapath-windows/ovsext/Gre.c
>+++ b/datapath-windows/ovsext/Gre.c
>@@ -158,7 +158,7 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport,
>         if (mss) {
>             OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
>             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
>-                                       mss, headRoom);
>+                                       mss, headRoom, FALSE);
>             if (*newNbl == NULL) {
>                 OVS_LOG_ERROR("Unable to segment NBL");
>                 return NDIS_STATUS_FAILURE;
>diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c
>index 5aa8652..1f36835 100644
>--- a/datapath-windows/ovsext/Stt.c
>+++ b/datapath-windows/ovsext/Stt.c
>@@ -185,7 +185,7 @@ OvsDoEncapStt(POVS_VPORT_ENTRY vport,
>         if ((innerFrameLen > OVS_MAX_STT_PACKET_LENGTH) ||
>             (layers->l4Offset > OVS_MAX_STT_L4_OFFSET_LENGTH)) {
>             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
>-                mss - headRoom, headRoom);
>+                                       mss - headRoom, headRoom, FALSE);
>             if (*newNbl == NULL) {
>                 OVS_LOG_ERROR("Unable to segment NBL");
>                 return NDIS_STATUS_FAILURE;
>diff --git a/datapath-windows/ovsext/User.c b/datapath-windows/ovsext/User.c
>index 3154640..7880220 100644
>--- a/datapath-windows/ovsext/User.c
>+++ b/datapath-windows/ovsext/User.c
>@@ -787,7 +787,7 @@ OvsCreateAndAddPackets(PVOID userData,
>         if (tsoInfo.LsoV1Transmit.MSS) {
>             OVS_LOG_TRACE("l4Offset %d", hdrInfo->l4Offset);
>             newNbl = OvsTcpSegmentNBL(switchContext, nbl, hdrInfo,
>-                    tsoInfo.LsoV1Transmit.MSS , 0);
>+                                      tsoInfo.LsoV1Transmit.MSS , 0, FALSE);
>             if (newNbl == NULL) {
>                 return NDIS_STATUS_FAILURE;
>             }
>diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
>index 84c2f2f..427f31c 100644
>--- a/datapath-windows/ovsext/Vxlan.c
>+++ b/datapath-windows/ovsext/Vxlan.c
>@@ -205,7 +205,7 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
>         if (mss) {
>             OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
>             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
>-                                       mss, headRoom);
>+                                       mss, headRoom, FALSE);
>             if (*newNbl == NULL) {
>                 OVS_LOG_ERROR("Unable to segment NBL");
>                 return NDIS_STATUS_FAILURE;
>-- 
>2.9.3.windows.1
>
>_______________________________________________
>dev mailing list
>dev@openvswitch.org
>https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_mailman_listinfo_ovs-2Ddev&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=Z6vowHUOjP5ysP_g372c49Nqc1vEKqHKNBkR5Q5Z7uo&m=pPaSVPWdJHWOLbOlgin3udisf19xvEAzICVuCAqHxxI&s=D5d7pARzyomYCQ-d30i7roGlgM3nOANyAc63qeEoQ0g&e=
Alin Serdean April 7, 2017, 2:24 a.m. UTC | #2
Since you split the functionality on `BOOLEAN isFragment` mind just creating new function and leaving FixSegmentHeader as is. I think it would look much cleaner.

Thanks,
Alin.

> -----Original Message-----
> From: ovs-dev-bounces@openvswitch.org [mailto:ovs-dev-
> bounces@openvswitch.org] On Behalf Of Anand Kumar
> Sent: Friday, March 24, 2017 10:51 PM
> To: dev@openvswitch.org
> Subject: [ovs-dev] [PATCH v6 4/5] datapath-windows: Updated
> OvsTcpSegmentNBL to handle IP fragments.
> 
> With this patch, OvsTcpSegmentNBL not only supports fragmenting NBL to
> TCP segments but also Ipv4 fragments.
> 
> To reflect the new changes, renamed function name from
> OvsTcpSegmentNBL to OvsFragmentNBL and created a wrapper for
> OvsTcpSegmentNBL.
> 
> Signed-off-by: Anand Kumar <kumaranand@vmware.com>
diff mbox

Patch

diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c
index d99052d..0011c10 100644
--- a/datapath-windows/ovsext/BufferMgmt.c
+++ b/datapath-windows/ovsext/BufferMgmt.c
@@ -1084,6 +1084,31 @@  nblcopy_error:
     return NULL;
 }
 
+NDIS_STATUS
+GetIpHeaderInfo(PNET_BUFFER_LIST curNbl,
+                UINT32 *hdrSize)
+{
+    CHAR *ethBuf[sizeof(EthHdr)];
+    EthHdr *eth;
+    IPHdr *ipHdr;
+    PNET_BUFFER curNb;
+
+    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
+    ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
+
+    eth = (EthHdr *)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH,
+                                      (PVOID)&ethBuf, 1, 0);
+    if (eth == NULL) {
+        return NDIS_STATUS_INVALID_PACKET;
+    }
+    ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH);
+    if (ipHdr == NULL) {
+        return NDIS_STATUS_INVALID_PACKET;
+    }
+    *hdrSize = (UINT32)(ETH_HEADER_LENGTH + (ipHdr->ihl * 4));
+    return NDIS_STATUS_SUCCESS;
+}
+
 /*
  * --------------------------------------------------------------------------
  * GetSegmentHeaderInfo
@@ -1113,15 +1138,16 @@  GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
 
 /*
  * --------------------------------------------------------------------------
- * FixSegmentHeader
+ * FixPacketHeader
  *
- *    Fix IP length, IP checksum, TCP sequence number and TCP checksum
- *    in the segment.
+ *    Fix IP length, Offset, IP checksum, TCP sequence number and TCP checksum
+ *    in the netbuffer if applicable.
  * --------------------------------------------------------------------------
  */
 static NDIS_STATUS
-FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
-                 BOOLEAN lastPacket, UINT16 packetCounter)
+FixPacketHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
+                BOOLEAN lastPacket, UINT16 packetCounter, UINT16 offset,
+                BOOLEAN isFragment)
 {
     EthHdr *dstEth = NULL;
     TCPHdr *dstTCP = NULL;
@@ -1140,41 +1166,55 @@  FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
     case ETH_TYPE_IPV4_NBO:
     {
         IPHdr *dstIP = NULL;
-
-        ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
+        if (!isFragment) {
+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
                 >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr));
-        dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
-        dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
-        ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
+            dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
+            dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4);
+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
                 >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
 
-        /* Fix IP length and checksum */
-        ASSERT(dstIP->protocol == IPPROTO_TCP);
-        dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
-        dstIP->id += packetCounter;
+            /* Fix IP length and checksum */
+            ASSERT(dstIP->protocol == IPPROTO_TCP);
+            dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP));
+            dstIP->id += packetCounter;
+            dstTCP->seq = htonl(seqNumber);
+
+            /*
+             * Set the TCP FIN and PSH bit only for the last packet
+             * More information can be found under:
+             * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
+             */
+            if (dstTCP->fin) {
+                dstTCP->fin = lastPacket;
+            }
+            if (dstTCP->psh) {
+                dstTCP->psh = lastPacket;
+            }
+            UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
+            dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
+                                             &dstIP->daddr,
+                                             IPPROTO_TCP,
+                                             csumLength);
+            dstTCP->check = CalculateChecksumNB(nb,
+                                                csumLength,
+                                                sizeof(*dstEth) + dstIP->ihl * 4);
+        } else {
+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
+                >= sizeof(EthHdr) + sizeof(IPHdr));
+
+            dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
+            ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
+                >= sizeof(EthHdr) + dstIP->ihl * 4);
+            dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4);
+            if (lastPacket) {
+                dstIP->frag_off = htons(offset & IP_OFFSET);
+            } else {
+                dstIP->frag_off = htons((offset & IP_OFFSET) | IP_MF);
+            }
+        }
         dstIP->check = 0;
         dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0);
-        dstTCP->seq = htonl(seqNumber);
-
-        /*
-         * Set the TCP FIN and PSH bit only for the last packet
-         * More information can be found under:
-         * https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx
-         */
-        if (dstTCP->fin) {
-            dstTCP->fin = lastPacket;
-        }
-        if (dstTCP->psh) {
-            dstTCP->psh = lastPacket;
-        }
-        UINT16 csumLength = segmentSize + TCP_HDR_LEN(dstTCP);
-        dstTCP->check = IPPseudoChecksum(&dstIP->saddr,
-                                         &dstIP->daddr,
-                                         IPPROTO_TCP,
-                                         csumLength);
-        dstTCP->check = CalculateChecksumNB(nb,
-                                            csumLength,
-                                            sizeof(*dstEth) + dstIP->ihl * 4);
         break;
     }
     case ETH_TYPE_IPV6_NBO:
@@ -1218,11 +1258,29 @@  FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
     return STATUS_SUCCESS;
 }
 
+ /*
+  * --------------------------------------------------------------------------
+ * OvsTcpSegmentNBL --
+ *      Wrapper function to Fragment a given NBL based on MSS
+ * --------------------------------------------------------------------------
+ */
+PNET_BUFFER_LIST
+OvsTcpSegmentNBL(PVOID ovsContext,
+                 PNET_BUFFER_LIST nbl,
+                 POVS_PACKET_HDR_INFO hdrInfo,
+                 UINT32 mss,
+                 UINT32 headRoom,
+                 BOOLEAN isIpFragment)
+{
+    return OvsFragmentNBL(ovsContext, nbl, hdrInfo, mss, headRoom, isIpFragment);
+}
+
+
 /*
  * --------------------------------------------------------------------------
- * OvsTcpSegmentNBL --
+ * OvsFragmentNBL --
  *
- *    Segment TCP payload, and prepend each segment with ether/IP/TCP header.
+ *    Fragment NBL payload, and prepend each segment with either/IP/TCP header.
  *    Leave headRoom for additional encap.
  *
  *    Please note,
@@ -1235,24 +1293,25 @@  FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
  * --------------------------------------------------------------------------
  */
 PNET_BUFFER_LIST
-OvsTcpSegmentNBL(PVOID ovsContext,
-                 PNET_BUFFER_LIST nbl,
-                 POVS_PACKET_HDR_INFO hdrInfo,
-                 UINT32 mss,
-                 UINT32 headRoom)
+OvsFragmentNBL(PVOID ovsContext,
+               PNET_BUFFER_LIST nbl,
+               POVS_PACKET_HDR_INFO hdrInfo,
+               UINT32 fragmentSize,
+               UINT32 headRoom,
+               BOOLEAN isIpFragment)
 {
     POVS_SWITCH_CONTEXT context = (POVS_SWITCH_CONTEXT)ovsContext;
 #ifdef DBG
     POVS_NBL_POOL ovsPool = &context->ovsPool;
 #endif
     POVS_BUFFER_CONTEXT dstCtx, srcCtx;
-    UINT32 size, hdrSize, seqNumber;
+    UINT32 size, hdrSize, nblSize, seqNumber = 0;
     PNET_BUFFER_LIST newNbl;
     PNET_BUFFER nb, newNb;
     NDIS_STATUS status;
     UINT16 segmentSize;
     ULONG copiedSize;
-    UINT16 packetCounter = 0;
+    UINT16 offset = 0, packetCounter = 0;
 
     srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
     if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
@@ -1264,18 +1323,28 @@  OvsTcpSegmentNBL(PVOID ovsContext,
     nb = NET_BUFFER_LIST_FIRST_NB(nbl);
     ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
 
-    /* Figure out the segment header size */
-    status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
+    /* Figure out the header size */
+    if (isIpFragment) {
+        status = GetIpHeaderInfo(nbl, &hdrSize);
+    } else {
+        status = GetSegmentHeaderInfo(nbl, hdrInfo, &hdrSize, &seqNumber);
+    }
     if (status != NDIS_STATUS_SUCCESS) {
         OVS_LOG_INFO("Cannot parse NBL header");
         return NULL;
     }
-
+    /* Get the NBL size. */
+    if (isIpFragment) {
+        nblSize = fragmentSize - hdrSize;
+    } else {
+        nblSize = fragmentSize;
+    }
     size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
 
     /* XXX add to ovsPool counters? */
-    newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL,
-            NULL, hdrSize, mss, hdrSize + headRoom , 0, 0);
+    newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
+                                               nblSize, hdrSize + headRoom ,
+                                               0, 0);
     if (newNbl == NULL) {
         return NULL;
     }
@@ -1283,7 +1352,7 @@  OvsTcpSegmentNBL(PVOID ovsContext,
     /* Now deal with TCP payload */
     for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
             newNb = NET_BUFFER_NEXT_NB(newNb)) {
-        segmentSize = (size > mss ? mss : size) & 0xffff;
+        segmentSize = (size > nblSize ? nblSize : size) & 0xffff;
         if (headRoom) {
             NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
         }
@@ -1295,17 +1364,21 @@  OvsTcpSegmentNBL(PVOID ovsContext,
             goto nblcopy_error;
         }
 
-        status = FixSegmentHeader(newNb, segmentSize, seqNumber,
-                                  NET_BUFFER_NEXT_NB(newNb) == NULL,
-                                  packetCounter);
+        status = FixPacketHeader(newNb, segmentSize, seqNumber,
+                                 NET_BUFFER_NEXT_NB(newNb) == NULL,
+                                 packetCounter, offset, isIpFragment);
+
         if (status != NDIS_STATUS_SUCCESS) {
             goto nblcopy_error;
         }
 
-
         /* Move on to the next segment */
+        if (isIpFragment) {
+            offset += (segmentSize) / 8;
+        } else {
+            seqNumber += segmentSize;
+        }
         size -= segmentSize;
-        seqNumber += segmentSize;
         packetCounter++;
     }
 
@@ -1319,6 +1392,15 @@  OvsTcpSegmentNBL(PVOID ovsContext,
         goto nbl_context_error;
     }
 
+    if (isIpFragment) {
+        /* Copy with Flag - NDIS_SWITCH_COPY_NBL_INFO_FLAGS_PRESERVE_DESTINATIONS. */
+        status = context->NdisSwitchHandlers.
+            CopyNetBufferListInfo(context->ovsPool.ndisContext, newNbl, nbl, 1);
+
+        if (status != NDIS_STATUS_SUCCESS) {
+            goto nbl_context_error;
+        }
+    }
     newNbl->ParentNetBufferList = nbl;
 
     /* Remember it's a fragment NBL so we can free it properly */
@@ -1340,7 +1422,7 @@  OvsTcpSegmentNBL(PVOID ovsContext,
     OvsDumpNetBufferList(newNbl);
     OvsDumpForwardingDetails(newNbl);
 #endif
-    OVS_LOG_TRACE("Segment nbl %p to newNbl: %p", nbl, newNbl);
+    OVS_LOG_TRACE("Fragmnet nbl %p to newNbl: %p", nbl, newNbl);
     return newNbl;
 
 nbl_context_error:
diff --git a/datapath-windows/ovsext/BufferMgmt.h b/datapath-windows/ovsext/BufferMgmt.h
index 77b2854..52fe532 100644
--- a/datapath-windows/ovsext/BufferMgmt.h
+++ b/datapath-windows/ovsext/BufferMgmt.h
@@ -116,7 +116,15 @@  PNET_BUFFER_LIST OvsTcpSegmentNBL(PVOID context,
                                   PNET_BUFFER_LIST nbl,
                                   POVS_PACKET_HDR_INFO hdrInfo,
                                   UINT32 MSS,
-                                  UINT32 headRoom);
+                                  UINT32 headRoom,
+                                  BOOLEAN isIpFragment);
+
+PNET_BUFFER_LIST OvsFragmentNBL(PVOID context,
+                                PNET_BUFFER_LIST nbl,
+                                POVS_PACKET_HDR_INFO hdrInfo,
+                                UINT32 MSS,
+                                UINT32 headRoom,
+                                BOOLEAN isIpFragment);
 
 PNET_BUFFER_LIST OvsAllocateNBLFromBuffer(PVOID context,
                                           PVOID buffer,
diff --git a/datapath-windows/ovsext/Geneve.c b/datapath-windows/ovsext/Geneve.c
index 1938aaa..43374e2 100644
--- a/datapath-windows/ovsext/Geneve.c
+++ b/datapath-windows/ovsext/Geneve.c
@@ -118,7 +118,7 @@  NDIS_STATUS OvsEncapGeneve(POVS_VPORT_ENTRY vport,
         if (mss) {
             OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
-                                       mss, headRoom);
+                                       mss, headRoom, FALSE);
             if (*newNbl == NULL) {
                 OVS_LOG_ERROR("Unable to segment NBL");
                 return NDIS_STATUS_FAILURE;
diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
index c5da064..f095742 100644
--- a/datapath-windows/ovsext/Gre.c
+++ b/datapath-windows/ovsext/Gre.c
@@ -158,7 +158,7 @@  OvsDoEncapGre(POVS_VPORT_ENTRY vport,
         if (mss) {
             OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
-                                       mss, headRoom);
+                                       mss, headRoom, FALSE);
             if (*newNbl == NULL) {
                 OVS_LOG_ERROR("Unable to segment NBL");
                 return NDIS_STATUS_FAILURE;
diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c
index 5aa8652..1f36835 100644
--- a/datapath-windows/ovsext/Stt.c
+++ b/datapath-windows/ovsext/Stt.c
@@ -185,7 +185,7 @@  OvsDoEncapStt(POVS_VPORT_ENTRY vport,
         if ((innerFrameLen > OVS_MAX_STT_PACKET_LENGTH) ||
             (layers->l4Offset > OVS_MAX_STT_L4_OFFSET_LENGTH)) {
             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
-                mss - headRoom, headRoom);
+                                       mss - headRoom, headRoom, FALSE);
             if (*newNbl == NULL) {
                 OVS_LOG_ERROR("Unable to segment NBL");
                 return NDIS_STATUS_FAILURE;
diff --git a/datapath-windows/ovsext/User.c b/datapath-windows/ovsext/User.c
index 3154640..7880220 100644
--- a/datapath-windows/ovsext/User.c
+++ b/datapath-windows/ovsext/User.c
@@ -787,7 +787,7 @@  OvsCreateAndAddPackets(PVOID userData,
         if (tsoInfo.LsoV1Transmit.MSS) {
             OVS_LOG_TRACE("l4Offset %d", hdrInfo->l4Offset);
             newNbl = OvsTcpSegmentNBL(switchContext, nbl, hdrInfo,
-                    tsoInfo.LsoV1Transmit.MSS , 0);
+                                      tsoInfo.LsoV1Transmit.MSS , 0, FALSE);
             if (newNbl == NULL) {
                 return NDIS_STATUS_FAILURE;
             }
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
index 84c2f2f..427f31c 100644
--- a/datapath-windows/ovsext/Vxlan.c
+++ b/datapath-windows/ovsext/Vxlan.c
@@ -205,7 +205,7 @@  OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
         if (mss) {
             OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
             *newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
-                                       mss, headRoom);
+                                       mss, headRoom, FALSE);
             if (*newNbl == NULL) {
                 OVS_LOG_ERROR("Unable to segment NBL");
                 return NDIS_STATUS_FAILURE;