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