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 <vsai...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev