Signed-off-by: Paul-Daniel Boca <pb...@cloudbasesolutions.com> --- datapath-windows/ovsext/NetProto.h | 10 ++++- datapath-windows/ovsext/PacketParser.h | 67 ++++++++++++++++++++++++++++++++++ datapath-windows/ovsext/Stt.c | 45 +++++++++++++++++++++++ datapath-windows/ovsext/Stt.h | 1 + 4 files changed, 122 insertions(+), 1 deletion(-)
diff --git a/datapath-windows/ovsext/NetProto.h b/datapath-windows/ovsext/NetProto.h index f7527f8..6cf6d8e 100644 --- a/datapath-windows/ovsext/NetProto.h +++ b/datapath-windows/ovsext/NetProto.h @@ -45,6 +45,8 @@ typedef struct EthHdr { #define ICMP_CSUM_OFFSET 2 #define INET_CSUM_LENGTH (sizeof(UINT16)) +#define PACKET_MAX_LENGTH 64*1024 // 64K + #define IP4_UNITS_TO_BYTES(x) ((x) << 2) #define IP4_BYTES_TO_UNITS(x) ((x) >> 2) @@ -245,7 +247,13 @@ typedef union _OVS_PACKET_HDR_INFO { typedef struct IPHdr { UINT8 ihl:4, version:4; - UINT8 tos; + union { + struct { + UINT8 ecn:2, + dscp:6; + }; + UINT8 tos; + }; UINT16 tot_len; UINT16 id; UINT16 frag_off; diff --git a/datapath-windows/ovsext/PacketParser.h b/datapath-windows/ovsext/PacketParser.h index f1d7f28..a72b7dc 100644 --- a/datapath-windows/ovsext/PacketParser.h +++ b/datapath-windows/ovsext/PacketParser.h @@ -99,6 +99,73 @@ OvsGetArp(const NET_BUFFER_LIST *packet, return OvsGetPacketBytes(packet, sizeof *storage, ofs, storage); } +/* +* Returns the start of NBL and computes the total length of Ethernet header +* Also returns the type of L3 header +*/ +static const PVOID +OvsGetEthHeader(const NET_BUFFER_LIST *packet, + UINT16 *length, + UINT16 *dlType, + Eth_Header *storage) +{ + UINT8 offset = 0; + PVOID vlanTagValue; + PUINT8 buffStart = NULL; + + const Eth_Header *eth = OvsGetPacketBytes(packet, ETH_MAX_HEADER_LEN, + 0, storage); + if (eth == NULL) { + return NULL; + } + + /* Keep a copy of packet start */ + buffStart = (PUINT8)eth; + + /* + * vlan_tci. + */ + vlanTagValue = NET_BUFFER_LIST_INFO(packet, Ieee8021QNetBufferListInfo); + if (!vlanTagValue) { + if (eth->dix.typeNBO == ETH_TYPE_802_1PQ_NBO) { + offset = sizeof(Eth_802_1pq_Tag); + } + + /* + * XXX Please note after this point, src mac and dst mac should + * not be accessed through eth + */ + eth = (Eth_Header *)((UINT8 *)eth + offset); + } + + /* + * dl_type. + * + * XXX assume that at least the first + * 12 bytes of received packets are mapped. This code has the stronger + * assumption that at least the first 22 bytes of 'packet' is mapped (if my + * arithmetic is right). + */ + if (ETH_TYPENOT8023(eth->dix.typeNBO)) { + *dlType = eth->dix.typeNBO; + *length = ETH_HEADER_LEN_DIX + offset; + } else if (OvsPacketLenNBL(packet) >= ETH_HEADER_LEN_802_3 && + eth->e802_3.llc.dsap == 0xaa && + eth->e802_3.llc.ssap == 0xaa && + eth->e802_3.llc.control == ETH_LLC_CONTROL_UFRAME && + eth->e802_3.snap.snapOrg[0] == 0x00 && + eth->e802_3.snap.snapOrg[1] == 0x00 && + eth->e802_3.snap.snapOrg[2] == 0x00) { + *dlType = eth->e802_3.snap.snapType.typeNBO; + *length = ETH_HEADER_LEN_802_3 + offset; + } else { + *dlType = htons(OVSWIN_DL_TYPE_NONE); + *length = ETH_HEADER_LEN_DIX + offset; + } + + return (UINT8*)eth; +} + static const IPHdr * OvsGetIp(const NET_BUFFER_LIST *packet, UINT32 ofs, diff --git a/datapath-windows/ovsext/Stt.c b/datapath-windows/ovsext/Stt.c index 8a1b1a9..a9e1cac 100644 --- a/datapath-windows/ovsext/Stt.c +++ b/datapath-windows/ovsext/Stt.c @@ -642,6 +642,9 @@ OvsSttReassemble(POVS_SWITCH_CONTEXT switchContext, NdisMoveMemory(&entry->ovsPktKey, &pktKey, sizeof (OVS_STT_PKT_KEY)); entry->recvdLen = fragmentLength; + if (ipHdr->ecn == IP_ECN_CE) { + entry->ecn = IP_ECN_CE; + } UINT64 currentTime; NdisGetCurrentSystemTime((LARGE_INTEGER *) ¤tTime); @@ -678,6 +681,9 @@ OvsSttReassemble(POVS_SWITCH_CONTEXT switchContext, if (segOffset == 0) { pktFragEntry->sttHdr = *sttHdr; } + if (ipHdr->ecn == IP_ECN_CE) { + pktFragEntry->ecn = IP_ECN_CE; + } /* Copy the fragment data from Source to existing buffer */ if (OvsGetPacketBytes(curNbl, fragmentLength, startOffset, @@ -689,6 +695,14 @@ OvsSttReassemble(POVS_SWITCH_CONTEXT switchContext, handle_error: if (lastPacket) { + /* It is RECOMMENDED that if any segment of the received STT + * frame has the CE (congestion experienced) bit set + * in its IP header, then the CE bit SHOULD be set in the IP + * header of the decapsulated STT frame.*/ + if (pktFragEntry->ecn == IP_ECN_CE) { + ipHdr->ecn = IP_ECN_CE; + } + /* Retrieve the original STT header */ NdisMoveMemory(newSttHdr, &pktFragEntry->sttHdr, sizeof (SttHdr)); targetPNbl = OvsAllocateNBLFromBuffer(switchContext, @@ -920,6 +934,37 @@ OvsDecapStt(POVS_SWITCH_CONTEXT switchContext, tunKey->ttl = ipHdr->ttl; tunKey->pad = 0; + /* Handle ECN */ + if (0 != ipHdr->tos) { + UINT16 length, dlType; + Eth_Header storage; + PUINT8 ethHdr = OvsGetEthHeader(*newNbl, &length, &dlType, &storage); + + if (dlType == htons(ETH_TYPE_IPV4)) { + IPHdr *innerIpHdr = (IPHdr*)(ethHdr + length); + + /* + * If CE is set for outer IP header, reset ECN of inner IP + * header to CE, all other values are kept the same + */ + if (ipHdr->ecn == IP_ECN_CE) { + innerIpHdr->ecn |= IP_ECN_CE; + } + /* copy DSCP from outer header to inner header */ + innerIpHdr->dscp = ipHdr->dscp; + /* fix IP checksum */ + innerIpHdr->check = IPChecksum((UINT8 *)innerIpHdr, + innerIpHdr->ihl * 4, 0); + } else if (dlType == htons(ETH_TYPE_IPV6)) { + IPv6Hdr *innerIpv6Hdr = (IPv6Hdr*)(ethHdr + length); + /* copy ECN and DSCN to inner header */ + innerIpv6Hdr->priority = ipHdr->ecn + | ((innerIpv6Hdr->flow_lbl[0] & 0x3) << 2); + innerIpv6Hdr->flow_lbl[0] = (innerIpv6Hdr->flow_lbl[0] & 0xF) + | ((ipHdr->tos & 0xF) << 4); + } + } + /* Apply VLAN tag if present */ if (ntohs(sttHdr->vlanTCI) & OVSWIN_VLAN_CFI) { NDIS_NET_BUFFER_LIST_8021Q_INFO vlanTag; diff --git a/datapath-windows/ovsext/Stt.h b/datapath-windows/ovsext/Stt.h index 8aea164..b9e8b88 100644 --- a/datapath-windows/ovsext/Stt.h +++ b/datapath-windows/ovsext/Stt.h @@ -68,6 +68,7 @@ typedef struct _OVS_STT_PKT_ENTRY { UINT64 timeout; UINT32 recvdLen; UINT32 allocatedLen; + UINT8 ecn; SttHdr sttHdr; PCHAR packetBuf; LIST_ENTRY link; -- 2.7.2.windows.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev