diff options
Diffstat (limited to 'datapath-windows')
-rw-r--r-- | datapath-windows/ovsext/Actions.c | 174 | ||||
-rw-r--r-- | datapath-windows/ovsext/Actions.h | 5 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-ftp.c | 159 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-icmp.c | 11 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-nat.c | 82 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-related.c | 45 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack.c | 287 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack.h | 34 | ||||
-rw-r--r-- | datapath-windows/ovsext/DpInternal.h | 2 | ||||
-rw-r--r-- | datapath-windows/ovsext/Flow.c | 41 | ||||
-rw-r--r-- | datapath-windows/ovsext/NetProto.h | 8 | ||||
-rw-r--r-- | datapath-windows/ovsext/PacketParser.c | 1 | ||||
-rw-r--r-- | datapath-windows/ovsext/Util.c | 19 | ||||
-rw-r--r-- | datapath-windows/ovsext/Util.h | 21 | ||||
-rw-r--r-- | datapath-windows/ovsext/precomp.h | 1 |
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" |