summaryrefslogtreecommitdiff
path: root/datapath-windows/ovsext/BufferMgmt.c
diff options
context:
space:
mode:
authorldejing <ldejing@vmware.com>2022-08-16 19:14:32 +0800
committerAlin-Gabriel Serdean <alin.serdean@canonical.com>2022-09-20 02:40:03 +0300
commit7af5c33c1629b309cbcbe3b6c9c3bd6d3b4c0abf (patch)
tree445f0e0379b0134bf1bbde32811b05ee59586014 /datapath-windows/ovsext/BufferMgmt.c
parent54a618f0bd83431a18307a312e5b41e401538bbc (diff)
downloadopenvswitch-7af5c33c1629b309cbcbe3b6c9c3bd6d3b4c0abf.tar.gz
datapath-windows: Add IPv6 conntrack ip fragment support on windows
Implementation on Windows: IPv6 conntrack ip fragment feature use a link list to store ip fragment. When ipv6 fragment module receives a fragment packet, it will store length of the fragment, until to the received length equal to the packet length before fragmented, it will reassemble fragment packet to a complete packet and send the complete packet to conntrack module. After conntrack processed the packet, fragment module will divide the complete packet into small fragment and send it to destination. Currently, ipv6 was implemented in a indenpent module, for the reason it can reduce the risk of introduce bug to ipv4 fragmenb module. Testing Topology: On the Windows VM runs on the ESXi host, two hyper-v ports attached to the ovs bridge; one hyper-v port worked as client and the other port worked as server. Testing Case: 1.UdpV6 a) UdpV6 fragment with multiple ipv6 extension fields. b) UdpV6 fragment in normal scenario. c) UdpV6 fragment in nat scenario. 2.IcmpV6 a) IcmpV6 fragment in normal scenario. b) IcmpV6 fragment in nat scenario. Signed-off-by: ldejing <ldejing@vmware.com> Signed-off-by: Alin-Gabriel Serdean <aserdean@ovn.org>
Diffstat (limited to 'datapath-windows/ovsext/BufferMgmt.c')
-rw-r--r--datapath-windows/ovsext/BufferMgmt.c464
1 files changed, 428 insertions, 36 deletions
diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c
index acf3c13a2..5c52757a0 100644
--- a/datapath-windows/ovsext/BufferMgmt.c
+++ b/datapath-windows/ovsext/BufferMgmt.c
@@ -77,6 +77,7 @@
*/
#include "precomp.h"
+#include "jhash.h"
#include "Debug.h"
#include "Flow.h"
#include "Offload.h"
@@ -90,8 +91,6 @@
#undef OVS_DBG_MOD
#endif
#define OVS_DBG_MOD OVS_DBG_BUFMGMT
-
-
/*
* --------------------------------------------------------------------------
* OvsInitBufferPool --
@@ -1109,19 +1108,26 @@ GetIpHeaderInfo(PNET_BUFFER_LIST curNbl,
{
EthHdr *eth;
IPHdr *ipHdr;
+ IPv6Hdr *ipv6Hdr;
PNET_BUFFER curNb;
curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
-
eth = (EthHdr *)NdisGetDataBuffer(curNb,
hdrInfo->l4Offset,
NULL, 1, 0);
if (eth == NULL) {
return NDIS_STATUS_INVALID_PACKET;
}
- ipHdr = (IPHdr *)((PCHAR)eth + hdrInfo->l3Offset);
- *hdrSize = (UINT32)(hdrInfo->l3Offset + (ipHdr->ihl * 4));
+
+ if (hdrInfo->isIPv6) {
+ ipv6Hdr = (IPv6Hdr *)((PCHAR)eth + hdrInfo->l3Offset);
+ *hdrSize = (UINT32)(hdrInfo->l4Offset);
+ } else {
+ ipHdr = (IPHdr *)((PCHAR)eth + hdrInfo->l3Offset);
+ *hdrSize = (UINT32)(hdrInfo->l3Offset + (ipHdr->ihl * 4));
+ }
+
return NDIS_STATUS_SUCCESS;
}
@@ -1151,17 +1157,72 @@ GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl,
return NDIS_STATUS_SUCCESS;
}
+static VOID
+FixFragmentHeader4(UINT16 fragmentSize, UINT16 offset, const EthHdr *dstEth,
+ BOOLEAN lastPacket)
+{
+ IPHdr *dstIP = NULL;
+
+ dstIP = (IPHdr *)((PCHAR)dstEth + sizeof(*dstEth));
+ dstIP->tot_len = htons(fragmentSize + 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);
+}
+
+static VOID
+FixFragmentHeader6(UINT16 offset, const EthHdr *dstEth,
+ UINT32 fragmentIdent,
+ BOOLEAN lastPacket)
+{
+ IPv6Hdr *dstIP = NULL;
+ UINT8 nextHdr;
+ IPv6ExtHdr *extHdr;
+
+ dstIP = (IPv6Hdr *)((PCHAR)dstEth + sizeof(*dstEth));
+ extHdr = (IPv6ExtHdr *)((PCHAR)dstIP + sizeof(IPv6Hdr));
+ nextHdr = dstIP->nexthdr;
+ while (nextHdr != SOCKET_IPPROTO_FRAGMENT) {
+ nextHdr = extHdr->nextHeader;
+ extHdr = (IPv6ExtHdr *)((PCHAR)extHdr + OVS_IPV6_OPT_LEN(extHdr));
+ if (!extHdr) {
+ break;
+ }
+ }
+
+ if (nextHdr == SOCKET_IPPROTO_FRAGMENT) {
+ IPv6FragHdr *fragHdr = (IPv6FragHdr *)extHdr;
+ fragHdr->reserved = 0x00;
+ fragHdr->offlg &= htons(0x00);
+ fragHdr->ident = fragmentIdent;
+ if (lastPacket) {
+ fragHdr->offlg |= htons(offset << 3);
+ } else {
+ fragHdr->offlg |= htons(0x01);
+ fragHdr->offlg |= htons(offset << 3) ;
+ }
+ } else {
+ if (!extHdr) {
+ ASSERT(! "Invalid fragment packet.");
+ }
+ }
+}
+
/*
* --------------------------------------------------------------------------
* FixFragmentHeader
*
* Fix IP length, Offset, IP checksum.
- * XXX - Support IpV6 Fragments
* --------------------------------------------------------------------------
*/
static NDIS_STATUS
-FixFragmentHeader(PNET_BUFFER nb, UINT16 fragmentSize,
- BOOLEAN lastPacket, UINT16 offset)
+FixFragmentHeader(PNET_BUFFER nb, UINT16 fragmentSize, BOOLEAN lastPacket,
+ UINT16 offset, UINT32 fragmentIdent)
{
EthHdr *dstEth = NULL;
PMDL mdl = NULL;
@@ -1180,25 +1241,20 @@ FixFragmentHeader(PNET_BUFFER nb, UINT16 fragmentSize,
{
IPHdr *dstIP = NULL;
ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
- >= sizeof(EthHdr) + sizeof(IPHdr));
-
+ >= 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(fragmentSize + 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);
+ >= sizeof(EthHdr) + dstIP->ihl * 4);
+ FixFragmentHeader4(fragmentSize, offset, dstEth, lastPacket);
break;
}
case ETH_TYPE_IPV6_NBO:
{
- return NDIS_STATUS_NOT_SUPPORTED;
+ ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb)
+ >= sizeof(EthHdr) + sizeof(IPv6Hdr));
+ FixFragmentHeader6(offset, dstEth, fragmentIdent,
+ lastPacket);
+ break;
}
default:
OVS_LOG_ERROR("Invalid eth type: %d\n", dstEth->Type);
@@ -1314,6 +1370,7 @@ FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber,
return STATUS_SUCCESS;
}
+
/*
* --------------------------------------------------------------------------
* OvsTcpSegmentNBL --
@@ -1331,6 +1388,187 @@ OvsTcpSegmentNBL(PVOID ovsContext,
return OvsFragmentNBL(ovsContext, nbl, hdrInfo, mss, headRoom, isIpFragment);
}
+NDIS_STATUS
+OvsFigureIPV6ExtHdrLayout(PNET_BUFFER_LIST nbl,
+ POVS_PACKET_HDR_INFO hdrInfo,
+ UINT16 *beforeFragmentExtFieldLen)
+{
+ EthHdr *eth;
+ IPv6Hdr *ipv6Hdr;
+ IPv6ExtHdr *extHdr;
+ PNET_BUFFER curNb;
+ UINT8 nextHdr = 0;
+ UINT16 offset = 0;
+ BOOLEAN foundRouterHeader = FALSE;
+ UINT16 extFieldLen = 0;
+
+ curNb = NET_BUFFER_LIST_FIRST_NB(nbl);
+ ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
+ eth = (EthHdr *)NdisGetDataBuffer(curNb,
+ hdrInfo->l4Offset,
+ NULL, 1, 0);
+ if (!eth) {
+ OVS_LOG_ERROR("Invalid packet.");
+ return NDIS_STATUS_INVALID_PACKET;
+ }
+
+ ipv6Hdr = (IPv6Hdr *)((PCHAR)eth + hdrInfo->l3Offset);
+ nextHdr = ipv6Hdr->nexthdr;
+ extHdr = (IPv6ExtHdr *)((PCHAR)ipv6Hdr + sizeof(*ipv6Hdr));
+ extFieldLen = hdrInfo->l4Offset - hdrInfo->l3Offset - sizeof(IPv6Hdr);
+
+ while (offset <= extFieldLen) {
+ switch (nextHdr) {
+ case SOCKET_IPPROTO_HOPOPTS:
+ *beforeFragmentExtFieldLen += OVS_IPV6_OPT_LEN(extHdr);
+ break;
+ case SOCKET_IPPROTO_ROUTING:
+ *beforeFragmentExtFieldLen += OVS_IPV6_OPT_LEN(extHdr);
+ foundRouterHeader = TRUE;
+ break;
+ case SOCKET_IPPROTO_DSTOPTS:
+ if (foundRouterHeader) {
+ /* In the ipv6 extension field, dst option field must
+ * appear with routeing option filed. */
+ *beforeFragmentExtFieldLen += OVS_IPV6_OPT_LEN(extHdr);
+ return NDIS_STATUS_SUCCESS;
+ } else {
+ /* dst opts field not appear with routing field,
+ * this represent this dst option field is
+ * bebind fragment. */
+ return NDIS_STATUS_SUCCESS;
+ }
+ break;
+ default:
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ offset += OVS_IPV6_OPT_LEN(extHdr);
+ nextHdr = extHdr->nextHeader;
+ extHdr = (IPv6ExtHdr *)((PCHAR)extHdr + OVS_IPV6_OPT_LEN(extHdr));
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * function name -- FixIPV6ExtHdrField
+ * This function mainly used to fix IPv6 extension field, because we only
+ * add fragment field in the header, not fix the next header filed,
+ * this function is used to fix that issue.
+ * --------------------------------------------------------------------------
+ */
+NDIS_STATUS
+FixIPV6ExtHdrField(PNET_BUFFER nb, UINT16 l3Offset, UINT16 l4Offset,
+ UINT16 fragmentSize)
+{
+ EthHdr *eth;
+ IPv6Hdr *ipv6Hdr = NULL;
+ IPv6ExtHdr *extHdr = NULL;
+ IPv6ExtHdr *lastExtHdr = NULL;
+ IPv6FragHdr *frgHdr = NULL;
+ UINT8 nextHdr = 0;
+ UINT16 offset = 0;
+ BOOLEAN exitLookup = FALSE;
+ BOOLEAN foundRouterHeader = FALSE;
+ PMDL mdl = NULL;
+ PUINT8 bufferStart = NULL;
+ UINT16 extFieldLen = 0;
+
+ mdl = NET_BUFFER_FIRST_MDL(nb);
+ bufferStart = (PUINT8)OvsGetMdlWithLowPriority(mdl);
+ if (!bufferStart) {
+ OVS_LOG_ERROR("Return, buffer start null.");
+ return STATUS_NDIS_INVALID_PACKET;
+ }
+ eth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb));
+ ipv6Hdr = (IPv6Hdr *)((PCHAR)eth+ l3Offset);
+ nextHdr = ipv6Hdr->nexthdr;
+ lastExtHdr = NULL;
+ extHdr = (IPv6ExtHdr *)((PCHAR)ipv6Hdr + sizeof(*ipv6Hdr));
+ extFieldLen = l4Offset - l3Offset - sizeof(IPv6Hdr);
+ ipv6Hdr->payload_len = htons(extFieldLen + fragmentSize);
+
+ while (offset <= extFieldLen) {
+ switch (nextHdr) {
+ case SOCKET_IPPROTO_HOPOPTS:
+ break;
+ case SOCKET_IPPROTO_ROUTING:
+ foundRouterHeader = TRUE;
+ break;
+ case SOCKET_IPPROTO_DSTOPTS:
+ if (foundRouterHeader) {
+ frgHdr = (IPv6FragHdr *)((PCHAR)extHdr + offset);
+ frgHdr->nextHeader = ipv6Hdr->nexthdr;
+ ipv6Hdr->nexthdr = SOCKET_IPPROTO_FRAGMENT;
+
+ } else {
+ /* This dest option field was appear behind
+ * fragment field. */
+ if (lastExtHdr) {
+ frgHdr = (IPv6FragHdr *)extHdr;
+ frgHdr->nextHeader = lastExtHdr->nextHeader;
+ lastExtHdr->nextHeader = SOCKET_IPPROTO_FRAGMENT;
+ } else {
+ frgHdr = (IPv6FragHdr *)((PCHAR)extHdr + offset);
+ frgHdr->nextHeader = ipv6Hdr->nexthdr;
+ ipv6Hdr->nexthdr = SOCKET_IPPROTO_FRAGMENT;
+ }
+ }
+ exitLookup = TRUE;
+ break;
+ default:
+ if (!offset) {
+ frgHdr = (IPv6FragHdr *)((PCHAR)extHdr + offset);
+ frgHdr->nextHeader = ipv6Hdr->nexthdr;
+ ipv6Hdr->nexthdr = SOCKET_IPPROTO_FRAGMENT;
+ } else {
+ frgHdr = (IPv6FragHdr *)extHdr;
+ frgHdr->nextHeader = lastExtHdr->nextHeader;
+ lastExtHdr->nextHeader = SOCKET_IPPROTO_FRAGMENT;
+ }
+ exitLookup = TRUE;
+ break;
+ }
+
+ if (exitLookup) {
+ break;
+ }
+
+ offset += OVS_IPV6_OPT_LEN(extHdr);
+ nextHdr = extHdr->nextHeader;
+ lastExtHdr = extHdr;
+ extHdr = (IPv6ExtHdr *)((PCHAR)extHdr + OVS_IPV6_OPT_LEN(extHdr));
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+UINT32
+GenFragIdent6(PNET_BUFFER_LIST nbl, POVS_PACKET_HDR_INFO hdrInfo)
+{
+ EthHdr *eth;
+ IPv6Hdr *ipv6Hdr;
+ PNET_BUFFER curNb;
+ UINT32 srcHash;
+ UINT32 dstHash;
+ UINT32 randNumber;
+ LARGE_INTEGER randomSeed;
+
+ curNb = NET_BUFFER_LIST_FIRST_NB(nbl);
+ ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
+ eth = (EthHdr *)NdisGetDataBuffer(curNb,
+ hdrInfo->l4Offset,
+ NULL, 1, 0);
+ ipv6Hdr = (IPv6Hdr *)((PCHAR)eth + hdrInfo->l3Offset);
+ KeQuerySystemTime(&randomSeed);
+ randNumber = randomSeed.LowPart * OVS_FRAG_MAGIC_NUMBER + 1;
+
+ srcHash = OvsJhashBytes((UINT32 *)(&(ipv6Hdr->saddr)), 4, randNumber);
+ dstHash = OvsJhashBytes((UINT32 *)(&(ipv6Hdr->daddr)), 4, srcHash);
+ return dstHash;
+}
/*
* --------------------------------------------------------------------------
@@ -1366,8 +1604,11 @@ OvsFragmentNBL(PVOID ovsContext,
PNET_BUFFER nb, newNb;
NDIS_STATUS status;
UINT16 segmentSize;
- ULONG copiedSize;
+ ULONG copiedSize = 0;
UINT16 offset = 0, packetCounter = 0;
+ UINT16 beforeFragHdrLen = 0;
+ UINT32 fragmentIdent = 0;
+ UINT16 ip6StdHeaderLen = 0;
srcCtx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
if (srcCtx == NULL || srcCtx->magic != OVS_CTX_MAGIC) {
@@ -1379,6 +1620,19 @@ OvsFragmentNBL(PVOID ovsContext,
nb = NET_BUFFER_LIST_FIRST_NB(nbl);
ASSERT(NET_BUFFER_NEXT_NB(nb) == NULL);
+ if (hdrInfo->isIPv6 && isIpFragment) {
+ /* 1. We need to calculate the header length before
+ * fragment and after fragment.
+ * */
+ status = OvsFigureIPV6ExtHdrLayout(nbl, hdrInfo,
+ &beforeFragHdrLen);
+ if (status != NDIS_STATUS_SUCCESS) {
+ OVS_LOG_ERROR("Figure out ipv6 header layout error.");
+ return NULL;
+ }
+ ip6StdHeaderLen = hdrInfo->l3Offset + sizeof(IPv6Hdr);
+ }
+
/* Figure out the header size */
if (isIpFragment) {
status = GetIpHeaderInfo(nbl, hdrInfo, &hdrSize);
@@ -1391,21 +1645,40 @@ OvsFragmentNBL(PVOID ovsContext,
}
/* Get the NBL size. */
if (isIpFragment) {
- nblSize = fragmentSize - hdrSize;
+ if (hdrInfo->isIPv6) {
+ nblSize = fragmentSize - hdrSize - sizeof(IPv6FragHdr);
+ } else {
+ nblSize = fragmentSize - hdrSize;
+ }
} else {
nblSize = fragmentSize;
}
+
size = NET_BUFFER_DATA_LENGTH(nb) - hdrSize;
+ if (hdrInfo->isIPv6) {
+ /* Because if we want to divide ipv6 info fragments,
+ * we need add a fragment header in packet, thus we will
+ * allocate more memory(contain fragment header) for the packet. */
+ UINT32 dataOffset = hdrSize + sizeof(IPv6FragHdr) + headRoom;
+ newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
+ nblSize,
+ dataOffset,
+ 0, 0);
+ } else {
+ newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
+ nblSize, hdrSize + headRoom,
+ 0, 0);
+ }
- /* XXX add to ovsPool counters? */
- newNbl = NdisAllocateFragmentNetBufferList(nbl, NULL, NULL, hdrSize,
- nblSize, hdrSize + headRoom ,
- 0, 0);
if (newNbl == NULL) {
return NULL;
}
- /* Now deal with TCP payload */
+ /* Generate fragment identification */
+ if (isIpFragment && hdrInfo->isIPv6) {
+ fragmentIdent = GenFragIdent6(nbl, hdrInfo);
+ }
+
for (newNb = NET_BUFFER_LIST_FIRST_NB(newNbl); newNb != NULL;
newNb = NET_BUFFER_NEXT_NB(newNb)) {
segmentSize = (size > nblSize ? nblSize : size) & 0xffff;
@@ -1413,17 +1686,128 @@ OvsFragmentNBL(PVOID ovsContext,
NdisAdvanceNetBufferDataStart(newNb, headRoom, FALSE, NULL);
}
- /* Now copy the eth/IP/TCP header and fix up */
- status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize, nb, 0,
- &copiedSize);
- if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
- goto nblcopy_error;
+ if (NET_BUFFER_LIST_FIRST_NB(newNbl) == newNb) {
+ if (hdrInfo->isIPv6) {
+ /* When it is first ipv6 packet, we need copy all of ip
+ * ext header Copy headers before fragment.
+ * */
+ status = NdisCopyFromNetBufferToNetBuffer(newNb, 0,
+ ip6StdHeaderLen,
+ nb, 0 , &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS ||
+ (hdrInfo->l3Offset + sizeof(IPv6Hdr)) != copiedSize) {
+ goto nblcopy_error;
+ }
+
+ if (beforeFragHdrLen) {
+ status = NdisCopyFromNetBufferToNetBuffer(newNb,
+ ip6StdHeaderLen,
+ beforeFragHdrLen,
+ nb,
+ ip6StdHeaderLen,
+ &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS ||
+ beforeFragHdrLen != copiedSize) {
+ goto nblcopy_error;
+ }
+ }
+ /* Copy fragment headers. */
+ /* Copy headers after fragments. */
+
+ UINT32 behindFragHdrLen = hdrSize - hdrInfo->l3Offset
+ - sizeof(IPv6Hdr)
+ - beforeFragHdrLen;
+ if (behindFragHdrLen > 0) {
+ status = NdisCopyFromNetBufferToNetBuffer(newNb,
+ (ip6StdHeaderLen
+ + beforeFragHdrLen
+ + sizeof(IPv6FragHdr)),
+ behindFragHdrLen,
+ nb,
+ ip6StdHeaderLen
+ + beforeFragHdrLen,
+ &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS ||
+ behindFragHdrLen != copiedSize) {
+ goto nblcopy_error;
+ }
+ }
+
+ /* Fix IPv6 opt fields. */
+ status = FixIPV6ExtHdrField(newNb,
+ hdrInfo->l3Offset,
+ hdrInfo->l4Offset + sizeof(IPv6FragHdr),
+ segmentSize);
+ if (status != NDIS_STATUS_SUCCESS) {
+ OVS_LOG_ERROR("Invalid reassemble packet.");
+ goto nblcopy_error;
+ }
+ } else {
+ /* Now copy the eth/IP/TCP header and fix up */
+ status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize,
+ nb, 0, &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS || hdrSize != copiedSize) {
+ goto nblcopy_error;
+ }
+ }
+ } else {
+ if (hdrInfo->isIPv6) {
+ /* Because ipv6 fragment not first packet, doesn't exist
+ * header after fragment, thus release some data space*/
+ UINT32 behindFragHdrLen = (hdrSize - hdrInfo->l3Offset
+ - sizeof(IPv6Hdr) - beforeFragHdrLen);
+ if (behindFragHdrLen > 0) {
+ NdisAdvanceNetBufferDataStart(newNb,
+ behindFragHdrLen,
+ FALSE, NULL);
+ }
+
+ /* When it is not first ipv6 packet, we only need copy before
+ * ipv6 segment. */
+ status = NdisCopyFromNetBufferToNetBuffer(newNb, 0,
+ ip6StdHeaderLen,
+ nb, 0 , &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS ||
+ (hdrInfo->l3Offset + sizeof(IPv6Hdr)) != copiedSize) {
+ goto nblcopy_error;
+ }
+
+ if (beforeFragHdrLen) {
+ status = NdisCopyFromNetBufferToNetBuffer(newNb,
+ ip6StdHeaderLen,
+ beforeFragHdrLen,
+ nb,
+ ip6StdHeaderLen,
+ &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS ||
+ beforeFragHdrLen != copiedSize) {
+ goto nblcopy_error;
+ }
+ }
+
+ status = FixIPV6ExtHdrField(newNb, hdrInfo->l3Offset,
+ (ip6StdHeaderLen +
+ beforeFragHdrLen +
+ sizeof(IPv6FragHdr)),
+ segmentSize);
+ if (status != NDIS_STATUS_SUCCESS) {
+ OVS_LOG_ERROR("Invalid reassemble packet.");
+ goto nblcopy_error;
+ }
+ } else {
+ status = NdisCopyFromNetBufferToNetBuffer(newNb, 0, hdrSize,
+ nb, 0, &copiedSize);
+ if (status != NDIS_STATUS_SUCCESS ||
+ hdrSize != copiedSize) {
+ goto nblcopy_error;
+ }
+ }
}
if (isIpFragment) {
status = FixFragmentHeader(newNb, segmentSize,
NET_BUFFER_NEXT_NB(newNb) == NULL,
- offset);
+ offset, fragmentIdent);
} else {
status = FixSegmentHeader(newNb, segmentSize, seqNumber,
NET_BUFFER_NEXT_NB(newNb) == NULL,
@@ -1431,12 +1815,20 @@ OvsFragmentNBL(PVOID ovsContext,
}
if (status != NDIS_STATUS_SUCCESS) {
+ OVS_LOG_INFO("nbl copy error.");
goto nblcopy_error;
}
/* Move on to the next segment */
if (isIpFragment) {
- offset += (segmentSize) / 8;
+ if (NET_BUFFER_LIST_FIRST_NB(newNbl) == newNb &&
+ hdrInfo->isIPv6) {
+ offset += (segmentSize) / 8;
+ offset += (UINT16)((hdrSize - ip6StdHeaderLen -
+ beforeFragHdrLen) / 8);
+ } else {
+ offset += (segmentSize) / 8;
+ }
} else {
seqNumber += segmentSize;
}
@@ -1755,7 +2147,7 @@ OvsCompleteNBL(PVOID switch_ctx,
if (value == 1 && pendingSend == exchange) {
InterlockedExchange16((SHORT volatile *)&ctx->pendingSend, 0);
OvsSendNBLIngress(context, parent, ctx->sendFlags);
- } else if (value == 0){
+ } else if (value == 0) {
return OvsCompleteNBL(context, parent, FALSE);
}
}