[ovs-dev] [PATCH v3] datapath-windows: Add GRE checksum

Alin Serdean aserdean at cloudbasesolutions.com
Wed Jun 8 13:44:30 UTC 2016


This patch introduces GRE checksum computation if the userspace requires
it on Tx. On Rx we verify the GRE checksum if the checksum bit was
specified and also inform the userspace about it.

Also fix the GRE header length as specified by the GRE flags not the
tunnel flags.

Signed-off-by: Alin Gabriel Serdean <aserdean at cloudbasesolutions.com>
---
v3: Fix access length and address comments
v2: Initial commit
---
 datapath-windows/ovsext/Gre.c | 79 ++++++++++++++++++++++++++++++-------------
 datapath-windows/ovsext/Gre.h | 16 +++++----
 2 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
index cb41593..bee3877 100644
--- a/datapath-windows/ovsext/Gre.c
+++ b/datapath-windows/ovsext/Gre.c
@@ -135,7 +135,8 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport,
     IPHdr *ipHdr;
     PGREHdr greHdr;
     POVS_GRE_VPORT vportGre;
-    UINT32 headRoom = GreTunHdrSize(tunKey->flags);
+    PCHAR pChk = NULL;
+    UINT32 headRoom = GreTunHdrSize(OvsTunnelFlagsToGreFlags(tunKey->flags));
 #if DBG
     UINT32 counterHeadRoom;
 #endif
@@ -259,6 +260,7 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport,
 
         if (tunKey->flags & OVS_TNL_F_CSUM) {
             RtlZeroMemory(currentOffset, 4);
+            pChk = currentOffset;
             currentOffset += 4;
 #if DBG
             counterHeadRoom -= 4;
@@ -275,6 +277,17 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport,
 #endif
         }
 
+        /* Checksum needs to be done after the GRE header has been set */
+        if (tunKey->flags & OVS_TNL_F_CSUM) {
+            ASSERT(pChk);
+            UINT16 chksum =
+                CalculateChecksumNB(curNb,
+                                    (UINT16)(NET_BUFFER_DATA_LENGTH(curNb) -
+                                             sizeof *ipHdr - sizeof *ethHdr),
+                                    sizeof *ipHdr + sizeof *ethHdr);
+            RtlCopyMemory(pChk, &chksum, 2);
+        }
+
 #if DBG
         ASSERT(counterHeadRoom == 0);
 #endif
@@ -299,34 +312,21 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
     EthHdr *ethHdr;
     IPHdr *ipHdr;
     GREHdr *greHdr;
-    UINT32 tunnelSize = 0, packetLength = 0;
+    UINT32 tunnelSize, packetLength;
     UINT32 headRoom = 0;
     PUINT8 bufferStart;
     NDIS_STATUS status;
 
     curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
     packetLength = NET_BUFFER_DATA_LENGTH(curNb);
-    tunnelSize = GreTunHdrSize(tunKey->flags);
+    curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+    tunnelSize = GreTunHdrSize(0);
     if (packetLength <= tunnelSize) {
         return NDIS_STATUS_INVALID_LENGTH;
     }
 
-    /*
-     * Create a copy of the NBL so that we have all the headers in one MDL.
-     */
-    *newNbl = OvsPartialCopyNBL(switchContext, curNbl,
-                                tunnelSize + OVS_DEFAULT_COPY_SIZE, 0,
-                                TRUE /*copy NBL info */);
-
-    if (*newNbl == NULL) {
-        return NDIS_STATUS_RESOURCES;
-    }
-
-    curNbl = *newNbl;
-    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
-    curMdl = NET_BUFFER_CURRENT_MDL(curNb);
-    bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority) +
-                  NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+    /* Get a contignuous buffer for the maxmimum length of a GRE header */
+    bufferStart = NdisGetDataBuffer(curNb, OVS_MAX_GRE_LGTH, NULL, 1, 0);
     if (!bufferStart) {
         status = NDIS_STATUS_RESOURCES;
         goto dropNbl;
@@ -346,16 +346,35 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
     greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
     headRoom += sizeof *greHdr;
 
+    tunnelSize = GreTunHdrSize(greHdr->flags);
+
+    /* Verify the packet length after looking at the GRE flags*/
+    if (packetLength <= tunnelSize) {
+        return NDIS_STATUS_INVALID_LENGTH;
+    }
+
     /* Validate if GRE header protocol type. */
     if (greHdr->protocolType != GRE_NET_TEB) {
-        status = STATUS_NDIS_INVALID_PACKET;
-        goto dropNbl;
+        *newNbl = NULL;
+        return STATUS_NDIS_INVALID_PACKET;
     }
 
     PCHAR currentOffset = (PCHAR)greHdr + sizeof *greHdr;
 
     if (greHdr->flags & GRE_CSUM) {
         tunKey->flags |= OVS_TNL_F_CSUM;
+        UINT16 prevChksum = *((UINT16 *)currentOffset);
+        RtlZeroMemory(currentOffset, 2);
+        UINT16 chksum =
+            CalculateChecksumNB(curNb,
+                                (UINT16)(NET_BUFFER_DATA_LENGTH(curNb) -
+                                (ipHdr->ihl * 4 + sizeof *ethHdr)),
+                                ipHdr->ihl * 4 + sizeof *ethHdr);
+        if (prevChksum != chksum) {
+            *newNbl = NULL;
+            return STATUS_NDIS_INVALID_PACKET;
+        }
+        RtlCopyMemory(currentOffset, &prevChksum, 2);
         currentOffset += 4;
         headRoom += 4;
     }
@@ -369,11 +388,25 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
         headRoom += 4;
     }
 
