Added support for IPv6 GRE tunnelling.

Tested using PING and iperf.

Signed-off-by: Sorin Vinturis <svintu...@cloudbasesolutions.com>
---
 datapath-windows/ovsext/Actions.c |   2 +-
 datapath-windows/ovsext/Gre.c     | 141 +++++++++++++++++++++++++-------------
 datapath-windows/ovsext/Gre.h     |   6 +-
 3 files changed, 100 insertions(+), 49 deletions(-)

diff --git a/datapath-windows/ovsext/Actions.c 
b/datapath-windows/ovsext/Actions.c
index 250ac13..69c87e8 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -768,7 +768,7 @@ OvsTunnelPortRx(OvsForwardingContext *ovsFwdCtx)
     switch(tunnelRxVport->ovsType) {
     case OVS_VPORT_TYPE_GRE:
         status = OvsDecapGre(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
-                             &ovsFwdCtx->tunKey, &newNbl);
+                             &ovsFwdCtx->tunKey, &ovsFwdCtx->layers, &newNbl);
         break;
     case OVS_VPORT_TYPE_VXLAN:
         status = OvsDecapVxlan(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
diff --git a/datapath-windows/ovsext/Gre.c b/datapath-windows/ovsext/Gre.c
index 0ceaab5..c33bec8 100644
--- a/datapath-windows/ovsext/Gre.c
+++ b/datapath-windows/ovsext/Gre.c
@@ -132,16 +132,20 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport,
     PMDL curMdl;
     PUINT8 bufferStart;
     EthHdr *ethHdr;
-    IPHdr *ipHdr;
     PGREHdr greHdr;
     POVS_GRE_VPORT vportGre;
-    UINT32 headRoom = GreTunHdrSize(tunKey->flags);
+    UINT32 headRoom =
+        GreTunHdrSize(tunKey->flags,
+                      fwdInfo->dstIpAddr.si_family == AF_INET ? TRUE : FALSE);
 #if DBG
     UINT32 counterHeadRoom;
 #endif
     UINT32 packetLength;
     ULONG mss = 0;
     ASSERT(*newNbl == NULL);
+    ASSERT(IsEqualIpAddr(&tunKey->dst, &fwdInfo->dstIpAddr));
+    ASSERT(IsEqualIpAddr(&tunKey->src, &fwdInfo->srcIpAddr) ||
+           IsNullIpAddr(&tunKey->src));
 
     curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
     packetLength = NET_BUFFER_DATA_LENGTH(curNb);
@@ -218,38 +222,61 @@ OvsDoEncapGre(POVS_VPORT_ENTRY vport,
                (PCHAR)&fwdInfo->srcMacAddr);
         NdisMoveMemory(ethHdr->Destination, fwdInfo->dstMacAddr,
                        sizeof ethHdr->Destination + sizeof ethHdr->Source);
-        ethHdr->Type = htons(ETH_TYPE_IPV4);
 #if DBG
         counterHeadRoom -= sizeof *ethHdr;
 #endif
 
-        /* IP header */
-        ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
-
-        ipHdr->ihl = sizeof *ipHdr / 4;
-        ipHdr->version = IPPROTO_IPV4;
-        ipHdr->tos = tunKey->tos;
-        ipHdr->tot_len = htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof *ethHdr);
-        ipHdr->id = (uint16)atomic_add64(&vportGre->ipId,
-                                         NET_BUFFER_DATA_LENGTH(curNb));
-        ipHdr->frag_off = (tunKey->flags & OVS_TNL_F_DONT_FRAGMENT) ?
-                          IP_DF_NBO : 0;
-        ipHdr->ttl = tunKey->ttl ? tunKey->ttl : 64;
-        ipHdr->protocol = IPPROTO_GRE;
-        ASSERT(IsEqualIpAddr(&tunKey->dst, &fwdInfo->dstIpAddr));
-        ASSERT(IsEqualIpAddr(&tunKey->src, &fwdInfo->srcIpAddr) ||
-               IsNullIpAddr(&tunKey->src));
-        ipHdr->saddr = fwdInfo->srcIpAddr.Ipv4.sin_addr.s_addr;
-        ipHdr->daddr = fwdInfo->dstIpAddr.Ipv4.sin_addr.s_addr;
-
-        ipHdr->check = 0;
-        ipHdr->check = IPChecksum((UINT8 *)ipHdr, sizeof *ipHdr, 0);
+        if (fwdInfo->dstIpAddr.si_family == AF_INET) {
+            IPHdr *ipv4Hdr;
+            ethHdr->Type = ETH_TYPE_IPV4_NBO;
+
+            /* IPv4 header */
+            ipv4Hdr = (IPHdr *)((PCHAR)ethHdr + sizeof(*ethHdr));
+
+            ipv4Hdr->ihl = sizeof(*ipv4Hdr) / 4;
+            ipv4Hdr->version = IPPROTO_IPV4;
+            ipv4Hdr->tos = tunKey->tos;
+            ipv4Hdr->tot_len =
+                htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof(*ethHdr));
+            ipv4Hdr->id = (uint16)atomic_add64(&vportGre->ipId,
+                                               NET_BUFFER_DATA_LENGTH(curNb));
+            ipv4Hdr->frag_off = (tunKey->flags & OVS_TNL_F_DONT_FRAGMENT) ?
+                              IP_DF_NBO : 0;
+            ipv4Hdr->ttl = tunKey->ttl ? tunKey->ttl : 64;
+            ipv4Hdr->protocol = IPPROTO_GRE;
+            ipv4Hdr->saddr = fwdInfo->srcIpAddr.Ipv4.sin_addr.s_addr;
+            ipv4Hdr->daddr = fwdInfo->dstIpAddr.Ipv4.sin_addr.s_addr;
+
+            ipv4Hdr->check = 0;
+            ipv4Hdr->check = IPChecksum((UINT8 *)ipv4Hdr, sizeof(*ipv4Hdr), 0);
 #if DBG
