[ovs-dev] [PATCH v6] datapath-windows: Add support for UDP and ICMP to Conntrack Module
Sairam Venugopal
vsairam at vmware.com
Thu Jun 16 17:53:38 UTC 2016
Disregard this patch. I will send a consolidated patch with changes.
On 6/15/16, 4:13 PM, "Sairam Venugopal" <vsairam at vmware.com> wrote:
>Enable support for UDP and ICMP in the connection tracking module on
>Hyper-V. Define 1s as variable and reuse it.
>
>Signed-off-by: Sairam Venugopal <vsairam at vmware.com>
>---
> datapath-windows/automake.mk | 1 +
> datapath-windows/ovsext/Conntrack-other.c | 82 +++++++++++++
> datapath-windows/ovsext/Conntrack-tcp.c | 10 +-
> datapath-windows/ovsext/Conntrack.c | 185
>++++++++++++++++++++++--------
> datapath-windows/ovsext/Conntrack.h | 13 ++-
> datapath-windows/ovsext/ovsext.vcxproj | 1 +
> 6 files changed, 239 insertions(+), 53 deletions(-)
> create mode 100644 datapath-windows/ovsext/Conntrack-other.c
>
>diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
>index c9af806..668cf2c 100644
>--- a/datapath-windows/automake.mk
>+++ b/datapath-windows/automake.mk
>@@ -13,6 +13,7 @@ EXTRA_DIST += \
> datapath-windows/ovsext/Atomic.h \
> datapath-windows/ovsext/BufferMgmt.c \
> datapath-windows/ovsext/BufferMgmt.h \
>+ datapath-windows/ovsext/Conntrack-other.c \
> datapath-windows/ovsext/Conntrack-tcp.c \
> datapath-windows/ovsext/Conntrack.c \
> datapath-windows/ovsext/Conntrack.h \
>diff --git a/datapath-windows/ovsext/Conntrack-other.c
>b/datapath-windows/ovsext/Conntrack-other.c
>new file mode 100644
>index 0000000..5d39389
>--- /dev/null
>+++ b/datapath-windows/ovsext/Conntrack-other.c
>@@ -0,0 +1,82 @@
>+/*
>+ * Copyright (c) 2015, 2016 VMware, Inc.
>+ *
>+ * Licensed under the Apache License, Version 2.0 (the "License");
>+ * you may not use this file except in compliance with the License.
>+ * You may obtain a copy of the License at:
>+ *
>+ * http://www.apache.org/licenses/LICENSE-2.0
>+ *
>+ * Unless required by applicable law or agreed to in writing, software
>+ * distributed under the License is distributed on an "AS IS" BASIS,
>+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
>implied.
>+ * See the License for the specific language governing permissions and
>+ * limitations under the License.
>+ */
>+
>+#include "Conntrack.h"
>+#include <stddef.h>
>+
>+enum other_state {
>+ OTHERS_FIRST,
>+ OTHERS_MULTIPLE,
>+ OTHERS_BIDIR,
>+};
>+
>+struct conn_other {
>+ struct OVS_CT_ENTRY up;
>+ enum other_state state;
>+};
>+
>+static const long long other_timeouts[] = {
>+ [OTHERS_FIRST] = 60 * CT_INTERVAL_SEC,
>+ [OTHERS_MULTIPLE] = 60 * CT_INTERVAL_SEC,
>+ [OTHERS_BIDIR] = 30 * CT_INTERVAL_SEC,
>+};
>+
>+static __inline struct conn_other*
>+OvsCastConntrackEntryToOtherEntry(OVS_CT_ENTRY *conn)
>+{
>+ ASSERT(conn);
>+ return CONTAINER_OF(conn, struct conn_other, up);
>+}
>+
>+static __inline VOID
>+OvsConntrackUpdateExpiration(struct conn_other *conn, long long now)
>+{
>+ ASSERT(conn);
>+ conn->up.expiration = now + other_timeouts[conn->state];
>+}
>+
>+enum ct_update_res
>+OvsConntrackUpdateOtherEntry(OVS_CT_ENTRY *conn_,
>+ BOOLEAN reply,
>+ UINT64 now)
>+{
>+ ASSERT(conn_);
>+ struct conn_other *conn = OvsCastConntrackEntryToOtherEntry(conn_);
>+
>+ if (reply && conn->state != OTHERS_BIDIR) {
>+ conn->state = OTHERS_BIDIR;
>+ } else if (conn->state == OTHERS_FIRST) {
>+ conn->state = OTHERS_MULTIPLE;
>+ }
>+
>+ OvsConntrackUpdateExpiration(conn, now);
>+
>+ return CT_UPDATE_VALID;
>+}
>+
>+OVS_CT_ENTRY *
>+OvsConntrackCreateOtherEntry(UINT64 now)
>+{
>+ struct conn_other *conn;
>+ conn = OvsAllocateMemoryWithTag(sizeof(struct conn_other),
>+ OVS_CT_POOL_TAG);
>+ /* XXX Handle memory allocation error (by returning a status) */
>+ ASSERT(conn);
>+ conn->up = (OVS_CT_ENTRY) {0};
>+ conn->state = OTHERS_FIRST;
>+ OvsConntrackUpdateExpiration(conn, now);
>+ return &conn->up;
>+}
>diff --git a/datapath-windows/ovsext/Conntrack-tcp.c
>b/datapath-windows/ovsext/Conntrack-tcp.c
>index 24f5e7c..19925c3 100644
>--- a/datapath-windows/ovsext/Conntrack-tcp.c
>+++ b/datapath-windows/ovsext/Conntrack-tcp.c
>@@ -389,18 +389,18 @@ OvsConntrackUpdateTcpEntry(OVS_CT_ENTRY* conn_,
>
> if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2
> && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) {
>- OvsConntrackUpdateExpiration(conn, now, 30 * 10000000LL);
>+ OvsConntrackUpdateExpiration(conn, now, 30 *
>CT_INTERVAL_SEC);
> } else if (src->state >= CT_DPIF_TCPS_CLOSING
> && dst->state >= CT_DPIF_TCPS_CLOSING) {
>- OvsConntrackUpdateExpiration(conn, now, 45 * 10000000LL);
>+ OvsConntrackUpdateExpiration(conn, now, 45 *
>CT_INTERVAL_SEC);
> } else if (src->state < CT_DPIF_TCPS_ESTABLISHED
> || dst->state < CT_DPIF_TCPS_ESTABLISHED) {
>- OvsConntrackUpdateExpiration(conn, now, 30 * 10000000LL);
>+ OvsConntrackUpdateExpiration(conn, now, 30 *
>CT_INTERVAL_SEC);
> } else if (src->state >= CT_DPIF_TCPS_CLOSING
> || dst->state >= CT_DPIF_TCPS_CLOSING) {
>- OvsConntrackUpdateExpiration(conn, now, 15 * 60 *
>10000000LL);
>+ OvsConntrackUpdateExpiration(conn, now, 15 * 60 *
>CT_INTERVAL_SEC);
> } else {
>- OvsConntrackUpdateExpiration(conn, now, 24 * 60 * 60 *
>10000000LL);
>+ OvsConntrackUpdateExpiration(conn, now, 24 * 60 * 60 *
>CT_INTERVAL_SEC);
> }
> } else if ((dst->state < CT_DPIF_TCPS_SYN_SENT
> || dst->state >= CT_DPIF_TCPS_FIN_WAIT_2
>diff --git a/datapath-windows/ovsext/Conntrack.c
>b/datapath-windows/ovsext/Conntrack.c
>index 544fd51..c3091e0 100644
>--- a/datapath-windows/ovsext/Conntrack.c
>+++ b/datapath-windows/ovsext/Conntrack.c
>@@ -146,9 +146,20 @@ OvsCtUpdateFlowKey(struct OvsFlowKey *key,
> }
> }
>
>+static __inline VOID
>+OvsCtAddEntry(POVS_CT_ENTRY entry, OvsConntrackKeyLookupCtx *ctx)
>+{
>+ NdisMoveMemory(&entry->key, &ctx->key, sizeof (OVS_CT_KEY));
>+ NdisMoveMemory(&entry->rev_key, &ctx->key, sizeof (OVS_CT_KEY));
>+ OvsCtKeyReverse(&entry->rev_key);
>+ InsertHeadList(&ovsConntrackTable[ctx->hash & CT_HASH_TABLE_MASK],
>+ &entry->link);
>+}
>+
> static __inline POVS_CT_ENTRY
>-OvsCtEntryCreate(const TCPHdr *tcp,
>- PNET_BUFFER_LIST curNbl,
>+OvsCtEntryCreate(PNET_BUFFER_LIST curNbl,
>+ UINT8 ipProto,
>+ UINT32 l4Offset,
> OvsConntrackKeyLookupCtx *ctx,
> OvsFlowKey *key,
> BOOLEAN commit,
>@@ -156,26 +167,74 @@ OvsCtEntryCreate(const TCPHdr *tcp,
> {
> POVS_CT_ENTRY entry = NULL;
> UINT32 state = 0;
>- if (!OvsConntrackValidateTcpPacket(tcp)) {
>- state |= OVS_CS_F_INVALID;
>- OvsCtUpdateFlowKey(key, state, ctx->key.zone, 0, NULL);
>- return entry;
>- }
>+ switch (ipProto)
>+ {
>+ case IPPROTO_TCP:
>+ {
>+ TCPHdr tcpStorage;
>+ const TCPHdr *tcp;
>+ tcp = OvsGetTcp(curNbl, l4Offset, &tcpStorage);
>+ if (!OvsConntrackValidateTcpPacket(tcp)) {
>+ goto invalid;
>+ }
>+
>+ state |= OVS_CS_F_NEW;
>+ if (commit) {
>+ entry = OvsConntrackCreateTcpEntry(tcp, curNbl,
>currentTime);
>+ OvsCtAddEntry(entry, ctx);
>+ }
>+
>+ OvsCtUpdateFlowKey(key, state, ctx->key.zone, 0, NULL);
>+ return entry;
>+ }
>+ case IPPROTO_ICMP:
>+ case IPPROTO_UDP:
>+ state |= OVS_CS_F_NEW;
>+ if (commit) {
>+ entry = OvsConntrackCreateOtherEntry(currentTime);
>+ OvsCtAddEntry(entry, ctx);
>+ }
>
>- state |= OVS_CS_F_NEW;
>- if (commit) {
>- entry = OvsConntrackCreateTcpEntry(tcp, curNbl, currentTime);
>- NdisMoveMemory(&entry->key, &ctx->key, sizeof (OVS_CT_KEY));
>- NdisMoveMemory(&entry->rev_key, &ctx->key, sizeof (OVS_CT_KEY));
>- OvsCtKeyReverse(&entry->rev_key);
>- InsertHeadList(&ovsConntrackTable[ctx->hash &
>CT_HASH_TABLE_MASK],
>- &entry->link);
>+ OvsCtUpdateFlowKey(key, state, ctx->key.zone, 0, NULL);
>+ return entry;
>+ default:
>+ goto invalid;
> }
>
>+invalid:
>+ state |= OVS_CS_F_INVALID;
> OvsCtUpdateFlowKey(key, state, ctx->key.zone, 0, NULL);
> return entry;
> }
>
>+static enum CT_UPDATE_RES
>+OvsCtUpdateEntry(OVS_CT_ENTRY* entry,
>+ PNET_BUFFER_LIST nbl,
>+ UINT8 ipProto,
>+ UINT32 l4Offset,
>+ BOOLEAN reply,
>+ UINT64 now)
>+{
>+ switch (ipProto)
>+ {
>+ case IPPROTO_TCP:
>+ {
>+ TCPHdr tcpStorage;
>+ const TCPHdr *tcp;
>+ tcp = OvsGetTcp(nbl, l4Offset, &tcpStorage);
>+ if (!tcp) {
>+ return CT_UPDATE_INVALID;
>+ }
>+ return OvsConntrackUpdateTcpEntry(entry, tcp, nbl, reply,
>now);
>+ }
>+ case IPPROTO_ICMP:
>+ case IPPROTO_UDP:
>+ return OvsConntrackUpdateOtherEntry(entry, reply, now);
>+ default:
>+ return CT_UPDATE_INVALID;
>+ }
>+}
>+
> static __inline VOID
> OvsCtEntryDelete(POVS_CT_ENTRY entry)
> {
>@@ -204,10 +263,12 @@ OvsDetectCtPacket(OvsFlowKey *key)
> if (key->ipKey.nwFrag != OVS_FRAG_TYPE_NONE) {
> return NDIS_STATUS_NOT_SUPPORTED;
> }
>- if (key->ipKey.nwProto != IPPROTO_TCP) {
>- return NDIS_STATUS_NOT_SUPPORTED;
>+ if (key->ipKey.nwProto == IPPROTO_TCP
>+ || key->ipKey.nwProto == IPPROTO_UDP
>+ || key->ipKey.nwProto == IPPROTO_ICMP) {
>+ return NDIS_STATUS_SUCCESS;
> }
>- return NDIS_STATUS_SUCCESS;
>+ return NDIS_STATUS_NOT_SUPPORTED;
> case ETH_TYPE_IPV6:
> return NDIS_STATUS_NOT_SUPPORTED;
> }
>@@ -265,16 +326,31 @@ OvsCtLookup(OvsConntrackKeyLookupCtx *ctx)
> return found;
> }
>
>-static __inline VOID
>-OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
>- UINT16 zone,
>- OvsConntrackKeyLookupCtx *ctx)
>+static __inline UINT32
>+OvsExtractLookupCtxHash(OvsConntrackKeyLookupCtx *ctx)
> {
> UINT32 hsrc, hdst,hash;
>+ hsrc = OvsJhashBytes((UINT32*) &ctx->key.src, sizeof(ctx->key.src),
>0);
>+ hdst = OvsJhashBytes((UINT32*) &ctx->key.dst, sizeof(ctx->key.dst),
>0);
>+ hash = hsrc ^ hdst; /* TO identify reverse traffic */
>+ return OvsJhashBytes((uint32_t *) &ctx->key.dst + 1,
>+ ((uint32_t *) (&ctx->key + 1) -
>+ (uint32_t *) (&ctx->key.dst + 1)),
>+ hash);
>+}
>
>+static __inline NDIS_STATUS
>+OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
>+ UINT16 zone,
>+ OvsConntrackKeyLookupCtx *ctx,
>+ PNET_BUFFER_LIST curNbl,
>+ UINT32 l4Offset)
>+{
> ctx->key.zone = zone;
> ctx->key.dl_type = flowKey->l2.dlType;
>+ ctx->related = FALSE;
>
>+ /* Extract L3 and L4*/
> if (flowKey->l2.dlType == htons(ETH_TYPE_IPV4)) {
> ctx->key.src.addr.ipv4 = flowKey->ipKey.nwSrc;
> ctx->key.dst.addr.ipv4 = flowKey->ipKey.nwDst;
>@@ -282,6 +358,28 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
>
> ctx->key.src.port = flowKey->ipKey.l4.tpSrc;
> ctx->key.dst.port = flowKey->ipKey.l4.tpDst;
>+ if (flowKey->ipKey.nwProto == IPPROTO_ICMP) {
>+ ICMPHdr icmpStorage;
>+ const ICMPHdr *icmp;
>+ icmp = OvsGetIcmp(curNbl, l4Offset, &icmpStorage);
>+ ASSERT(icmp);
>+ ctx->key.src.port = ctx->key.dst.port = icmp->fields.echo.id;
>+
>+ /* Related bit is set when ICMP has an error */
>+ /* XXX parse out the appropriate src and dst from inner pkt
>*/
>+ switch (icmp->type) {
>+ case ICMP4_DEST_UNREACH:
>+ case ICMP4_TIME_EXCEEDED:
>+ case ICMP4_PARAM_PROB:
>+ case ICMP4_SOURCE_QUENCH:
>+ case ICMP4_REDIRECT: {
>+ ctx->related = TRUE;
>+ break;
>+ }
>+ default:
>+ ctx->related = FALSE;
>+ }
>+ }
> } else if (flowKey->l2.dlType == htons(ETH_TYPE_IPV6)) {
> ctx->key.src.addr.ipv6 = flowKey->ipv6Key.ipv6Src;
> ctx->key.dst.addr.ipv6 = flowKey->ipv6Key.ipv6Dst;
>@@ -289,18 +387,13 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
>
> ctx->key.src.port = flowKey->ipv6Key.l4.tpSrc;
> ctx->key.dst.port = flowKey->ipv6Key.l4.tpDst;
>+ /* XXX Handle ICMPv6 errors*/
>+ } else {
>+ return NDIS_STATUS_INVALID_PACKET;
> }
>
>- /* Related bit is set for ICMP and FTP (Not supported)*/
>- ctx->related = FALSE;
>-
>- hsrc = OvsJhashBytes((UINT32*) &ctx->key.src, sizeof(ctx->key.src),
>0);
>- hdst = OvsJhashBytes((UINT32*) &ctx->key.dst, sizeof(ctx->key.dst),
>0);
>- hash = hsrc ^ hdst; /* TO identify reverse traffic */
>- ctx->hash = OvsJhashBytes((uint32_t *) &ctx->key.dst + 1,
>- ((uint32_t *) (&ctx->key + 1) -
>- (uint32_t *) (&ctx->key.dst + 1)),
>- hash);
>+ ctx->hash = OvsExtractLookupCtxHash(ctx);
>+ return NDIS_STATUS_SUCCESS;
> }
>
> /*
>@@ -311,7 +404,7 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
> */
> static __inline POVS_CT_ENTRY
> OvsProcessConntrackEntry(PNET_BUFFER_LIST curNbl,
>- const TCPHdr *tcp,
>+ UINT32 l4Offset,
> OvsConntrackKeyLookupCtx *ctx,
> OvsFlowKey *key,
> UINT16 zone,
>@@ -329,8 +422,8 @@ OvsProcessConntrackEntry(PNET_BUFFER_LIST curNbl,
> }
> } else {
> CT_UPDATE_RES result;
>- result = OvsConntrackUpdateTcpEntry(entry, tcp, curNbl,
>- ctx->reply, currentTime);
>+ result = OvsCtUpdateEntry(entry, curNbl, key->ipKey.nwProto,
>+ l4Offset, ctx->reply, currentTime);
> switch (result) {
> case CT_UPDATE_VALID:
> state |= OVS_CS_F_ESTABLISHED;
>@@ -345,14 +438,18 @@ OvsProcessConntrackEntry(PNET_BUFFER_LIST curNbl,
> //Delete and update the Conntrack
> OvsCtEntryDelete(ctx->entry);
> ctx->entry = NULL;
>- entry = OvsCtEntryCreate(tcp, curNbl, ctx, key,
>- commit, currentTime);
>+ entry = OvsCtEntryCreate(curNbl, key->ipKey.nwProto,
>l4Offset,
>+ ctx, key, commit, currentTime);
> break;
> }
> }
> /* Copy mark and label from entry into flowKey. If actions specify
> different mark and label, update the flowKey. */
>- OvsCtUpdateFlowKey(key, state, zone, entry->mark, &entry->labels);
>+ if (entry) {
>+ OvsCtUpdateFlowKey(key, state, zone, entry->mark,
>&entry->labels);
>+ } else {
>+ OvsCtUpdateFlowKey(key, state, zone, 0, NULL);
>+ }
> return entry;
> }
>
>@@ -401,15 +498,12 @@ OvsCtExecute_(PNET_BUFFER_LIST curNbl,
> NDIS_STATUS status = NDIS_STATUS_SUCCESS;
> POVS_CT_ENTRY entry = NULL;
> OvsConntrackKeyLookupCtx ctx = { 0 };
>- TCPHdr tcpStorage;
>- UINT64 currentTime;
> LOCK_STATE_EX lockState;
>- const TCPHdr *tcp;
>- tcp = OvsGetTcp(curNbl, layers->l4Offset, &tcpStorage);
>+ UINT64 currentTime;
> NdisGetCurrentSystemTime((LARGE_INTEGER *) ¤tTime);
>
> /* Retrieve the Conntrack Key related fields from packet */
>- OvsCtSetupLookupCtx(key, zone, &ctx);
>+ OvsCtSetupLookupCtx(key, zone, &ctx, curNbl, layers->l4Offset);
>
> NdisAcquireRWLockWrite(ovsConntrackLockObj, &lockState, 0);
>
>@@ -418,11 +512,12 @@ OvsCtExecute_(PNET_BUFFER_LIST curNbl,
>
> if (!entry) {
> /* If no matching entry was found, create one and add New state
>*/
>- entry = OvsCtEntryCreate(tcp, curNbl, &ctx,
>+ entry = OvsCtEntryCreate(curNbl, key->ipKey.nwProto,
>+ layers->l4Offset, &ctx,
> key, commit, currentTime);
> } else {
> /* Process the entry and update CT flags */
>- entry = OvsProcessConntrackEntry(curNbl, tcp, &ctx, key,
>+ entry = OvsProcessConntrackEntry(curNbl, layers->l4Offset, &ctx,
>key,
> zone, commit, currentTime);
> }
>
>diff --git a/datapath-windows/ovsext/Conntrack.h
>b/datapath-windows/ovsext/Conntrack.h
>index a754544..883ac57 100644
>--- a/datapath-windows/ovsext/Conntrack.h
>+++ b/datapath-windows/ovsext/Conntrack.h
>@@ -80,8 +80,11 @@ typedef struct OvsConntrackKeyLookupCtx {
>
> #define CT_HASH_TABLE_SIZE ((UINT32)1 << 10)
> #define CT_HASH_TABLE_MASK (CT_HASH_TABLE_SIZE - 1)
>-#define CT_ENTRY_TIMEOUT (2 * 600000000) // 2m
>-#define CT_CLEANUP_INTERVAL (2 * 600000000) // 2m
>+#define CT_INTERVAL_SEC 10000000LL //1s
>+#define CT_ENTRY_TIMEOUT (2 * 60 * CT_INTERVAL_SEC) // 2m
>+#define CT_CLEANUP_INTERVAL (2 * 60 * CT_INTERVAL_SEC) // 2m
>+
>+
> /* Given POINTER, the address of the given MEMBER in a STRUCT object,
>returns
> the STRUCT object. */
> #define CONTAINER_OF(POINTER, STRUCT, MEMBER) \
>@@ -99,9 +102,13 @@ BOOLEAN OvsConntrackValidateTcpPacket(const TCPHdr
>*tcp);
> OVS_CT_ENTRY * OvsConntrackCreateTcpEntry(const TCPHdr *tcp,
> PNET_BUFFER_LIST nbl,
> UINT64 now);
>+OVS_CT_ENTRY * OvsConntrackCreateOtherEntry(UINT64 now);
> enum CT_UPDATE_RES OvsConntrackUpdateTcpEntry(OVS_CT_ENTRY* conn_,
> const TCPHdr *tcp,
> PNET_BUFFER_LIST nbl,
> BOOLEAN reply,
> UINT64 now);
>-#endif /* __OVS_CONNTRACK_H_ */
>\ No newline at end of file
>+enum ct_update_res OvsConntrackUpdateOtherEntry(OVS_CT_ENTRY *conn_,
>+ BOOLEAN reply,
>+ UINT64 now);
>+#endif /* __OVS_CONNTRACK_H_ */
>diff --git a/datapath-windows/ovsext/ovsext.vcxproj
>b/datapath-windows/ovsext/ovsext.vcxproj
>index 0356ddf..0ad4c58 100644
>--- a/datapath-windows/ovsext/ovsext.vcxproj
>+++ b/datapath-windows/ovsext/ovsext.vcxproj
>@@ -176,6 +176,7 @@
> <ItemGroup>
> <ClCompile Include="Actions.c" />
> <ClCompile Include="BufferMgmt.c" />
>+ <ClCompile Include="Conntrack-other.c" />
> <ClCompile Include="Conntrack-tcp.c" />
> <ClCompile Include="Conntrack.c" />
> <ClCompile Include="Debug.c" />
>--
>2.5.0.windows.1
>
More information about the dev
mailing list