+    /*
+     * Create a copy of the NBL so that we have all the headers in one MDL.
+     */
+    *newNbl = OvsPartialCopyNBL(switchContext, curNbl,
+                                tunnelSize, 0,
+                                TRUE /*copy NBL info */);
+
+    if (*newNbl == NULL) {
+        return NDIS_STATUS_RESOURCES;
+    }
+
+    curNbl = *newNbl;
+    curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
+
     /* Clear out the receive flag for the inner packet. */
     NET_BUFFER_LIST_INFO(curNbl, TcpIpChecksumNetBufferListInfo) = 0;
-    NdisAdvanceNetBufferDataStart(curNb, GreTunHdrSize(tunKey->flags), FALSE,
+    NdisAdvanceNetBufferDataStart(curNb, GreTunHdrSize(greHdr->flags), FALSE,
                                   NULL);
-    ASSERT(headRoom == GreTunHdrSize(tunKey->flags));
+    ASSERT(headRoom == GreTunHdrSize(greHdr->flags));
     return NDIS_STATUS_SUCCESS;
 
 dropNbl:
diff --git a/datapath-windows/ovsext/Gre.h b/datapath-windows/ovsext/Gre.h
index d2472d9..7e20ced 100644
--- a/datapath-windows/ovsext/Gre.h
+++ b/datapath-windows/ovsext/Gre.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Cloudbase Solutions Srl
+ * Copyright (c) 2015, 2016 Cloudbase Solutions Srl
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,6 +51,8 @@ typedef struct GREHdr {
 /* GRE Flags*/
 #define GRE_CSUM    0x0080
 #define GRE_KEY     0x0020
+/* The maximum GRE header length that we can process */
+#define OVS_MAX_GRE_LGTH (sizeof(EthHdr) + sizeof(IPHdr) + sizeof(GREHdr) + 12)
 
 NTSTATUS OvsInitGreTunnel(POVS_VPORT_ENTRY vport);
 
@@ -76,11 +78,13 @@ OvsTunnelFlagsToGreFlags(UINT16 tunnelflags)
 {
     UINT16 flags = 0;
 
-    if (tunnelflags & OVS_TNL_F_CSUM)
+    if (tunnelflags & OVS_TNL_F_CSUM) {
         flags |= GRE_CSUM;
+    }
 
-    if (tunnelflags & OVS_TNL_F_KEY)
+    if (tunnelflags & OVS_TNL_F_KEY) {
         flags |= GRE_KEY;
+    }
 
     return flags;
 }
@@ -89,10 +93,8 @@ static __inline UINT32
 GreTunHdrSize(UINT16 flags)
 {
     UINT32 sum = sizeof(EthHdr) + sizeof(IPHdr) + sizeof(GREHdr);
-    sum += (flags & OVS_TNL_F_CSUM) ?
-           4 : 0;
-    sum += (flags & OVS_TNL_F_KEY) ?
-           4 : 0;
+    sum += (flags & GRE_CSUM) ? 4 : 0;
+    sum += (flags & GRE_KEY) ? 4 : 0;
 
     return sum;
 }
-- 
1.9.5.msysgit.0



More information about the dev mailing list