[ovs-dev] [PATCH 3/5] datapath-windows: IPv6 support for VXLAN
Sorin Vinturis
svinturis at cloudbasesolutions.com
Tue May 31 22:45:22 UTC 2016
Added support for IPv6 VXLAN tunnelling.
Tested using PING and iperf.
Signed-off-by: Sorin Vinturis <svinturis at cloudbasesolutions.com>
---
datapath-windows/ovsext/Actions.c | 120 ++++++++++++++----------
datapath-windows/ovsext/Flow.c | 66 +++++++++++---
datapath-windows/ovsext/Vxlan.c | 187 ++++++++++++++++++++++++++------------
datapath-windows/ovsext/Vxlan.h | 7 +-
4 files changed, 257 insertions(+), 123 deletions(-)
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index ead9741..250ac13 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -216,8 +216,19 @@ OvsDetectTunnelRxPkt(OvsForwardingContext *ovsFwdCtx,
* packets only if they are at least VXLAN header size.
*/
if (!flowKey->ipKey.nwFrag) {
- UINT16 dstPort = htons(flowKey->ipKey.l4.tpDst);
- switch (flowKey->ipKey.nwProto) {
+ UINT16 dstPort;
+ UINT8 nwProto;
+
+ if (flowKey->l2.dlType == ETH_TYPE_IPV4_NBO) {
+ nwProto = flowKey->ipKey.nwProto;
+ dstPort = htons(flowKey->ipKey.l4.tpDst);
+ } else {
+ ASSERT(flowKey->l2.dlType == ETH_TYPE_IPV6_NBO);
+ nwProto = flowKey->ipv6Key.nwProto;
+ dstPort = htons(flowKey->ipv6Key.l4.tpDst);
+ }
+
+ switch (nwProto) {
case IPPROTO_GRE:
tunnelVport = OvsFindTunnelVportByPortType(ovsFwdCtx->switchContext,
OVS_VPORT_TYPE_GRE);
@@ -761,7 +772,7 @@ OvsTunnelPortRx(OvsForwardingContext *ovsFwdCtx)
break;
case OVS_VPORT_TYPE_VXLAN:
status = OvsDecapVxlan(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
- &ovsFwdCtx->tunKey, &newNbl);
+ &ovsFwdCtx->tunKey, &ovsFwdCtx->layers, &newNbl);
break;
case OVS_VPORT_TYPE_STT:
status = OvsDecapStt(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
@@ -1238,55 +1249,68 @@ OvsActionMplsPush(OvsForwardingContext *ovsFwdCtx,
/*
* --------------------------------------------------------------------------
- * OvsTunnelAttrToIPv4TunnelKey --
+ * OvsTunnelAttrToIPTunnelKey --
* Convert tunnel attribute to OvsIPTunnelKey.
* --------------------------------------------------------------------------
*/
static __inline NDIS_STATUS
-OvsTunnelAttrToIPv4TunnelKey(PNL_ATTR attr,
- OvsIPTunnelKey *tunKey)
+OvsTunnelAttrToIPTunnelKey(PNL_ATTR attr,
+ OvsIPTunnelKey *tunKey)
{
- PNL_ATTR a;
- INT rem;
-
- ASSERT(NlAttrType(attr) == OVS_KEY_ATTR_TUNNEL);
- for (UINT32 i = 0; i < sizeof(*tunKey) / sizeof(UINT64); i++) {
- tunKey->attr[i] = 0;
- }
-
- NL_ATTR_FOR_EACH_UNSAFE (a, rem, NlAttrData(attr),
- NlAttrGetSize(attr)) {
- switch (NlAttrType(a)) {
- case OVS_TUNNEL_KEY_ATTR_ID:
- tunKey->tunnelId = NlAttrGetBe64(a);
- tunKey->flags |= OVS_TNL_F_KEY;
- break;
- case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
- tunKey->src.Ipv4.sin_addr.s_addr = NlAttrGetBe32(a);
- tunKey->src.si_family = AF_INET;
- break;
- case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
- tunKey->dst.Ipv4.sin_addr.s_addr = NlAttrGetBe32(a);
- tunKey->dst.si_family = AF_INET;
- break;
- case OVS_TUNNEL_KEY_ATTR_TOS:
- tunKey->tos = NlAttrGetU8(a);
- break;
- case OVS_TUNNEL_KEY_ATTR_TTL:
- tunKey->ttl = NlAttrGetU8(a);
- break;
- case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
- tunKey->flags |= OVS_TNL_F_DONT_FRAGMENT;
- break;
- case OVS_TUNNEL_KEY_ATTR_CSUM:
- tunKey->flags |= OVS_TNL_F_CSUM;
- break;
- default:
- ASSERT(0);
- }
- }
-
- return NDIS_STATUS_SUCCESS;
+ PNL_ATTR a;
+ INT rem;
+
+ ASSERT(NlAttrType(attr) == OVS_KEY_ATTR_TUNNEL);
+ for (UINT32 i = 0; i < sizeof(*tunKey) / sizeof(UINT64); i++) {
+ tunKey->attr[i] = 0;
+ }
+
+ NL_ATTR_FOR_EACH_UNSAFE(a, rem, NlAttrData(attr), NlAttrGetSize(attr)) {
+ switch (NlAttrType(a)) {
+ case OVS_TUNNEL_KEY_ATTR_ID:
+ tunKey->tunnelId = NlAttrGetBe64(a);
+ tunKey->flags |= OVS_TNL_F_KEY;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
+ tunKey->src.Ipv4.sin_addr.s_addr = NlAttrGetBe32(a);
+ tunKey->src.si_family = AF_INET;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
+ tunKey->dst.Ipv4.sin_addr.s_addr = NlAttrGetBe32(a);
+ tunKey->dst.si_family = AF_INET;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
+ RtlCopyMemory(&tunKey->src.Ipv6.sin6_addr,
+ NlAttrGetUnspec(a,
+ sizeof(tunKey->src.Ipv6.sin6_addr)),
+ sizeof(tunKey->src.Ipv6.sin6_addr));
+ tunKey->src.si_family = AF_INET6;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV6_DST:
+ RtlCopyMemory(&tunKey->dst.Ipv6.sin6_addr,
+ NlAttrGetUnspec(a,
+ sizeof(tunKey->dst.Ipv6.sin6_addr)),
+ sizeof(tunKey->dst.Ipv6.sin6_addr));
+ tunKey->dst.si_family = AF_INET6;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_TOS:
+ tunKey->tos = NlAttrGetU8(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_TTL:
+ tunKey->ttl = NlAttrGetU8(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+ tunKey->flags |= OVS_TNL_F_DONT_FRAGMENT;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_CSUM:
+ tunKey->flags |= OVS_TNL_F_CSUM;
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
}
/*
@@ -1517,7 +1541,7 @@ OvsExecuteSetAction(OvsForwardingContext *ovsFwdCtx,
case OVS_KEY_ATTR_TUNNEL:
{
OvsIPTunnelKey tunKey;
- status = OvsTunnelAttrToIPv4TunnelKey((PNL_ATTR)a, &tunKey);
+ status = OvsTunnelAttrToIPTunnelKey((PNL_ATTR)a, &tunKey);
ASSERT(status == NDIS_STATUS_SUCCESS);
tunKey.flow_hash = (uint16)(hash ? *hash : OvsHashFlow(key));
tunKey.dst_port = key->ipKey.l4.tpDst;
diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c
index 1eb5102..9470e3c 100644
--- a/datapath-windows/ovsext/Flow.c
+++ b/datapath-windows/ovsext/Flow.c
@@ -189,7 +189,7 @@ const NL_POLICY nlFlowTunnelKeyPolicy[] = {
.maxLen = 8, .optional = TRUE},
[OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = {.type = NL_A_UNSPEC, .minLen = 4,
.maxLen = 4, .optional = TRUE},
- [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = {.type = NL_A_UNSPEC, .minLen = 4 ,
+ [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = {.type = NL_A_UNSPEC, .minLen = 4,
.maxLen = 4, .optional = FALSE},
[OVS_TUNNEL_KEY_ATTR_TOS] = {.type = NL_A_UNSPEC, .minLen = 1,
.maxLen = 1, .optional = TRUE},
@@ -1005,16 +1005,34 @@ MapFlowTunKeyToNlKey(PNL_BUFFER nlBuf,
goto done;
}
- if (!NlMsgPutTailU32(nlBuf, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
- tunKey->dst.Ipv4.sin_addr.s_addr)) {
- rc = STATUS_UNSUCCESSFUL;
- goto done;
+ if (tunKey->dst.si_family == AF_INET) {
+ if (!NlMsgPutTailU32(nlBuf, OVS_TUNNEL_KEY_ATTR_IPV4_DST,
+ tunKey->dst.Ipv4.sin_addr.s_addr)) {
+ rc = STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ } else { // tunKey->dst.si_family == AF_INET6
+ if (!NlMsgPutTailUnspec(nlBuf, OVS_TUNNEL_KEY_ATTR_IPV6_DST,
+ (PCHAR)&tunKey->dst.Ipv6.sin6_addr,
+ sizeof(tunKey->dst.Ipv6.sin6_addr))) {
+ rc = STATUS_UNSUCCESSFUL;
+ goto done;
+ }
}
- if (!NlMsgPutTailU32(nlBuf, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
- tunKey->src.Ipv4.sin_addr.s_addr)) {
- rc = STATUS_UNSUCCESSFUL;
- goto done;
+ if (tunKey->src.si_family == AF_INET) {
+ if (!NlMsgPutTailU32(nlBuf, OVS_TUNNEL_KEY_ATTR_IPV4_SRC,
+ tunKey->src.Ipv4.sin_addr.s_addr)) {
+ rc = STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ } else { // tunKey->src.si_family == AF_INET6
+ if (!NlMsgPutTailUnspec(nlBuf, OVS_TUNNEL_KEY_ATTR_IPV6_SRC,
+ (PCHAR)&tunKey->src.Ipv6.sin6_addr,
+ sizeof(tunKey->src.Ipv6.sin6_addr))) {
+ rc = STATUS_UNSUCCESSFUL;
+ goto done;
+ }
}
if (!NlMsgPutTailU8(nlBuf, OVS_TUNNEL_KEY_ATTR_TOS,
@@ -1653,15 +1671,33 @@ MapTunAttrToFlowPut(PNL_ATTR *keyAttrs,
}
if (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_DST]) {
- destKey->tunKey.dst.si_family = AF_INET;
- destKey->tunKey.dst.Ipv4.sin_addr.s_addr =
- NlAttrGetU32(tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_DST]);
+ destKey->tunKey.dst.si_family = AF_INET;
+ destKey->tunKey.dst.Ipv4.sin_addr.s_addr =
+ NlAttrGetU32(tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_DST]);
}
if (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]) {
- destKey->tunKey.src.si_family = AF_INET;
- destKey->tunKey.src.Ipv4.sin_addr.s_addr =
- NlAttrGetU32(tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]);
+ destKey->tunKey.src.si_family = AF_INET;
+ destKey->tunKey.src.Ipv4.sin_addr.s_addr =
+ NlAttrGetU32(tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV4_SRC]);
+ }
+
+ if (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV6_DST]) {
+ destKey->tunKey.dst.si_family = AF_INET6;
+ RtlCopyMemory(&destKey->tunKey.dst.Ipv6.sin6_addr,
+ NlAttrGetUnspec(
+ tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV6_DST],
+ sizeof(destKey->tunKey.dst.Ipv6.sin6_addr)),
+ sizeof(destKey->tunKey.dst.Ipv6.sin6_addr));
+ }
+
+ if (tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV6_SRC]) {
+ destKey->tunKey.src.si_family = AF_INET6;
+ RtlCopyMemory(&destKey->tunKey.src.Ipv6.sin6_addr,
+ NlAttrGetUnspec(
+ tunAttrs[OVS_TUNNEL_KEY_ATTR_IPV6_SRC],
+ sizeof(destKey->tunKey.src.Ipv6.sin6_addr)),
+ sizeof(destKey->tunKey.src.Ipv6.sin6_addr));
}
if (tunAttrs[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT]) {
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
index 7f64acc..a2c132c 100644
--- a/datapath-windows/ovsext/Vxlan.c
+++ b/datapath-windows/ovsext/Vxlan.c
@@ -185,14 +185,19 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
PMDL curMdl;
PUINT8 bufferStart;
EthHdr *ethHdr;
- IPHdr *ipHdr;
UDPHdr *udpHdr;
VXLANHdr *vxlanHdr;
POVS_VXLAN_VPORT vportVxlan;
- UINT32 headRoom = OvsGetVxlanTunHdrSize();
+ UINT32 headRoom =
+ OvsGetVxlanTunHdrSize(fwdInfo->dstIpAddr.si_family == AF_INET ?
+ TRUE : FALSE);
UINT32 packetLength;
ULONG mss = 0;
+ ASSERT(IsEqualIpAddr(&tunKey->dst, &fwdInfo->dstIpAddr));
+ ASSERT(IsEqualIpAddr(&tunKey->src, &fwdInfo->srcIpAddr) ||
+ IsNullIpAddr(&tunKey->src));
+
/*
* XXX: the assumption currently is that the NBL is owned by OVS, and
* headroom has already been allocated as part of allocating the NBL and
@@ -249,7 +254,8 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
}
curMdl = NET_BUFFER_CURRENT_MDL(curNb);
- bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
+ bufferStart =
+ (PUINT8)MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
if (!bufferStart) {
status = NDIS_STATUS_RESOURCES;
goto ret_error;
@@ -257,50 +263,71 @@ OvsDoEncapVxlan(POVS_VPORT_ENTRY vport,
bufferStart += NET_BUFFER_CURRENT_MDL_OFFSET(curNb);
if (NET_BUFFER_NEXT_NB(curNb)) {
- OVS_LOG_TRACE("nb length %u next %u", NET_BUFFER_DATA_LENGTH(curNb),
+ OVS_LOG_TRACE("nb length %u next %u",
+ NET_BUFFER_DATA_LENGTH(curNb),
NET_BUFFER_DATA_LENGTH(curNb->Next));
}
/* L2 header */
ethHdr = (EthHdr *)bufferStart;
- ASSERT(((PCHAR)&fwdInfo->dstMacAddr + sizeof fwdInfo->dstMacAddr) ==
+ ASSERT(((PCHAR)&fwdInfo->dstMacAddr + sizeof(fwdInfo->dstMacAddr)) ==
(PCHAR)&fwdInfo->srcMacAddr);
NdisMoveMemory(ethHdr->Destination, fwdInfo->dstMacAddr,
- sizeof ethHdr->Destination + sizeof ethHdr->Source);
- ethHdr->Type = htons(ETH_TYPE_IPV4);
-
- /* 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(&vportVxlan->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 : VXLAN_DEFAULT_TTL;
- ipHdr->protocol = IPPROTO_UDP;
- 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);
+ sizeof(ethHdr->Destination) + sizeof(ethHdr->Source));
+
+ 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(&vportVxlan->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 : VXLAN_DEFAULT_TTL;
+ ipv4Hdr->protocol = IPPROTO_UDP;
+ 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);
+
+ udpHdr = (UDPHdr *)((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_UDP;
+ ipv6Hdr->hop_limit = tunKey->ttl ? tunKey->ttl : VXLAN_DEFAULT_TTL;
+ ipv6Hdr->saddr = fwdInfo->srcIpAddr.Ipv6.sin6_addr;
+ ipv6Hdr->daddr = fwdInfo->dstIpAddr.Ipv6.sin6_addr;
+
+ udpHdr = (UDPHdr *)((PCHAR)ipv6Hdr + sizeof(*ipv6Hdr));
+ }
/* UDP header */
- udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
udpHdr->source = htons(tunKey->flow_hash | MAXINT16);
udpHdr->dest = htons(vportVxlan->dstPort);
udpHdr->len = htons(NET_BUFFER_DATA_LENGTH(curNb) - headRoom +
- sizeof *udpHdr + sizeof *vxlanHdr);
+ sizeof(*udpHdr) + sizeof(*vxlanHdr));
udpHdr->check = 0;
/* VXLAN header */
- vxlanHdr = (VXLANHdr *)((PCHAR)udpHdr + sizeof *udpHdr);
+ vxlanHdr = (VXLANHdr *)((PCHAR)udpHdr + sizeof(*udpHdr));
vxlanHdr->flags1 = 0;
vxlanHdr->locallyReplicate = 0;
vxlanHdr->flags2 = 0;
@@ -363,7 +390,7 @@ OvsEncapVxlan(POVS_VPORT_ENTRY vport,
static __inline NDIS_STATUS
OvsCalculateUDPChecksum(PNET_BUFFER_LIST curNbl,
PNET_BUFFER curNb,
- IPHdr *ipHdr,
+ EthHdr *ethHdr,
UDPHdr *udpHdr,
UINT32 packetLength)
{
@@ -378,14 +405,40 @@ OvsCalculateUDPChecksum(PNET_BUFFER_LIST curNbl,
checkSum = udpHdr->check;
- l4Payload = packetLength - sizeof(EthHdr) - ipHdr->ihl * 4;
- udpHdr->check = 0;
- udpHdr->check =
- IPPseudoChecksum((UINT32 *)&ipHdr->saddr,
- (UINT32 *)&ipHdr->daddr,
- IPPROTO_UDP, (UINT16)l4Payload);
- udpHdr->check = CalculateChecksumNB(curNb, (UINT16)l4Payload,
- sizeof(EthHdr) + ipHdr->ihl * 4);
+ switch (ethHdr->Type) {
+ case ETH_TYPE_IPV4_NBO: {
+ IPHdr *ipHdr = (IPHdr *)((PCHAR)ethHdr + sizeof(*ethHdr));
+
+ l4Payload = packetLength - sizeof(EthHdr) - ipHdr->ihl * 4;
+ udpHdr->check = 0;
+ udpHdr->check =
+ IPPseudoChecksum((UINT32 *)&ipHdr->saddr,
+ (UINT32 *)&ipHdr->daddr,
+ IPPROTO_UDP, (UINT16)l4Payload);
+ udpHdr->check =
+ CalculateChecksumNB(curNb, (UINT16)l4Payload,
+ sizeof(EthHdr) + ipHdr->ihl * 4);
+ break;
+ }
+ case ETH_TYPE_IPV6_NBO: {
+ IPv6Hdr *ipv6Hdr = (IPv6Hdr *)((PCHAR)ethHdr + sizeof(*ethHdr));
+
+ l4Payload = packetLength - sizeof(EthHdr) - sizeof(IPv6Hdr);
+ udpHdr->check = 0;
+ udpHdr->check =
+ IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->saddr,
+ (UINT32 *)&ipv6Hdr->daddr,
+ IPPROTO_UDP, (UINT16)l4Payload);
+ udpHdr->check =
+ CalculateChecksumNB(curNb, (UINT16)l4Payload,
+ sizeof(EthHdr) + sizeof(IPv6Hdr));
+ break;
+ }
+ default:
+ OVS_LOG_ERROR("Invalid eth type: %d\n", ethHdr->Type);
+ ASSERT(!"Invalid eth type");
+ }
+
if (checkSum != udpHdr->check) {
OVS_LOG_TRACE("UDP checksum incorrect.");
return NDIS_STATUS_INVALID_PACKET;
@@ -407,12 +460,12 @@ NDIS_STATUS
OvsDecapVxlan(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;
UDPHdr *udpHdr;
VXLANHdr *vxlanHdr;
UINT32 tunnelSize = 0, packetLength = 0;
@@ -422,7 +475,7 @@ OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
/* Check the length of the UDP payload */
curNb = NET_BUFFER_LIST_FIRST_NB(curNbl);
packetLength = NET_BUFFER_DATA_LENGTH(curNb);
- tunnelSize = OvsGetVxlanTunHdrSize();
+ tunnelSize = OvsGetVxlanTunHdrSize(layers->isIPv4 ? TRUE : FALSE);
if (packetLength <= tunnelSize) {
return NDIS_STATUS_INVALID_LENGTH;
}
@@ -442,24 +495,42 @@ OvsDecapVxlan(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;
- /* XXX: Handle IP options. */
- 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;
- udpHdr = (UDPHdr *)((PCHAR)ipHdr + sizeof *ipHdr);
+
+ if (ethHdr->Type == ETH_TYPE_IPV4_NBO) {
+ IPHdr *ipHdr;
+ /* XXX: Handle IP options. */
+ 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;
+ udpHdr = (UDPHdr *)((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;
+ udpHdr = (UDPHdr *)((PCHAR)ipv6Hdr + sizeof(*ipv6Hdr));
+ }
/* Validate if NIC has indicated checksum failure. */
status = OvsValidateUDPChecksum(curNbl, udpHdr->check == 0);
@@ -469,13 +540,14 @@ OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
/* Calculate and verify UDP checksum if NIC didn't do it. */
if (udpHdr->check != 0) {
- status = OvsCalculateUDPChecksum(curNbl, curNb, ipHdr, udpHdr, packetLength);
+ status = OvsCalculateUDPChecksum(curNbl, curNb, ethHdr,
+ udpHdr, packetLength);
if (status != NDIS_STATUS_SUCCESS) {
goto dropNbl;
}
}
- vxlanHdr = (VXLANHdr *)((PCHAR)udpHdr + sizeof *udpHdr);
+ vxlanHdr = (VXLANHdr *)((PCHAR)udpHdr + sizeof(*udpHdr));
if (vxlanHdr->instanceID) {
tunKey->flags = OVS_TNL_F_KEY;
tunKey->tunnelId = VXLAN_VNI_TO_TUNNELID(vxlanHdr->vxlanID);
@@ -539,6 +611,7 @@ OvsSlowPathDecapVxlan(const PNET_BUFFER_LIST packet,
tunnelKey->dst.si_family = AF_INET;
tunnelKey->ttl = nh->ttl;
tunnelKey->tos = nh->tos;
+
if (VxlanHeader->instanceID) {
tunnelKey->flags = OVS_TNL_F_KEY;
tunnelKey->tunnelId = VXLAN_VNI_TO_TUNNELID(VxlanHeader->vxlanID);
diff --git a/datapath-windows/ovsext/Vxlan.h b/datapath-windows/ovsext/Vxlan.h
index be154a5..9e8b3c3 100644
--- a/datapath-windows/ovsext/Vxlan.h
+++ b/datapath-windows/ovsext/Vxlan.h
@@ -69,14 +69,15 @@ NDIS_STATUS OvsEncapVxlan(POVS_VPORT_ENTRY vport,
NDIS_STATUS OvsDecapVxlan(POVS_SWITCH_CONTEXT switchContext,
PNET_BUFFER_LIST curNbl,
OvsIPTunnelKey *tunKey,
+ POVS_PACKET_HDR_INFO layers,
PNET_BUFFER_LIST *newNbl);
static __inline UINT32
-OvsGetVxlanTunHdrSize(VOID)
+OvsGetVxlanTunHdrSize(BOOLEAN isIpv4)
{
/* XXX: Can L2 include VLAN at all? */
- return sizeof (EthHdr) + sizeof (IPHdr) + sizeof (UDPHdr) +
- sizeof (VXLANHdr);
+ return sizeof(EthHdr) + (isIpv4 ? sizeof(IPHdr) : sizeof(IPv6Hdr)) +
+ sizeof (UDPHdr) + sizeof (VXLANHdr);
}
#define VXLAN_UDP_PORT 4789
--
1.9.0.msysgit.0
More information about the dev
mailing list