summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlin Serdean <aserdean@cloudbasesolutions.com>2016-06-17 20:00:54 +0000
committerGurucharan Shetty <guru@ovn.org>2016-06-24 11:30:30 -0700
commit9a5b6ddfbd8e6fe63f33eace09fb987a2957c468 (patch)
treec5870bae7691776fc463e1e76493d3b3dc2f37a1
parentaaca4fe0ce9e90a41b3f4db84be7d05823c733e4 (diff)
downloadopenvswitch-9a5b6ddfbd8e6fe63f33eace09fb987a2957c468.tar.gz
datapath-windows: Add GRE checksum
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@cloudbasesolutions.com> Acked-by: Nithin Raju <nithin@vmware.com> Signed-off-by: Gurucharan Shetty <guru@ovn.org>
-rw-r--r--datapath-windows/ovsext/Gre.c112
-rw-r--r--datapath-windows/ovsext/Gre.h16
2 files changed, 92 insertions, 36 deletions
diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
index cb4159379..1976b08f1 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,37 +312,42 @@ 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;
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ PCHAR tempBuf = NULL;
+
+ ASSERT(*newNbl == NULL);
+
+ *newNbl = NULL;
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 contiguous buffer for the maximum length of a GRE header */
+ bufferStart = NdisGetDataBuffer(curNb, OVS_MAX_GRE_LGTH, NULL, 1, 0);
if (!bufferStart) {
- status = NDIS_STATUS_RESOURCES;
- goto dropNbl;
+ /* Documentation is unclear on where the packet can be fragmented.
+ * For the moment allocate the buffer needed to get the maximum length
+ * of a GRE header contiguous */
+ tempBuf = OvsAllocateMemoryWithTag(OVS_MAX_GRE_LGTH, OVS_GRE_POOL_TAG);
+ if (!tempBuf) {
+ status = NDIS_STATUS_RESOURCES;
+ goto end;
+ }
+ RtlZeroMemory(tempBuf, OVS_MAX_GRE_LGTH);
+ bufferStart = NdisGetDataBuffer(curNb, OVS_MAX_GRE_LGTH, tempBuf,
+ 1, 0);
+ if (!bufferStart) {
+ status = NDIS_STATUS_RESOURCES;
+ goto end;
+ }
}
ethHdr = (EthHdr *)bufferStart;
@@ -346,16 +364,36 @@ 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) {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ goto end;
+ }
+
/* Validate if GRE header protocol type. */
if (greHdr->protocolType != GRE_NET_TEB) {
status = STATUS_NDIS_INVALID_PACKET;
- goto dropNbl;
+ goto end;
}
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) {
+ status = STATUS_NDIS_INVALID_PACKET;
+ goto end;
+ }
+ RtlCopyMemory(currentOffset, &prevChksum, 2);
currentOffset += 4;
headRoom += 4;
}
@@ -369,15 +407,31 @@ 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) {
+ status = NDIS_STATUS_RESOURCES;
+ goto end;
+ }
+
+ 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));
- return NDIS_STATUS_SUCCESS;
+ ASSERT(headRoom == GreTunHdrSize(greHdr->flags));
-dropNbl:
- OvsCompleteNBL(switchContext, *newNbl, TRUE);
- *newNbl = NULL;
+end:
+ if (tempBuf) {
+ OvsFreeMemoryWithTag(tempBuf, OVS_GRE_POOL_TAG);
+ tempBuf = NULL;
+ }
return status;
}
diff --git a/datapath-windows/ovsext/Gre.h b/datapath-windows/ovsext/Gre.h
index d2472d91a..7e20ced96 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;
}