-        counterHeadRoom -= sizeof *ipHdr;
+            counterHeadRoom -= sizeof(*ipv4Hdr);
 #endif
 
+            greHdr = (GREHdr *)((PCHAR)ipv4Hdr + sizeof(*ipv4Hdr));
+        } else {
+            IPv6Hdr *ipv6Hdr;
+            ASSERT(fwdInfo->dstIpAddr.si_family == AF_INET6);
+            ethHdr->Type = ETH_TYPE_IPV6_NBO;
+
+            ipv6Hdr = (IPv6Hdr *)((PCHAR)ethHdr + sizeof(*ethHdr));
+            ipv6Hdr->version = IPPROTO_IPV6;
+            ipv6Hdr->priority = (tunKey->tos & 0xF0) >> 4;
+            ipv6Hdr->flow_lbl[0] = (tunKey->tos & 0x0F) << 4;
+            ipv6Hdr->payload_len =
+                htons(NET_BUFFER_DATA_LENGTH(curNb) - sizeof(*ethHdr));
+            ipv6Hdr->nexthdr = IPPROTO_GRE;
+            ipv6Hdr->hop_limit = tunKey->ttl ? tunKey->ttl : 64;
+            ipv6Hdr->saddr = fwdInfo->srcIpAddr.Ipv6.sin6_addr;
+            ipv6Hdr->daddr = fwdInfo->dstIpAddr.Ipv6.sin6_addr;
+#if DBG
+            counterHeadRoom -= sizeof(*ipv6Hdr);
+#endif
+
+            greHdr = (GREHdr *)((PCHAR)ipv6Hdr + sizeof(*ipv6Hdr));
+        }
+
         /* GRE header */
-        greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
         greHdr->flags = OvsTunnelFlagsToGreFlags(tunKey->flags);
         greHdr->protocolType = GRE_NET_TEB;
 #if DBG
@@ -293,21 +320,21 @@ NDIS_STATUS
 OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
             PNET_BUFFER_LIST curNbl,
             OvsIPTunnelKey *tunKey,
+            POVS_PACKET_HDR_INFO layers,
             PNET_BUFFER_LIST *newNbl)
 {
     PNET_BUFFER curNb;
     PMDL curMdl;
     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);
+    tunnelSize = GreTunHdrSize(tunKey->flags, layers->isIPv4 ? TRUE : FALSE);
     if (packetLength <= tunnelSize) {
         return NDIS_STATUS_INVALID_LENGTH;
     }
@@ -326,27 +353,45 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
     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);
