summaryrefslogtreecommitdiff
path: root/datapath-windows
diff options
context:
space:
mode:
Diffstat (limited to 'datapath-windows')
-rw-r--r--datapath-windows/ovsext/Actions.c174
-rw-r--r--datapath-windows/ovsext/Actions.h5
-rw-r--r--datapath-windows/ovsext/Conntrack-ftp.c159
-rw-r--r--datapath-windows/ovsext/Conntrack-icmp.c11
-rw-r--r--datapath-windows/ovsext/Conntrack-nat.c82
-rw-r--r--datapath-windows/ovsext/Conntrack-related.c45
-rw-r--r--datapath-windows/ovsext/Conntrack.c287
-rw-r--r--datapath-windows/ovsext/Conntrack.h34
-rw-r--r--datapath-windows/ovsext/DpInternal.h2
-rw-r--r--datapath-windows/ovsext/Flow.c41
-rw-r--r--datapath-windows/ovsext/NetProto.h8
-rw-r--r--datapath-windows/ovsext/PacketParser.c1
-rw-r--r--datapath-windows/ovsext/Util.c19
-rw-r--r--datapath-windows/ovsext/Util.h21
-rw-r--r--datapath-windows/ovsext/precomp.h1
15 files changed, 793 insertions, 97 deletions
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index c66ece080..0f7f78932 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -1618,6 +1618,180 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx,
return NDIS_STATUS_SUCCESS;
}
+UINT16
+OvsCalculateICMPv6Checksum(struct in6_addr srcAddr,
+ struct in6_addr dstAddr,
+ uint16_t totalLength,
+ uint16_t protocol,
+ uint16_t *icmpStart,
+ uint16_t length)
+{
+ uint32_t checkSum = 0;
+ uint16_t *srcAddressPtr = (uint16_t *)&srcAddr;
+ uint16_t *dstAddressPtr = (uint16_t *)&dstAddr;
+ uint16_t *value = (uint16_t *)icmpStart;
+ int index = 0;
+
+ checkSum = totalLength + protocol;
+
+ for (int i = 0; i < 8; i++) {
+ checkSum += ntohs(srcAddressPtr[i]);
+ checkSum += ntohs(dstAddressPtr[i]);
+ }
+
+ for (index = length; index > 1; index -= 2) {
+ checkSum += ntohs(*value);
+ value++;
+ }
+
+ if (index > 0) {
+ checkSum += (uint16_t)(*((uint8_t *)value));
+ }
+
+ while ((checkSum >> 16) & 0xffff) {
+ checkSum = (checkSum & 0xffff) + ((checkSum >> 16) & 0xffff);
+ }
+
+ return htons(~((uint16_t)checkSum));
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OvsUpdateAddressAndPortForIpv6--
+ *
+ * Update ipv6 address in ovsFwdCtx.curNbl.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+NDIS_STATUS
+OvsUpdateAddressAndPortForIpv6(OvsForwardingContext *ovsFwdCtx,
+ struct in6_addr newAddr, UINT16 newPort,
+ BOOLEAN isSource, BOOLEAN isTx)
+{
+ PUINT8 bufferStart;
+ UINT32 hdrSize;
+ OVS_PACKET_HDR_INFO *layers = &ovsFwdCtx->layers;
+ IPv6Hdr *ipHdr;
+ TCPHdr *tcpHdr = NULL;
+ UDPHdr *udpHdr = NULL;
+ struct in6_addr *addrField = NULL;
+ UINT16 *portField = NULL;
+ UINT16 *checkField = NULL;
+ BOOLEAN l4Offload = FALSE;
+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
+
+ ASSERT(layers->value != 0);
+
+ if (layers->isTcp || layers->isUdp) {
+ hdrSize = layers->l4Offset +
+ layers->isTcp ? sizeof (*tcpHdr) : sizeof (*udpHdr);
+ } else {
+ hdrSize = layers->l3Offset + sizeof (*ipHdr);
+ }
+
+ csumInfo.Value = NET_BUFFER_LIST_INFO(ovsFwdCtx->curNbl,
+ TcpIpChecksumNetBufferListInfo);
+
+ bufferStart = OvsGetHeaderBySize(ovsFwdCtx, hdrSize);
+ if (!bufferStart) {
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ ipHdr = (IPv6Hdr *)(bufferStart + layers->l3Offset);
+
+ if (layers->isTcp) {
+ tcpHdr = (TCPHdr *)(bufferStart + layers->l4Offset);
+ } else if (layers->isUdp) {
+ udpHdr = (UDPHdr *)(bufferStart + layers->l4Offset);
+ }
+
+ if (isSource) {
+ addrField = &ipHdr->saddr;
+ if (tcpHdr) {
+ portField = &tcpHdr->source;
+ checkField = &tcpHdr->check;
+ l4Offload = isTx ? (BOOLEAN)csumInfo.Transmit.TcpChecksum :
+ ((BOOLEAN)csumInfo.Receive.TcpChecksumSucceeded ||
+ (BOOLEAN)csumInfo.Receive.TcpChecksumFailed);
+ } else if (udpHdr) {
+ portField = &udpHdr->source;
+ checkField = &udpHdr->check;
+ l4Offload = isTx ? (BOOLEAN)csumInfo.Transmit.UdpChecksum :
+ ((BOOLEAN)csumInfo.Receive.UdpChecksumSucceeded ||
+ (BOOLEAN)csumInfo.Receive.UdpChecksumFailed);
+ }
+ if (isTx && l4Offload) {
+ *checkField = IPv6PseudoChecksum((UINT32 *)&newAddr, (UINT32 *)&ipHdr->daddr,
+ tcpHdr ? IPPROTO_TCP : IPPROTO_UDP,
+ ntohs(ipHdr->payload_len) -
+ (ovsFwdCtx->layers.l4Offset - ovsFwdCtx->layers.l3Offset));
+ }
+ } else {
+ addrField = &ipHdr->daddr;
+ if (tcpHdr) {
+ portField = &tcpHdr->dest;
+ checkField = &tcpHdr->check;
+ l4Offload = isTx ? (BOOLEAN)csumInfo.Transmit.TcpChecksum :
+ ((BOOLEAN)csumInfo.Receive.TcpChecksumSucceeded ||
+ (BOOLEAN)csumInfo.Receive.TcpChecksumFailed);
+ } else if (udpHdr) {
+ portField = &udpHdr->dest;
+ checkField = &udpHdr->check;
+ l4Offload = isTx ? (BOOLEAN)csumInfo.Transmit.UdpChecksum :
+ ((BOOLEAN)csumInfo.Receive.UdpChecksumSucceeded ||
+ (BOOLEAN)csumInfo.Receive.UdpChecksumFailed);
+ }
+
+ if (isTx && l4Offload) {
+ *checkField = IPv6PseudoChecksum((UINT32 *)&ipHdr->saddr, (UINT32 *)&newAddr,
+ tcpHdr ? IPPROTO_TCP : IPPROTO_UDP,
+ ntohs(ipHdr->payload_len) -
+ (ovsFwdCtx->layers.l4Offset - ovsFwdCtx->layers.l3Offset));
+ }
+ }
+
+ if (memcmp(addrField, &newAddr, sizeof(struct in6_addr))) {
+ if ((checkField && *checkField != 0) && (!l4Offload || !isTx)) {
+ uint32_t *oldField = (uint32_t *)addrField;
+ uint32_t *newField = (uint32_t *)&newAddr;
+ *checkField = ChecksumUpdate32(*checkField, oldField[0], newField[0]);
+ *checkField = ChecksumUpdate32(*checkField, oldField[1], newField[1]);
+ *checkField = ChecksumUpdate32(*checkField, oldField[2], newField[2]);
+ *checkField = ChecksumUpdate32(*checkField, oldField[3], newField[3]);
+ }
+
+ *addrField = newAddr;
+
+ if (layers->isIcmp) {
+ ICMPHdr *icmp =(ICMPHdr *)(bufferStart + layers->l4Offset);
+ icmp->checksum = 0x00;
+ icmp->checksum = OvsCalculateICMPv6Checksum(ipHdr->saddr, ipHdr->daddr,
+ ntohs(ipHdr->payload_len),
+ IPPROTO_ICMPV6,
+ (uint16_t *)icmp,
+ ntohs(ipHdr->payload_len));
+ }
+ }
+
+ if (portField && *portField != newPort) {
+ if ((checkField) && (!l4Offload || !isTx)) {
+ /* Recompute total checksum. */
+ *checkField = ChecksumUpdate16(*checkField, *portField,
+ newPort);
+ }
+ *portField = newPort;
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
/*
*----------------------------------------------------------------------------
* OvsUpdateIPv4Header --
diff --git a/datapath-windows/ovsext/Actions.h b/datapath-windows/ovsext/Actions.h
index b374c3a18..7329d0ed0 100644
--- a/datapath-windows/ovsext/Actions.h
+++ b/datapath-windows/ovsext/Actions.h
@@ -133,4 +133,9 @@ OvsUpdateAddressAndPort(OvsForwardingContext *ovsFwdCtx,
UINT32 newAddr, UINT16 newPort,
BOOLEAN isSource, BOOLEAN isTx);
+NDIS_STATUS
+OvsUpdateAddressAndPortForIpv6(OvsForwardingContext *ovsFwdCtx,
+ struct in6_addr newAddr, UINT16 newPort,
+ BOOLEAN isSource, BOOLEAN isTx);
+
#endif /* __ACTIONS_H_ */
diff --git a/datapath-windows/ovsext/Conntrack-ftp.c b/datapath-windows/ovsext/Conntrack-ftp.c
index ce09a6528..066723685 100644
--- a/datapath-windows/ovsext/Conntrack-ftp.c
+++ b/datapath-windows/ovsext/Conntrack-ftp.c
@@ -14,15 +14,21 @@
* limitations under the License.
*/
+#include <string.h>
#include "Conntrack.h"
#include "PacketParser.h"
+#include "util.h"
/* Eg: 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)*/
#define FTP_PASV_RSP_PREFIX "227"
+#define FTP_EXTEND_PASV_RSP_PREFIX "229"
+#define FTP_EXTEND_ACTIVE_RSP_PREFIX "200"
typedef enum FTP_TYPE {
FTP_TYPE_PASV = 1,
- FTP_TYPE_ACTIVE
+ FTP_TYPE_ACTIVE,
+ FTP_EXTEND_TYPE_PASV,
+ FTP_EXTEND_TYPE_ACTIVE
} FTP_TYPE;
static __inline UINT32
@@ -123,12 +129,11 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
POVS_CT_ENTRY entry,
BOOLEAN request)
{
- NDIS_STATUS status;
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
FTP_TYPE ftpType = 0;
const char *buf;
char temp[256] = { 0 };
char ftpMsg[256] = { 0 };
-
UINT32 len;
TCPHdr tcpStorage;
const TCPHdr *tcp;
@@ -156,6 +161,9 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
if ((len >= 5) && (OvsStrncmp("PORT", ftpMsg, 4) == 0)) {
ftpType = FTP_TYPE_ACTIVE;
req = ftpMsg + 4;
+ } else if ((len >= 5) && (OvsStrncmp("EPRT", ftpMsg, 4) == 0)) {
+ ftpType = FTP_EXTEND_TYPE_ACTIVE;
+ req = ftpMsg + 4;
}
} else {
if ((len >= 4) && (OvsStrncmp(FTP_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) {
@@ -176,6 +184,25 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
/* PASV command without ( */
req = ftpMsg + 3;
}
+ } else if ((len >= 4) && (OvsStrncmp(FTP_EXTEND_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) {
+ ftpType = FTP_EXTEND_TYPE_PASV;
+ /* The ftp extended passive mode only contain port info, ip address
+ * is same with the network protocol used by control connection.
+ * 229 Entering Extended Passive Mode (|||port|)
+ * */
+ char *paren;
+ paren = strchr(ftpMsg, '|');
+ if (paren) {
+ req = paren + 3;
+ } else {
+ /* Not a valid EPSV packet. */
+ return NDIS_STATUS_INVALID_PACKET;
+ }
+
+ if (!(*req > '0' && * req < '9')) {
+ /* Not a valid port number. */
+ return NDIS_STATUS_INVALID_PACKET;
+ }
}
}
@@ -184,28 +211,102 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
return NDIS_STATUS_SUCCESS;
}
- UINT32 arr[6] = {0};
- status = OvsCtExtractNumbers(req, len, arr, 6, ',');
+ struct ct_addr clientIp = {0}, serverIp = {0};
+ UINT16 port = 0;
- if (status != NDIS_STATUS_SUCCESS) {
- return status;
- }
+ if (ftpType == FTP_TYPE_ACTIVE || ftpType == FTP_TYPE_PASV) {
+ UINT32 arr[6] = {0};
+ status = OvsCtExtractNumbers(req, len, arr, 6, ',');
+
+ if (status != NDIS_STATUS_SUCCESS) {
+ return status;
+ }
+
+ UINT32 ip = ntohl((arr[0] << 24) | (arr[1] << 16) |
+ (arr[2] << 8) | arr[3]);
+ port = ntohs(((arr[4] << 8) | arr[5]));
+
+ serverIp.ipv4 = ip;
+ clientIp.ipv4 = key->ipKey.nwDst;
+ } else {
+ if (ftpType == FTP_EXTEND_TYPE_ACTIVE) {
+ /** In ftp active mode, we need to parse string like below:
+ * " |2|20::1|50778|", 2 represent address is ipv6, 1 represent
+ * address family is ipv4, "20::1" is ipv6 address, 50779 is port
+ * client need to listen.
+ * **/
+ char *curHdr = NULL;
+ char *nextHdr = NULL;
+ int index = 0;
+ int isIpv6AddressFamily = 0;
+ char ftpStr[1024] = {0x00};
+
+ RtlCopyMemory(ftpStr, req, strlen(req));
+ for (curHdr = ftpStr; *curHdr != '|'; curHdr++);
+ curHdr = curHdr + 1;;
+ do {
+ /** index == 0 parse address family,
+ * index == 1 parse address,
+ * index == 2 parse port **/
+ for (nextHdr = curHdr; *nextHdr != '|'; nextHdr++);
+ *nextHdr = '\0';
+
+ if (*curHdr == '0' || !curHdr || index > 2) {
+ break;
+ }
+
+ if (index == 0 && *curHdr == '1') {
+ isIpv6AddressFamily = 0;
+ } else if (index == 0 && *curHdr == '2') {
+ isIpv6AddressFamily = 1;
+ }
+
+ if (index == 1 && isIpv6AddressFamily) {
+ OvsIpv6StringToAddress(curHdr, &clientIp.ipv6);
+ }
+
+ if (index == 2) {
+ for (char *tmp = curHdr; *tmp != '\0'; tmp++) {
+ port = port * 10 + (*tmp - '0');
+ }
+ port = htons(port);
+ }
+
+ curHdr = nextHdr + 1;
+ index++;
+ } while (1);
+
+ if (index < 2) { /* Not valid packet due to less than three parameter */
+ return NDIS_STATUS_SUCCESS;
+ }
+ serverIp.ipv6 = key->ipv6Key.ipv6Dst;
+ }
+
+ if (ftpType == FTP_EXTEND_TYPE_PASV) {
+ /* Here used to parse the string "229 Entering Extended Passive Mode (|||50522|),
+ * 50522 is the port we want". */
+ char *tmp = req;
+ while (*tmp != '|' && *tmp != '\0') {
+ port = port * 10 + (*tmp - '0');
+ tmp++;
+ }
- UINT32 ip = ntohl((arr[0] << 24) | (arr[1] << 16) |
- (arr[2] << 8) | arr[3]);
- UINT16 port = ntohs(((arr[4] << 8) | arr[5]));
+ port = htons(port);
+
+ serverIp.ipv6 = key->ipv6Key.ipv6Src;
+ clientIp.ipv6 = key->ipv6Key.ipv6Dst;
+ }
+ }
switch (ftpType) {
case FTP_TYPE_PASV:
/* Ensure that the command states Server's IP address */
- ASSERT(ip == key->ipKey.nwSrc);
-
OvsCtRelatedEntryCreate(key->ipKey.nwProto,
key->l2.dlType,
/* Server's IP */
- ip,
+ serverIp,
/* Use intended client's IP */
- key->ipKey.nwDst,
+ clientIp,
/* Dynamic port opened on server */
port,
/* We don't know the client port */
@@ -217,9 +318,33 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
OvsCtRelatedEntryCreate(key->ipKey.nwProto,
key->l2.dlType,
/* Server's default IP address */
- key->ipKey.nwDst,
+ serverIp,
+ /* Client's IP address */
+ clientIp,
+ /* FTP Data Port is 20 */
+ ntohs(IPPORT_FTP_DATA),
+ /* Port opened up on Client */
+ port,
+ currentTime,
+ entry);
+ break;
+ case FTP_EXTEND_TYPE_PASV:
+ OvsCtRelatedEntryCreate(key->ipv6Key.nwProto,
+ key->l2.dlType,
+ serverIp,
+ clientIp,
+ port,
+ 0,
+ currentTime,
+ entry);
+ break;
+ case FTP_EXTEND_TYPE_ACTIVE:
+ OvsCtRelatedEntryCreate(key->ipv6Key.nwProto,
+ key->l2.dlType,
+ /* Server's default IP address */
+ serverIp,
/* Client's IP address */
- ip,
+ clientIp,
/* FTP Data Port is 20 */
ntohs(IPPORT_FTP_DATA),
/* Port opened up on Client */
diff --git a/datapath-windows/ovsext/Conntrack-icmp.c b/datapath-windows/ovsext/Conntrack-icmp.c
index 28fe2bff8..9221f8518 100644
--- a/datapath-windows/ovsext/Conntrack-icmp.c
+++ b/datapath-windows/ovsext/Conntrack-icmp.c
@@ -70,6 +70,17 @@ OvsConntrackValidateIcmpPacket(const ICMPHdr *icmp)
|| icmp->type == ICMP4_TIMESTAMP_REQUEST;
}
+BOOLEAN
+OvsConntrackValidateIcmp6Packet(const ICMPHdr *icmp)
+{
+ if (!icmp) {
+ OVS_LOG_TRACE("Invalid ICMP packet detected, header cannot be NULL");
+ return FALSE;
+ }
+
+ return icmp->type == ICMP6_ECHO_REQUEST;
+}
+
OVS_CT_ENTRY *
OvsConntrackCreateIcmpEntry(UINT64 now)
{
diff --git a/datapath-windows/ovsext/Conntrack-nat.c b/datapath-windows/ovsext/Conntrack-nat.c
index 1607d4c4f..497354ec8 100644
--- a/datapath-windows/ovsext/Conntrack-nat.c
+++ b/datapath-windows/ovsext/Conntrack-nat.c
@@ -42,12 +42,9 @@ OvsHashNatKey(const OVS_CT_KEY *key)
static __inline BOOLEAN
OvsNatKeyAreSame(const OVS_CT_KEY *key1, const OVS_CT_KEY *key2)
{
- // XXX: Compare IPv6 key as well
#define FIELD_COMPARE(field) \
if (key1->field != key2->field) return FALSE
- FIELD_COMPARE(src.addr.ipv4_aligned);
- FIELD_COMPARE(dst.addr.ipv4_aligned);
FIELD_COMPARE(src.port);
FIELD_COMPARE(dst.port);
FIELD_COMPARE(zone);
@@ -56,6 +53,15 @@ OvsNatKeyAreSame(const OVS_CT_KEY *key1, const OVS_CT_KEY *key2)
FIELD_COMPARE(dst.icmp_type);
FIELD_COMPARE(src.icmp_code);
FIELD_COMPARE(dst.icmp_code);
+
+ if (memcmp(&(key1->src.addr), &(key2->src.addr), sizeof(struct ct_addr))) {
+ return FALSE;
+ }
+
+ if (memcmp(&(key1->dst.addr), &(key2->dst.addr), sizeof(struct ct_addr))) {
+ return FALSE;
+ }
+
return TRUE;
#undef FIELD_COMPARE
}
@@ -215,18 +221,37 @@ OvsNatPacket(OvsForwardingContext *ovsFwdCtx,
} else {
key->ipKey.nwDst = endpoint->addr.ipv4_aligned;
}
- } else if (ctKey->dl_type == htons(ETH_TYPE_IPV6)){
- // XXX: IPv6 packet not supported yet.
- return;
+ } else if (ctKey->dl_type == htons(ETH_TYPE_IPV6)) {
+ OvsUpdateAddressAndPortForIpv6(ovsFwdCtx,
+ endpoint->addr.ipv6,
+ endpoint->port, isSrcNat,
+ !reverse);
+ if (isSrcNat) {
+ key->ipv6Key.ipv6Src = endpoint->addr.ipv6;
+ } else {
+ key->ipv6Key.ipv6Dst = endpoint->addr.ipv6;
+ }
}
if (natAction & (NAT_ACTION_SRC_PORT | NAT_ACTION_DST_PORT)) {
- if (isSrcNat) {
- if (key->ipKey.l4.tpSrc != 0) {
- key->ipKey.l4.tpSrc = endpoint->port;
+ if (ctKey->dl_type == htons(ETH_TYPE_IPV4)) {
+ if (isSrcNat) {
+ if (key->ipKey.l4.tpSrc != 0) {
+ key->ipKey.l4.tpSrc = endpoint->port;
+ }
+ } else {
+ if (key->ipKey.l4.tpDst != 0) {
+ key->ipKey.l4.tpDst = endpoint->port;
+ }
}
- } else {
- if (key->ipKey.l4.tpDst != 0) {
- key->ipKey.l4.tpDst = endpoint->port;
+ } else if (ctKey->dl_type == htons(ETH_TYPE_IPV6)) {
+ if (isSrcNat) {
+ if (key->ipv6Key.l4.tpSrc != 0) {
+ key->ipv6Key.l4.tpSrc = endpoint->port;
+ }
+ } else {
+ if (key->ipv6Key.l4.tpDst != 0) {
+ key->ipv6Key.l4.tpDst = endpoint->port;
+ }
}
}
}
@@ -326,8 +351,8 @@ OvsNatTranslateCtEntry(OVS_CT_ENTRY *entry)
ctAddr.ipv4_aligned = htonl(
ntohl(entry->natInfo.minAddr.ipv4_aligned) + addrIndex);
} else {
- // XXX: IPv6 not supported
- return FALSE;
+ /** Current, only support nat single address**/
+ ctAddr.ipv6_aligned = entry->natInfo.minAddr.ipv6_aligned;
}
port = firstPort;
@@ -379,8 +404,33 @@ OvsNatTranslateCtEntry(OVS_CT_ENTRY *entry)
ctAddr.ipv4_aligned = htonl(
ntohl(ctAddr.ipv4_aligned) + 1);
} else {
- // XXX: IPv6 not supported
- return FALSE;
+ /** When all ports was used, return fails indicate exceed range. **/
+ uint32_t addr[8] = {0};
+ uint16_t *tmpAddr = (uint16_t *)&(ctAddr.ipv6_aligned);
+ for (int m = 0; m < 8; m++) {
+ addr[m] = tmpAddr[m];
+ }
+
+ uint16_t carry = 1, i = 8;
+ while (carry && i)
+ {
+ addr[i-1] += carry;
+ if (addr[i-1] > 0xffff || !addr[i-1])
+ {
+ carry = 1;
+ addr[i-1] &= 0xffff;
+ } else carry = 0;
+ i--;
+ }
+
+ if (carry) {
+ OVS_LOG_INFO("Ipv6 address incremented overflow.");
+ return FALSE;
+ }
+
+ for (int m = 0; m < 8; m++) {
+ tmpAddr[m] = (uint16_t)addr[m];
+ }
}
} else {
ctAddr = entry->natInfo.minAddr;
diff --git a/datapath-windows/ovsext/Conntrack-related.c b/datapath-windows/ovsext/Conntrack-related.c
index a5bba5cf8..f985c7631 100644
--- a/datapath-windows/ovsext/Conntrack-related.c
+++ b/datapath-windows/ovsext/Conntrack-related.c
@@ -38,10 +38,22 @@ static __inline BOOLEAN
OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey)
{
/* FTP PASV - Client initiates the connection from unknown port */
- if ((incomingKey.dst.addr.ipv4 == entryKey.src.addr.ipv4) &&
+ if ((incomingKey.dl_type == entryKey.dl_type) &&
+ (incomingKey.dl_type == htons(ETH_TYPE_IPV4)) &&
+ (incomingKey.dst.addr.ipv4 == entryKey.src.addr.ipv4) &&
(incomingKey.dst.port == entryKey.src.port) &&
(incomingKey.src.addr.ipv4 == entryKey.dst.addr.ipv4) &&
- (incomingKey.dl_type == entryKey.dl_type) &&
+ (incomingKey.nw_proto == entryKey.nw_proto)) {
+ return TRUE;
+ }
+
+ if ((incomingKey.dl_type == entryKey.dl_type) &&
+ (incomingKey.dl_type == htons(ETH_TYPE_IPV6)) &&
+ !memcmp(&(incomingKey.dst.addr.ipv6), &(entryKey.src.addr.ipv6),
+ sizeof(incomingKey.dst.addr.ipv6)) &&
+ (incomingKey.dst.port == entryKey.src.port) &&
+ !memcmp(&(incomingKey.src.addr.ipv6), &(entryKey.dst.addr.ipv6),
+ sizeof(incomingKey.src.addr.ipv6)) &&
(incomingKey.nw_proto == entryKey.nw_proto)) {
return TRUE;
}
@@ -51,10 +63,22 @@ OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey)
* except 20. In this case, the incomingKey's src port is different with
* entryKey's src port.
*/
- if ((incomingKey.src.addr.ipv4 == entryKey.src.addr.ipv4) &&
+ if ((incomingKey.dl_type == entryKey.dl_type) &&
+ (incomingKey.dl_type == htons(ETH_TYPE_IPV4)) &&
+ (incomingKey.src.addr.ipv4 == entryKey.src.addr.ipv4) &&
(incomingKey.dst.addr.ipv4 == entryKey.dst.addr.ipv4) &&
(incomingKey.dst.port == entryKey.dst.port) &&
- (incomingKey.dl_type == entryKey.dl_type) &&
+ (incomingKey.nw_proto == entryKey.nw_proto)) {
+ return TRUE;
+ }
+
+ if ((incomingKey.dl_type == entryKey.dl_type) &&
+ (incomingKey.dl_type == htons(ETH_TYPE_IPV6)) &&
+ !memcmp(&(incomingKey.src.addr.ipv6), &(entryKey.src.addr.ipv6),
+ sizeof(incomingKey.src.addr.ipv6)) &&
+ !memcmp(&(incomingKey.dst.addr.ipv6), &(entryKey.dst.addr.ipv6),
+ sizeof(incomingKey.src.addr.ipv6)) &&
+ (incomingKey.dst.port == entryKey.dst.port) &&
(incomingKey.nw_proto == entryKey.nw_proto)) {
return TRUE;
}
@@ -110,8 +134,8 @@ OvsCtRelatedEntryDelete(POVS_CT_REL_ENTRY entry)
NDIS_STATUS
OvsCtRelatedEntryCreate(UINT8 ipProto,
UINT16 dl_type,
- UINT32 serverIp,
- UINT32 clientIp,
+ struct ct_addr serverIp,
+ struct ct_addr clientIp,
UINT16 serverPort,
UINT16 clientPort,
UINT64 currentTime,
@@ -127,13 +151,18 @@ OvsCtRelatedEntryCreate(UINT8 ipProto,
RtlZeroMemory(entry, sizeof(struct OVS_CT_REL_ENTRY));
entry->expiration = currentTime + (CT_INTERVAL_SEC * 60);
- entry->key.src.addr.ipv4 = serverIp;
- entry->key.dst.addr.ipv4 = clientIp;
entry->key.nw_proto = ipProto;
entry->key.dl_type = dl_type;
entry->key.src.port = serverPort;
entry->key.dst.port = clientPort;
entry->parent = parent;
+ if (dl_type == htons(ETH_TYPE_IPV6)) {
+ entry->key.src.addr.ipv6 = serverIp.ipv6;
+ entry->key.dst.addr.ipv6 = clientIp.ipv6;
+ } else {
+ entry->key.src.addr.ipv4 = serverIp.ipv4;
+ entry->key.dst.addr.ipv4 = clientIp.ipv4;
+ }
UINT32 hash = OvsExtractCtRelatedKeyHash(&entry->key);
diff --git a/datapath-windows/ovsext/Conntrack.c b/datapath-windows/ovsext/Conntrack.c
index 237efa9e9..471bf961b 100644
--- a/datapath-windows/ovsext/Conntrack.c
+++ b/datapath-windows/ovsext/Conntrack.c
@@ -189,6 +189,13 @@ OvsCtSetZoneLimit(int zone, ULONG value) {
NdisReleaseSpinLock(&ovsCtZoneLock);
}
+static uint32_t
+OvsCtEndpointHashAdd(uint32_t hash, const struct ct_endpoint *ep)
+{
+ BUILD_ASSERT_DECL(sizeof *ep % 4 == 0);
+ return OvsJhashBytes((UINT32 *)ep, sizeof *ep, hash);
+}
+
/*
*----------------------------------------------------------------------------
* OvsCtHashKey
@@ -199,8 +206,10 @@ UINT32
OvsCtHashKey(const OVS_CT_KEY *key)
{
UINT32 hsrc, hdst, hash;
- hsrc = key->src.addr.ipv4 | ntohl(key->src.port);
- hdst = key->dst.addr.ipv4 | ntohl(key->dst.port);
+ hsrc = ntohl(key->src.port);
+ hdst = ntohl(key->dst.port);
+ hsrc = OvsCtEndpointHashAdd(hsrc, &key->src);
+ hdst = OvsCtEndpointHashAdd(hdst, &key->dst);
hash = hsrc ^ hdst; /* TO identify reverse traffic */
hash = hash | (key->zone + key->nw_proto);
hash = OvsJhashWords((uint32_t*) &hash, 1, hash);
@@ -341,6 +350,26 @@ OvsCtEntryCreate(OvsForwardingContext *fwdCtx,
}
break;
}
+ case IPPROTO_ICMPV6:
+ {
+ ICMPHdr storage;
+ const ICMPHdr *icmp;
+ icmp = OvsGetIcmp(curNbl, layers->l4Offset, &storage);
+ if (!OvsConntrackValidateIcmp6Packet(icmp)) {
+ if(icmp) {
+ OVS_LOG_TRACE("Invalid ICMP packet detected, icmp->type %u",
+ icmp->type);
+ }
+ state = OVS_CS_F_INVALID;
+ break;
+ }
+
+ if (commit) {
+ entry = OvsConntrackCreateIcmpEntry(currentTime);
+ }
+ break;
+ }
+
case IPPROTO_ICMP:
{
ICMPHdr storage;
@@ -435,6 +464,15 @@ OvsCtUpdateEntry(OVS_CT_ENTRY* entry,
NdisReleaseSpinLock(&(entry->lock));
break;
}
+
+ case IPPROTO_ICMPV6:
+ {
+ NdisAcquireSpinLock(&(entry->lock));
+ status = OvsConntrackUpdateIcmpEntry(entry, reply, now);
+ NdisReleaseSpinLock(&(entry->lock));
+ break;
+ }
+
case IPPROTO_UDP:
{
NdisAcquireSpinLock(&(entry->lock));
@@ -528,6 +566,23 @@ OvsDetectCtPacket(OvsForwardingContext *fwdCtx,
}
return NDIS_STATUS_NOT_SUPPORTED;
case ETH_TYPE_IPV6:
+ if (key->ipv6Key.nwProto == IPPROTO_ICMPV6
+ || key->ipv6Key.nwProto == IPPROTO_TCP
+ || key->ipv6Key.nwProto == IPPROTO_UDP) {
+ /** TODO fragment **/
+
+ /** Extract flow key from packet and assign it to
+ * returned parameter. **/
+ status = OvsExtractFlow(fwdCtx->curNbl, fwdCtx->srcVportNo,
+ &newFlowKey, &fwdCtx->layers,
+ !OvsIphIsZero(&(fwdCtx->tunKey.dst)) ? &(fwdCtx->tunKey) : NULL);
+ if (status != NDIS_STATUS_SUCCESS) {
+ OVS_LOG_ERROR("Extract flow for ipv6 failed Nbl %p", fwdCtx->curNbl);
+ return status;
+ }
+ *key = newFlowKey;
+ return NDIS_STATUS_SUCCESS;
+ }
return NDIS_STATUS_NOT_SUPPORTED;
}
@@ -606,6 +661,54 @@ OvsCtLookup(OvsConntrackKeyLookupCtx *ctx)
return found;
}
+const TCPHdr*
+OvsGetTcpHeader(PNET_BUFFER_LIST nbl,
+ OVS_PACKET_HDR_INFO *layers,
+ VOID *storage,
+ UINT32 *tcpPayloadLen)
+{
+ IPHdr *ipHdr;
+ IPv6Hdr *ipv6Hdr;
+ TCPHdr *tcp;
+ VOID *dest = storage;
+ uint16_t ipv6ExtLength = 0;
+
+ if (layers->isIPv6) {
+ ipv6Hdr = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(nbl),
+ layers->l4Offset + sizeof(TCPHdr),
+ NULL, 1, 0);
+ if (ipv6Hdr == NULL) {
+ return NULL;
+ }
+
+ tcp = (TCPHdr *)((PCHAR)ipv6Hdr + layers->l4Offset);
+ ipv6Hdr = (IPv6Hdr *)((PCHAR)ipv6Hdr + layers->l3Offset);
+ if (tcp->doff * 4 >= sizeof *tcp) {
+ NdisMoveMemory(dest, tcp, sizeof(TCPHdr));
+ ipv6ExtLength = layers->l4Offset - layers->l3Offset - sizeof(IPv6Hdr);
+ *tcpPayloadLen = (ntohs(ipv6Hdr->payload_len) - ipv6ExtLength - TCP_HDR_LEN(tcp));
+ return storage;
+ }
+ } else {
+ ipHdr = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(nbl),
+ layers->l4Offset + sizeof(TCPHdr),
+ NULL, 1 /*no align*/, 0);
+ if (ipHdr == NULL) {
+ return NULL;
+ }
+
+ ipHdr = (IPHdr *)((PCHAR)ipHdr + layers->l3Offset);
+ tcp = (TCPHdr *)((PCHAR)ipHdr + ipHdr->ihl * 4);
+
+ if (tcp->doff * 4 >= sizeof *tcp) {
+ NdisMoveMemory(dest, tcp, sizeof(TCPHdr));
+ *tcpPayloadLen = TCP_DATA_LENGTH(ipHdr, tcp);
+ return storage;
+ }
+ }
+ return NULL;
+}
+
static UINT8
OvsReverseIcmpType(UINT8 type)
{
@@ -622,6 +725,10 @@ OvsReverseIcmpType(UINT8 type)
return ICMP4_INFO_REPLY;
case ICMP4_INFO_REPLY:
return ICMP4_INFO_REQUEST;
+ case ICMP6_ECHO_REQUEST:
+ return ICMP6_ECHO_REPLY;
+ case ICMP6_ECHO_REPLY:
+ return ICMP6_ECHO_REQUEST;
default:
return 0;
}
@@ -692,8 +799,8 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
return NDIS_STATUS_INVALID_PACKET;
}
/* Separate ICMP connection: identified using id */
- ctx->key.dst.icmp_id = icmp->fields.echo.id;
- ctx->key.src.icmp_id = icmp->fields.echo.id;
+ ctx->key.dst.icmp_id = ntohs(icmp->fields.echo.id);
+ ctx->key.src.icmp_id = ntohs(icmp->fields.echo.id);
ctx->key.src.icmp_type = icmp->type;
ctx->key.dst.icmp_type = OvsReverseIcmpType(icmp->type);
break;
@@ -702,7 +809,6 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
case ICMP4_PARAM_PROB:
case ICMP4_SOURCE_QUENCH:
case ICMP4_REDIRECT: {
- /* XXX Handle inner packet */
ctx->related = TRUE;
break;
}
@@ -717,7 +823,53 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
ctx->key.src.port = flowKey->ipv6Key.l4.tpSrc;
ctx->key.dst.port = flowKey->ipv6Key.l4.tpDst;
- /* XXX Handle ICMPv6 errors*/
+ if (flowKey->ipv6Key.nwProto == IPPROTO_ICMPV6) {
+ ICMPHdr icmpStorage;
+ const ICMPHdr *icmp;
+ icmp = OvsGetIcmp(curNbl, l4Offset, &icmpStorage);
+ ASSERT(icmp);
+
+ switch (icmp->type) {
+ case ICMP6_ECHO_REQUEST:
+ case ICMP6_ECHO_REPLY: {
+ ctx->key.dst.icmp_id = ntohs(icmp->fields.echo.id);
+ ctx->key.src.icmp_id = ntohs(icmp->fields.echo.id);
+ ctx->key.src.icmp_type = icmp->type;
+ ctx->key.dst.icmp_type = OvsReverseIcmpType(icmp->type);
+ break;
+ }
+ case ICMP6_DST_UNREACH:
+ case ICMP6_TIME_EXCEEDED:
+ case ICMP6_PARAM_PROB:
+ case ICMP6_PACKET_TOO_BIG: {
+ Ipv6Key ipv6Key;
+ OVS_PACKET_HDR_INFO layers;
+ OvsExtractLayers(curNbl, &layers);
+ layers.l3Offset = layers.l7Offset;
+ NDIS_STATUS status = OvsParseIPv6(curNbl, &ipv6Key, &layers);
+ if (status != NDIS_STATUS_SUCCESS) {
+ return NDIS_STATUS_INVALID_PACKET;
+ }
+ ctx->key.src.addr.ipv6 = ipv6Key.ipv6Src;
+ ctx->key.dst.addr.ipv6 = ipv6Key.ipv6Dst;
+ ctx->key.nw_proto = ipv6Key.nwProto;
+ if (ipv6Key.nwProto == SOCKET_IPPROTO_TCP) {
+ OvsParseTcp(curNbl, &(ipv6Key.l4), &layers);
+ } else if (ipv6Key.nwProto == SOCKET_IPPROTO_UDP) {
+ OvsParseUdp(curNbl, &(ipv6Key.l4), &layers);
+ } else if (ipv6Key.nwProto == SOCKET_IPPROTO_SCTP) {
+ OvsParseSctp(curNbl, &ipv6Key.l4, &layers);
+ }
+ ctx->key.src.port = ipv6Key.l4.tpSrc;
+ ctx->key.dst.port = ipv6Key.l4.tpDst;
+ OvsCtKeyReverse(&ctx->key);
+ ctx->related = TRUE;
+ break;
+ }
+ default:
+ ctx->related = FALSE;
+ }
+ }
} else {
return NDIS_STATUS_INVALID_PACKET;
}
@@ -744,6 +896,13 @@ OvsDetectFtpPacket(OvsFlowKey *key) {
ntohs(key->ipKey.l4.tpSrc) == IPPORT_FTP));
}
+static __inline BOOLEAN
+OvsDetectFtp6Packet(OvsFlowKey *key) {
+ return (key->ipv6Key.nwProto == IPPROTO_TCP &&
+ (ntohs(key->ipv6Key.l4.tpDst) == IPPORT_FTP ||
+ ntohs(key->ipv6Key.l4.tpSrc) == IPPORT_FTP));
+}
+
/*
*----------------------------------------------------------------------------
* OvsProcessConntrackEntry
@@ -777,11 +936,22 @@ OvsProcessConntrackEntry(OvsForwardingContext *fwdCtx,
} else {
CT_UPDATE_RES result;
UINT32 bucketIdx;
- result = OvsCtUpdateEntry(entry, curNbl, key->ipKey.nwProto, layers,
- ctx->reply, currentTime);
+
+ if (layers->isIPv6) {
+ result = OvsCtUpdateEntry(entry, curNbl, key->ipv6Key.nwProto, layers,
+ ctx->reply, currentTime);
+ } else {
+ result = OvsCtUpdateEntry(entry, curNbl, key->ipKey.nwProto, layers,
+ ctx->reply, currentTime);
+ }
+
switch (result) {
case CT_UPDATE_VALID:
state |= OVS_CS_F_ESTABLISHED;
+ /** when the ct state is established, at least
+ * request/reply two packets go through,
+ * so the ct_state shouldn't contain new.**/
+ state &= ~OVS_CS_F_NEW;
if (ctx->reply) {
state |= OVS_CS_F_REPLY_DIR;
}
@@ -796,9 +966,17 @@ OvsProcessConntrackEntry(OvsForwardingContext *fwdCtx,
OvsCtEntryDelete(ctx->entry, TRUE);
NdisReleaseRWLock(ovsCtBucketLock[bucketIdx], &lockStateTable);
ctx->entry = NULL;
- entry = OvsCtEntryCreate(fwdCtx, key->ipKey.nwProto, layers,
- ctx, key, natInfo, commit, currentTime,
- entryCreated);
+
+ if (layers->isIPv6) {
+ entry = OvsCtEntryCreate(fwdCtx, key->ipv6Key.nwProto, layers,
+ ctx, key, natInfo, commit, currentTime,
+ entryCreated);
+ } else {
+ entry = OvsCtEntryCreate(fwdCtx, key->ipKey.nwProto, layers,
+ ctx, key, natInfo, commit, currentTime,
+ entryCreated);
+ }
+
if (!entry) {
return NULL;
}
@@ -810,7 +988,8 @@ OvsProcessConntrackEntry(OvsForwardingContext *fwdCtx,
}
if (entry) {
NdisAcquireSpinLock(&(entry->lock));
- if (key->ipKey.nwProto == IPPROTO_TCP) {
+ if ((layers->isIPv6 && key->ipv6Key.nwProto == IPPROTO_TCP) ||
+ (!(layers->isIPv6) && key->ipKey.nwProto == IPPROTO_TCP)) {
/* Update the related bit if there is a parent */
if (entry->parent) {
state |= OVS_CS_F_RELATED;
@@ -938,6 +1117,29 @@ OvsCtUpdateTuple(OvsFlowKey *key, OVS_CT_KEY *ctKey)
htons(ctKey->src.icmp_code);
}
+/*
+ * --------------------------------------------------------------------------
+ * OvsCtUpdateTupleV6 name --
+ * Update origin tuple for ipv6 packet.
+ * --------------------------------------------------------------------------
+ */
+static __inline void
+OvsCtUpdateTupleV6(OvsFlowKey *key, OVS_CT_KEY *ctKey)
+{
+ RtlCopyMemory(&key->ct.tuple_ipv6.ipv6_src, &ctKey->src.addr.ipv6_aligned, sizeof(key->ct.tuple_ipv6.ipv6_src));
+ RtlCopyMemory(&key->ct.tuple_ipv6.ipv6_dst, &ctKey->dst.addr.ipv6_aligned, sizeof(key->ct.tuple_ipv6.ipv6_dst));
+ key->ct.tuple_ipv6.ipv6_proto = ctKey->nw_proto;
+
+ /* Orig tuple Port is overloaded to take in ICMP-Type & Code */
+ /* This mimics the behavior in lib/conntrack.c*/
+ key->ct.tuple_ipv6.src_port = ctKey->nw_proto != IPPROTO_ICMPV6 ?
+ ctKey->src.port :
+ htons(ctKey->src.icmp_type);
+ key->ct.tuple_ipv6.dst_port = ctKey->nw_proto != IPPROTO_ICMPV6 ?
+ ctKey->dst.port :
+ htons(ctKey->src.icmp_code);
+}
+
static __inline NDIS_STATUS
OvsCtExecute_(OvsForwardingContext *fwdCtx,
OvsFlowKey *key,
@@ -954,6 +1156,8 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx,
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
BOOLEAN triggerUpdateEvent = FALSE;
BOOLEAN entryCreated = FALSE;
+ BOOLEAN isFtpPacket = FALSE;
+ BOOLEAN isFtpRequestDirection = FALSE;
POVS_CT_ENTRY entry = NULL;
POVS_CT_ENTRY parent = NULL;
PNET_BUFFER_LIST curNbl = fwdCtx->curNbl;
@@ -1004,10 +1208,17 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx,
return NDIS_STATUS_RESOURCES;
}
/* If no matching entry was found, create one and add New state */
- entry = OvsCtEntryCreate(fwdCtx, key->ipKey.nwProto,
- layers, &ctx,
- key, natInfo, commit, currentTime,
- &entryCreated);
+ if (key->l2.dlType == htons(ETH_TYPE_IPV6)) {
+ entry = OvsCtEntryCreate(fwdCtx, key->ipv6Key.nwProto,
+ layers, &ctx,
+ key, natInfo, commit, currentTime,
+ &entryCreated);
+ } else {
+ entry = OvsCtEntryCreate(fwdCtx, key->ipKey.nwProto,
+ layers, &ctx,
+ key, natInfo, commit, currentTime,
+ &entryCreated);
+ }
}
if (entry == NULL) {
@@ -1030,10 +1241,22 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx,
OvsCtSetMarkLabel(key, entry, mark, labels, &triggerUpdateEvent);
- if (OvsDetectFtpPacket(key)) {
+ if (layers->isIPv6) {
+ isFtpPacket = OvsDetectFtp6Packet(key);
+ if (ntohs(key->ipv6Key.l4.tpDst) == IPPORT_FTP) {
+ isFtpRequestDirection = TRUE;
+ }
+ } else {
+ isFtpPacket = OvsDetectFtpPacket(key);
+ if (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP) {
+ isFtpRequestDirection = TRUE;
+ }
+ }
+
+ if (isFtpPacket) {
/* FTP parser will always be loaded */
status = OvsCtHandleFtp(curNbl, key, layers, currentTime, entry,
- (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP));
+ isFtpRequestDirection);
if (status != NDIS_STATUS_SUCCESS) {
OVS_LOG_ERROR("Error while parsing the FTP packet");
}
@@ -1064,6 +1287,14 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx,
} else {
OvsCtUpdateTuple(key, &entry->key);
}
+ } else if (entry->key.dl_type == ntohs(ETH_TYPE_IPV6)) {
+ if (parent != NULL) {
+ OVS_ACQUIRE_SPIN_LOCK(&(parent->lock), irql);
+ OvsCtUpdateTupleV6(key, &parent->key);
+ OVS_RELEASE_SPIN_LOCK(&(parent->lock), irql);
+ } else {
+ OvsCtUpdateTupleV6(key, &entry->key);
+ }
}
if (entryCreated) {
@@ -1400,13 +1631,15 @@ MapNlToCtTuple(POVS_MESSAGE msgIn, PNL_ATTR ctAttr,
PNL_ATTR ctTupleAttrs[__CTA_MAX];
UINT32 attrOffset;
static const NL_POLICY ctTuplePolicy[] = {
- [CTA_TUPLE_IP] = {.type = NL_A_NESTED, .optional = FALSE },
- [CTA_TUPLE_PROTO] = {.type = NL_A_NESTED, .optional = FALSE},
+ [CTA_TUPLE_IP] = { .type = NL_A_NESTED, .optional = FALSE },
+ [CTA_TUPLE_PROTO] = { .type = NL_A_NESTED, .optional = FALSE},
};
static const NL_POLICY ctTupleIpPolicy[] = {
[CTA_IP_V4_SRC] = { .type = NL_A_BE32, .optional = TRUE },
[CTA_IP_V4_DST] = { .type = NL_A_BE32, .optional = TRUE },
+ [CTA_IP_V6_SRC] = { .type = NL_A_BE32,.optional = TRUE },
+ [CTA_IP_V6_DST] = { .type = NL_A_BE32,.optional = TRUE },
};
static const NL_POLICY ctTupleProtoPolicy[] = {
@@ -1415,6 +1648,9 @@ MapNlToCtTuple(POVS_MESSAGE msgIn, PNL_ATTR ctAttr,
[CTA_PROTO_DST_PORT] = { .type = NL_A_BE16, .optional = TRUE },
[CTA_PROTO_ICMP_TYPE] = { .type = NL_A_U8, .optional = TRUE },
[CTA_PROTO_ICMP_CODE] = { .type = NL_A_U8, .optional = TRUE },
+ [CTA_PROTO_ICMPV6_ID] = { .type = NL_A_BE16,.optional = TRUE },
+ [CTA_PROTO_ICMPV6_TYPE] = { .type = NL_A_U8,.optional = TRUE },
+ [CTA_PROTO_ICMPV6_CODE] = { .type = NL_A_U8,.optional = TRUE },
};
if (!ctAttr) {
@@ -1467,8 +1703,11 @@ MapNlToCtTuple(POVS_MESSAGE msgIn, PNL_ATTR ctAttr,
ctTupleProtoAttrs[CTA_PROTO_ICMP_CODE] ) {
ct_tuple->src_port = NlAttrGetU8(ctTupleProtoAttrs[CTA_PROTO_ICMP_TYPE]);
ct_tuple->dst_port = NlAttrGetU8(ctTupleProtoAttrs[CTA_PROTO_ICMP_CODE]);
+ } else if (ctTupleProtoAttrs[CTA_PROTO_ICMPV6_TYPE] &&
+ ctTupleProtoAttrs[CTA_PROTO_ICMPV6_CODE] ) {
+ ct_tuple->src_port = NlAttrGetU8(ctTupleProtoAttrs[CTA_PROTO_ICMPV6_TYPE]);
+ ct_tuple->dst_port = NlAttrGetU8(ctTupleProtoAttrs[CTA_PROTO_ICMPV6_CODE]);
}
-
}
}
@@ -1551,15 +1790,15 @@ MapProtoTupleToNl(PNL_BUFFER nlBuf, OVS_CT_KEY *key)
goto done;
}
} else if (key->nw_proto == IPPROTO_ICMPV6) {
- if (!NlMsgPutTailU16(nlBuf, CTA_PROTO_ICMPV6_ID, 0)) {
+ if (!NlMsgPutTailU16(nlBuf, CTA_PROTO_ICMPV6_ID, htons(key->src.icmp_id))) {
status = NDIS_STATUS_FAILURE;
goto done;
}
- if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMPV6_TYPE, 0)) {
+ if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMPV6_TYPE, key->src.icmp_type)) {
status = NDIS_STATUS_FAILURE;
goto done;
}
- if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMPV6_CODE, 0)) {
+ if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMPV6_CODE, key->src.icmp_code)) {
status = NDIS_STATUS_FAILURE;
goto done;
}
diff --git a/datapath-windows/ovsext/Conntrack.h b/datapath-windows/ovsext/Conntrack.h
index bbbf49c11..b68a54f30 100644
--- a/datapath-windows/ovsext/Conntrack.h
+++ b/datapath-windows/ovsext/Conntrack.h
@@ -167,33 +167,8 @@ OvsConntrackUpdateExpiration(OVS_CT_ENTRY *ctEntry,
ctEntry->expiration = now + interval;
}
-static const TCPHdr*
-OvsGetTcpHeader(PNET_BUFFER_LIST nbl,
- OVS_PACKET_HDR_INFO *layers,
- VOID *storage,
- UINT32 *tcpPayloadLen)
-{
- IPHdr *ipHdr;
- TCPHdr *tcp;
- VOID *dest = storage;
-
- ipHdr = NdisGetDataBuffer(NET_BUFFER_LIST_FIRST_NB(nbl),
- layers->l4Offset + sizeof(TCPHdr),
- NULL, 1 /*no align*/, 0);
- if (ipHdr == NULL) {
- return NULL;
- }
-
- ipHdr = (IPHdr *)((PCHAR)ipHdr + layers->l3Offset);
- tcp = (TCPHdr *)((PCHAR)ipHdr + ipHdr->ihl * 4);
- if (tcp->doff * 4 >= sizeof *tcp) {
- NdisMoveMemory(dest, tcp, sizeof(TCPHdr));
- *tcpPayloadLen = TCP_DATA_LENGTH(ipHdr, tcp);
- return storage;
- }
-
- return NULL;
-}
+const TCPHdr* OvsGetTcpHeader(PNET_BUFFER_LIST nbl, OVS_PACKET_HDR_INFO *layers,
+ VOID *storage, UINT32 *tcpPayloadLen);
VOID OvsCleanupConntrack(VOID);
NTSTATUS OvsInitConntrack(POVS_SWITCH_CONTEXT context);
@@ -203,6 +178,7 @@ NDIS_STATUS OvsExecuteConntrackAction(OvsForwardingContext *fwdCtx,
const PNL_ATTR a);
BOOLEAN OvsConntrackValidateTcpPacket(const TCPHdr *tcp);
BOOLEAN OvsConntrackValidateIcmpPacket(const ICMPHdr *icmp);
+BOOLEAN OvsConntrackValidateIcmp6Packet(const ICMPHdr *icmp);
OVS_CT_ENTRY * OvsConntrackCreateTcpEntry(const TCPHdr *tcp,
UINT64 now,
UINT32 tcpPayloadLen);
@@ -235,8 +211,8 @@ NTSTATUS OvsInitCtRelated(POVS_SWITCH_CONTEXT context);
VOID OvsCleanupCtRelated(VOID);
NDIS_STATUS OvsCtRelatedEntryCreate(UINT8 ipProto,
UINT16 dl_type,
- UINT32 serverIp,
- UINT32 clientIp,
+ struct ct_addr serverIp,
+ struct ct_addr clientIp,
UINT16 serverPort,
UINT16 clientPort,
UINT64 currentTime,
diff --git a/datapath-windows/ovsext/DpInternal.h b/datapath-windows/ovsext/DpInternal.h
index b5027e35e..6af5748e1 100644
--- a/datapath-windows/ovsext/DpInternal.h
+++ b/datapath-windows/ovsext/DpInternal.h
@@ -207,6 +207,7 @@ typedef __declspec(align(8)) struct OvsFlowKey {
UINT32 state;
struct ovs_key_ct_labels labels;
struct ovs_key_ct_tuple_ipv4 tuple_ipv4;
+ struct ovs_key_ct_tuple_ipv6 tuple_ipv6;
} ct; /* Connection Tracking Flags */
} OvsFlowKey;
@@ -217,6 +218,7 @@ typedef __declspec(align(8)) struct OvsFlowKey {
#define OVS_ARP_KEY_SIZE (sizeof (ArpKey))
#define OVS_ICMPV6_KEY_SIZE (sizeof (Icmp6Key))
#define OVS_MPLS_KEY_SIZE (sizeof (MplsKey))
+#define OVS_TUPLE_IPV6 (sizeof (struct ovs_key_ct_tuple_ipv6))
typedef struct OvsFlowStats {
Ovs64AlignedU64 packetCount;
diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c
index 0a7b2b1d4..08fba4c4d 100644
--- a/datapath-windows/ovsext/Flow.c
+++ b/datapath-windows/ovsext/Flow.c
@@ -186,6 +186,10 @@ const NL_POLICY nlFlowKeyPolicy[] = {
[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4] = {.type = NL_A_UNSPEC,
.minLen = sizeof(struct ovs_key_ct_tuple_ipv4),
.maxLen = sizeof(struct ovs_key_ct_tuple_ipv4),
+ .optional = TRUE},
+ [OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6] = {.type = NL_A_UNSPEC,
+ .minLen = OVS_TUPLE_IPV6,
+ .maxLen = OVS_TUPLE_IPV6,
.optional = TRUE}
};
const UINT32 nlFlowKeyPolicyLen = ARRAY_SIZE(nlFlowKeyPolicy);
@@ -1580,6 +1584,13 @@ _MapKeyAttrToFlowPut(PNL_ATTR *keyAttrs,
sizeof(struct ovs_key_ct_tuple_ipv4));
}
+ if (keyAttrs[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]) {
+ const struct ovs_key_ct_tuple_ipv6 *tuple_ipv6;
+ tuple_ipv6 = NlAttrGet(keyAttrs[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
+ NdisMoveMemory(&destKey->ct.tuple_ipv6, tuple_ipv6,
+ sizeof(struct ovs_key_ct_tuple_ipv6));
+ }
+
/* ===== L2 headers ===== */
if (keyAttrs[OVS_KEY_ATTR_IN_PORT]) {
destKey->l2.inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
@@ -2170,6 +2181,13 @@ OvsGetFlowMetadata(OvsFlowKey *key,
sizeof(struct ovs_key_ct_tuple_ipv4));
}
+ if (keyAttrs[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]) {
+ const struct ovs_key_ct_tuple_ipv6 *tuple_ipv6;
+ tuple_ipv6 = NlAttrGet(keyAttrs[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
+ NdisMoveMemory(&key->ct.tuple_ipv6, tuple_ipv6,
+ sizeof(struct ovs_key_ct_tuple_ipv6));
+ }
+
return status;
}
@@ -2292,6 +2310,7 @@ OvsExtractLayers(const NET_BUFFER_LIST *packet,
if (icmp) {
layers->l7Offset = layers->l4Offset + sizeof *icmp;
}
+ layers->isIcmp = 1;
}
}
} else {
@@ -2651,6 +2670,8 @@ FlowEqual(OvsFlow *srcFlow,
sizeof(struct ovs_key_ct_labels)) &&
!memcmp(&srcFlow->key.ct.tuple_ipv4, &dstKey->ct.tuple_ipv4,
sizeof(struct ovs_key_ct_tuple_ipv4)) &&
+ !memcmp(&srcFlow->key.ct.tuple_ipv6, &dstKey->ct.tuple_ipv6,
+ sizeof(struct ovs_key_ct_tuple_ipv6)) &&
FlowMemoryEqual((UINT64 *)((UINT8 *)&srcFlow->key + offset),
(UINT64 *) dstStart,
size));
@@ -2763,13 +2784,20 @@ OvsLookupFlow(OVS_DATAPATH *datapath,
0);
*hash = OvsJhashWords((UINT32*)hash, 1, lblHash);
}
- if (key->ct.tuple_ipv4.ipv4_src) {
+ if (key->ct.tuple_ipv4.ipv4_proto) {
UINT32 tupleHash = OvsJhashBytes(
&key->ct.tuple_ipv4,
sizeof(struct ovs_key_ct_tuple_ipv4),
0);
*hash = OvsJhashWords((UINT32*)hash, 1, tupleHash);
}
+
+ if (key->ct.tuple_ipv6.ipv6_proto) {
+ UINT32 tupleHash = OvsJhashBytes(&key->ct.tuple_ipv6,
+ sizeof(struct ovs_key_ct_tuple_ipv6),
+ 0);
+ *hash = OvsJhashWords((UINT32*)hash, 1, tupleHash);
+ }
}
head = &datapath->flowTable[HASH_BUCKET(*hash)];
@@ -2945,7 +2973,9 @@ ReportFlowInfo(OvsFlow *flow,
NdisMoveMemory(&info->key.ct.tuple_ipv4,
&flow->key.ct.tuple_ipv4,
sizeof(struct ovs_key_ct_tuple_ipv4));
-
+ NdisMoveMemory(&info->key.ct.tuple_ipv6,
+ &flow->key.ct.tuple_ipv6,
+ sizeof(struct ovs_key_ct_tuple_ipv6));
return status;
}
@@ -3339,6 +3369,13 @@ OvsProbeSupportedFeature(POVS_MESSAGE msgIn,
OVS_LOG_ERROR("Invalid ct_tuple_ipv4.");
status = STATUS_INVALID_PARAMETER;
}
+ } else if (keyAttrs[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]) {
+ const struct ovs_key_ct_tuple_ipv6 *ct_tuple_ipv6;
+ ct_tuple_ipv6 = NlAttrGet(keyAttrs[OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6]);
+ if (!ct_tuple_ipv6) {
+ OVS_LOG_ERROR("Invalid ct_tuple_ipv6.");
+ status = STATUS_INVALID_PARAMETER;
+ }
} else {
OVS_LOG_ERROR("Feature not supported.");
status = STATUS_INVALID_PARAMETER;
diff --git a/datapath-windows/ovsext/NetProto.h b/datapath-windows/ovsext/NetProto.h
index 9a17deee7..39726c203 100644
--- a/datapath-windows/ovsext/NetProto.h
+++ b/datapath-windows/ovsext/NetProto.h
@@ -239,7 +239,8 @@ typedef union _OVS_PACKET_HDR_INFO {
UINT16 tcpCsumNeeded:1;
UINT16 udpCsumNeeded:1;
UINT16 udpCsumZero:1;
- UINT16 pad:8;
+ UINT16 isIcmp:1;
+ UINT16 pad:7;
} ;
UINT64 value;
} OVS_PACKET_HDR_INFO, *POVS_PACKET_HDR_INFO;
@@ -300,6 +301,11 @@ typedef struct IPv6FragHdr {
UINT32 ident;
} IPv6FragHdr;
+typedef struct IPv6OptHdr {
+ UINT8 nextHdr;
+ UINT8 hdrLen;
+} IPv6OptHdr;
+
typedef struct IPv6NdOptHdr {
UINT8 type;
UINT8 len;
diff --git a/datapath-windows/ovsext/PacketParser.c b/datapath-windows/ovsext/PacketParser.c
index f8adcc3c9..aeead5899 100644
--- a/datapath-windows/ovsext/PacketParser.c
+++ b/datapath-windows/ovsext/PacketParser.c
@@ -318,6 +318,7 @@ OvsParseIcmpV6(const NET_BUFFER_LIST *packet,
}
layers->l7Offset = ofs;
+ layers->isIcmp = 1;
return NDIS_STATUS_SUCCESS;
invalid:
diff --git a/datapath-windows/ovsext/Util.c b/datapath-windows/ovsext/Util.c
index abd38c2fe..d703b2468 100644
--- a/datapath-windows/ovsext/Util.c
+++ b/datapath-windows/ovsext/Util.c
@@ -161,3 +161,22 @@ OvsPerCpuDataCleanup()
{
OvsDeferredActionsCleanup();
}
+
+NTSTATUS
+OvsIpv6StringToAddress(const char* ip6String, struct in6_addr *ipv6Addr)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ char *terminator = NULL;
+
+ status = RtlIpv6StringToAddressA(ip6String, &terminator, ipv6Addr);
+ return status;
+}
+
+char *
+OvsIpv6AddressToString(struct in6_addr ipv6Addr, char* ip6String)
+{
+ char *returnedIpv6Str = NULL;
+
+ returnedIpv6Str = RtlIpv6AddressToStringA((&ipv6Addr), ip6String);
+ return returnedIpv6Str;
+} \ No newline at end of file
diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h
index a9bccf36c..f63a885a9 100644
--- a/datapath-windows/ovsext/Util.h
+++ b/datapath-windows/ovsext/Util.h
@@ -143,6 +143,27 @@ OvsPerCpuDataInit();
VOID
OvsPerCpuDataCleanup();
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsIpv6StringToAddress --
+ * The function was used to convert ip6string to binary ipv6 address.
+ * --------------------------------------------------------------------------
+ */
+NTSTATUS
+OvsIpv6StringToAddress(const char* ip6String, struct in6_addr *ipv6Addr);
+
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsIpv6AddressToString --
+ * The function convert bindary ipv6Addr to string.
+ * --------------------------------------------------------------------------
+ */
+char *
+OvsIpv6AddressToString(struct in6_addr ipv6Addr, char* ip6String);
+
+
static LARGE_INTEGER seed;
/*
diff --git a/datapath-windows/ovsext/precomp.h b/datapath-windows/ovsext/precomp.h
index 14f6843d3..e9f62f6ab 100644
--- a/datapath-windows/ovsext/precomp.h
+++ b/datapath-windows/ovsext/precomp.h
@@ -19,6 +19,7 @@
#include <intsafe.h>
#include <ntintsafe.h>
#include <ntstrsafe.h>
+#include <ip2string.h>
#include "Types.h"