summaryrefslogtreecommitdiff
path: root/datapath-windows/ovsext/Vxlan.c
diff options
context:
space:
mode:
authorAlin Serdean <aserdean@cloudbasesolutions.com>2015-09-30 21:16:55 +0000
committerBen Pfaff <blp@nicira.com>2015-10-02 07:22:49 -0700
commit89d762f3d5339a1f257de4298f48b535878ddf20 (patch)
tree3bca0e1fe9938510502d2b74f0642bbdf6a4ff9f /datapath-windows/ovsext/Vxlan.c
parent9f0c26b9bd116b13b52d050e990aa48e2393d98a (diff)
downloadopenvswitch-89d762f3d5339a1f257de4298f48b535878ddf20.tar.gz
datapath-windows: Compute checksums for VXLAN inner packets.
Windows does not support VXLAN hardware offloading. Currently we do not compute IP/TCP/UDP checksums for the inner packet. This patch computes the checksums mentioned above in regards with the enabled settings. i.e. if IP checksum offloading is enabled for the inner packet we compute it. The same applies for TCP and UDP packets. This patch also revizes the computation of ones' complement over different memory blocks, in the case the lengths are odd. Also per documentation: https://msdn.microsoft.com/en-us/library/windows/hardware/ff568840%28v=vs.85%29.aspx set the TCP flags FIN and PSH only for the last segment in the case LSO is enabled. Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com> Acked-by: Sairam Venugopal <vsairam@vmware.com> Acked-by: Sorin Vinturis <svinturis@cloudbasesolutions.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'datapath-windows/ovsext/Vxlan.c')
-rw-r--r--datapath-windows/ovsext/Vxlan.c84
1 files changed, 75 insertions, 9 deletions
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
index 2364f2868..c0611dad5 100644
--- a/datapath-windows/ovsext/Vxlan.c
+++ b/datapath-windows/ovsext/Vxlan.c
@@ -152,9 +152,9 @@ OvsCleanupVxlanTunnel(PIRP irp,
if (vxlanPort->filterID != 0) {
status = OvsTunnelFilterDelete(irp,
- vxlanPort->filterID,
- callback,
- tunnelContext);
+ vxlanPort->filterID,
+ callback,
+ tunnelContext);
} else {
OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
vport->priv = NULL;
@@ -198,20 +198,24 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
*/
curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
packetLength = NET_BUFFER_DATA_LENGTH(curNb);
+
if (layers->isTcp) {
NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo;
tsoInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
- TcpLargeSendNetBufferListInfo);
- OVS_LOG_TRACE("MSS %u packet len %u", tsoInfo.LsoV1Transmit.MSS, packetLength);
+ TcpLargeSendNetBufferListInfo);
+ OVS_LOG_TRACE("MSS %u packet len %u", tsoInfo.LsoV1Transmit.MSS,
+ packetLength);
if (tsoInfo.LsoV1Transmit.MSS) {
OVS_LOG_TRACE("l4Offset %d", layers->l4Offset);
*newNbl = OvsTcpSegmentNBL(switchContext, curNbl, layers,
- tsoInfo.LsoV1Transmit.MSS, headRoom);
+ tsoInfo.LsoV1Transmit.MSS, headRoom);
if (*newNbl == NULL) {
OVS_LOG_ERROR("Unable to segment NBL");
return NDIS_STATUS_FAILURE;
}
+ /* Clear out LSO flags after this point */
+ NET_BUFFER_LIST_INFO(*newNbl, TcpLargeSendNetBufferListInfo) = 0;
}
}
@@ -226,6 +230,70 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
OVS_LOG_ERROR("Unable to copy NBL");
return NDIS_STATUS_FAILURE;
}
+ /*
+ * To this point we do not have VXLAN offloading.
+ * Apply defined checksums
+ */
+ curNb = NET_BUFFER_LIST_FIRST_NB(*newNbl);
+ curMdl = NET_BUFFER_CURRENT_MDL(curNb);
+ bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
+ if (!bufferStart) {
+ status = NDIS_STATUS_RESOURCES;
+ goto ret_error;
+ }
+
+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
+ csumInfo.Value = NET_BUFFER_LIST_INFO(curNbl,
+ TcpIpChecksumNetBufferListInfo);
+
+ bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
+
+ if (layers->isIPv4) {
+ IPHdr *ip = (IPHdr *)(bufferStart + layers->l3Offset);
+
+ if (csumInfo.Transmit.IpHeaderChecksum) {
+ ip->check = 0;
+ ip->check = IPChecksum((UINT8 *)ip, 4 * ip->ihl, 0);
+ }
+
+ if (layers->isTcp && csumInfo.Transmit.TcpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset);
+ tcp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr,
+ IPPROTO_TCP, csumLength);
+ tcp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip);
+ udp->check = IPPseudoChecksum(&ip->saddr, &ip->daddr,
+ IPPROTO_UDP, csumLength);
+ udp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ }
+ } else if (layers->isIPv6) {
+ IPv6Hdr *ip = (IPv6Hdr *)(bufferStart + layers->l3Offset);
+
+ if (layers->isTcp && csumInfo.Transmit.TcpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ TCPHdr *tcp = (TCPHdr *)(bufferStart + layers->l4Offset);
+ tcp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr,
+ (UINT32 *) &ip->daddr,
+ IPPROTO_TCP, csumLength);
+ tcp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ } else if (layers->isUdp && csumInfo.Transmit.UdpChecksum) {
+ UINT16 csumLength = (UINT16)(packetLength - layers->l4Offset);
+ UDPHdr *udp = (UDPHdr *)((PCHAR)ip + sizeof *ip);
+ udp->check = IPv6PseudoChecksum((UINT32 *) &ip->saddr,
+ (UINT32 *) &ip->daddr,
+ IPPROTO_UDP, csumLength);
+ udp->check = CalculateChecksumNB(curNb, csumLength,
+ (UINT32)(layers->l4Offset));
+ }
+ }
+ /* Clear out TcpIpChecksumNetBufferListInfo flag */
+ NET_BUFFER_LIST_INFO(*newNbl, TcpIpChecksumNetBufferListInfo) = 0;
}
curNbl = *newNbl;
@@ -257,9 +325,6 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
sizeof ethHdr->Destination + sizeof ethHdr->Source);
ethHdr->Type = htons(ETH_TYPE_IPV4);
- // XXX: question: there are fields in the OvsIPv4TunnelKey for ttl and such,
- // should we use those values instead? or will they end up being
- // uninitialized;
/* IP header */
ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
@@ -277,6 +342,7 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
ASSERT(tunKey->src == fwdInfo->srcIpAddr || tunKey->src == 0);
ipHdr->saddr = fwdInfo->srcIpAddr;
ipHdr->daddr = fwdInfo->dstIpAddr;
+
ipHdr->check = 0;
ipHdr->check = IPChecksum((UINT8 *)ipHdr, sizeof *ipHdr, 0);