+    bufferStart =
+        (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
     if (!bufferStart) {
         status = NDIS_STATUS_RESOURCES;
         goto dropNbl;
     }
+    bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
 
     ethHdr = (EthHdr *)bufferStart;
-    headRoom += sizeof *ethHdr;
-
-    ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof *ethHdr);
-    tunKey->src.Ipv4.sin_addr.s_addr = ipHdr->saddr;
-    tunKey->src.Ipv4.sin_family = AF_INET;
-    tunKey->dst.Ipv4.sin_addr.s_addr = ipHdr->daddr;
-    tunKey->dst.Ipv4.sin_family = AF_INET;
-    tunKey->tos = ipHdr->tos;
-    tunKey->ttl = ipHdr->ttl;
-    tunKey->pad = 0;
-    headRoom += sizeof *ipHdr;
-
-    greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
+    headRoom += sizeof(*ethHdr);
+
+    if (ethHdr->Type == ETH_TYPE_IPV4_NBO) {
+        IPHdr *ipHdr;
+        ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof(*ethHdr));
+        tunKey->src.Ipv4.sin_addr.s_addr = ipHdr->saddr;
+        tunKey->src.si_family = AF_INET;
+        tunKey->dst.Ipv4.sin_addr.s_addr = ipHdr->daddr;
+        tunKey->dst.si_family = AF_INET;
+        tunKey->tos = ipHdr->tos;
+        tunKey->ttl = ipHdr->ttl;
+        tunKey->pad = 0;
+        headRoom += sizeof(*ipHdr);
+        greHdr = (GREHdr *)((PCHAR)ipHdr + sizeof(*ipHdr));
+    } else {
+        IPv6Hdr *ipv6Hdr;
+        ASSERT(ethHdr->Type == ETH_TYPE_IPV6_NBO);
+        ipv6Hdr = (IPv6Hdr *)((PCHAR)ethHdr + sizeof(*ethHdr));
+        tunKey->src.Ipv6.sin6_addr = ipv6Hdr->saddr;
+        tunKey->src.si_family = AF_INET6;
+        tunKey->dst.Ipv6.sin6_addr = ipv6Hdr->daddr;
+        tunKey->dst.si_family = AF_INET6;
+        tunKey->tos = (ipv6Hdr->priority << 4) |
+                      ((ipv6Hdr->flow_lbl[0] & 0xF0) >> 4);
+        tunKey->ttl = ipv6Hdr->hop_limit;
+        tunKey->pad = 0;
+        headRoom += sizeof(*ipv6Hdr);
+        greHdr = (GREHdr *)((PCHAR)ipv6Hdr + sizeof(*ipv6Hdr));
+    }
+
     headRoom += sizeof *greHdr;
 
     /* Validate if GRE header protocol type. */
@@ -374,9 +419,13 @@ OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
 
     /* 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(tunKey->flags,
+                                                layers->isIPv4 ? TRUE : FALSE),
+                                  FALSE,
                                   NULL);
-    ASSERT(headRoom == GreTunHdrSize(tunKey->flags));
+    ASSERT(headRoom == GreTunHdrSize(tunKey->flags,
+                                     layers->isIPv4 ? TRUE : FALSE));
     return NDIS_STATUS_SUCCESS;
 
 dropNbl:
diff --git a/datapath-windows/ovsext/Gre.h b/datapath-windows/ovsext/Gre.h
index d560491..a4aa459 100644
--- a/datapath-windows/ovsext/Gre.h
+++ b/datapath-windows/ovsext/Gre.h
@@ -69,6 +69,7 @@ NDIS_STATUS OvsEncapGre(POVS_VPORT_ENTRY vport,
 NDIS_STATUS OvsDecapGre(POVS_SWITCH_CONTEXT switchContext,
                         PNET_BUFFER_LIST curNbl,
                         OvsIPTunnelKey *tunKey,
+                        POVS_PACKET_HDR_INFO layers,
                         PNET_BUFFER_LIST *newNbl);
 
 static __inline UINT16
@@ -86,9 +87,10 @@ OvsTunnelFlagsToGreFlags(UINT16 tunnelflags)
 }
 
 static __inline UINT32
-GreTunHdrSize(UINT16 flags)
+GreTunHdrSize(UINT16 flags, BOOLEAN isIpv4)
 {
-    UINT32 sum = sizeof(EthHdr) + sizeof(IPHdr) + sizeof(GREHdr);
+    UINT32 sum = sizeof(EthHdr) + (isIpv4 ? sizeof(IPHdr) : sizeof(IPv6Hdr)) +
+                 sizeof(GREHdr);
     sum += (flags & OVS_TNL_F_CSUM) ?
            4 : 0;
     sum += (flags & OVS_TNL_F_KEY) ?
-- 
1.9.0.msysgit.0
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to