Message ID | 1466032436-7868-1-git-send-email-vsairam@vmware.com |
---|---|
State | Not Applicable |
Headers | show |
Disregard this patch. I will send a consolidated patch with changes. On 6/15/16, 4:13 PM, "Sairam Venugopal" <vsairam@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@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 >
> -----Mesaj original----- > De la: dev [mailto:dev-bounces@openvswitch.org] În numele Sairam > Venugopal > Trimis: Thursday, June 16, 2016 8:54 PM > Către: Sairam Venugopal <vsairam@vmware.com>; dev@openvswitch.org > Subiect: Re: [ovs-dev] [PATCH v6] datapath-windows: Add support for UDP > and ICMP to Conntrack Module > > Disregard this patch. I will send a consolidated patch with changes. > [Alin Gabriel Serdean: ] Looking forward for a v7. Thanks, Alin.
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" />
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@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