On 9 November 2016 at 16:34, Sairam Venugopal <[email protected]> wrote:
> Add support for tracking ICMP code and Type in the Hyper-V Conntrack > module. This code is similar to the userspace connection tracker. > > Signed-off-by: Sairam Venugopal <[email protected]> > Thanks, applied. > --- > datapath-windows/ovsext/Conntrack-icmp.c | 84 > +++++++++++++++++++++++++++++++ > datapath-windows/ovsext/Conntrack-other.c | 15 ++---- > datapath-windows/ovsext/Conntrack-tcp.c | 25 ++++----- > datapath-windows/ovsext/Conntrack.c | 73 > ++++++++++++++++++++++++--- > datapath-windows/ovsext/Conntrack.h | 24 ++++++++- > datapath-windows/ovsext/ovsext.vcxproj | 1 + > 6 files changed, 190 insertions(+), 32 deletions(-) > create mode 100644 datapath-windows/ovsext/Conntrack-icmp.c > > diff --git a/datapath-windows/ovsext/Conntrack-icmp.c > b/datapath-windows/ovsext/Conntrack-icmp.c > new file mode 100644 > index 0000000..7db8e7d > --- /dev/null > +++ b/datapath-windows/ovsext/Conntrack-icmp.c > @@ -0,0 +1,84 @@ > +/* > + * Copyright (c) 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 "NetProto.h" > +#include "Conntrack.h" > +#include <stddef.h> > + > +enum icmp_state { > + ICMPS_FIRST, > + ICMPS_REPLY, > +}; > + > +struct conn_icmp { > + struct OVS_CT_ENTRY up; > + enum icmp_state state; > +}; > + > +static const enum ct_timeout icmp_timeouts[] = { > + [ICMPS_FIRST] = 60 * CT_INTERVAL_SEC, > + [ICMPS_REPLY] = 30 * CT_INTERVAL_SEC, > +}; > + > +static __inline struct conn_icmp * > +OvsCastConntrackEntryToIcmpEntry(OVS_CT_ENTRY* conn) > +{ > + return CONTAINER_OF(conn, struct conn_icmp, up); > +} > + > +enum CT_UPDATE_RES > +OvsConntrackUpdateIcmpEntry(OVS_CT_ENTRY* conn_, > + BOOLEAN reply, > + UINT64 now) > +{ > + struct conn_icmp *conn = OvsCastConntrackEntryToIcmpEntry(conn_); > + > + if (reply && conn->state != ICMPS_REPLY) { > + conn->state = ICMPS_REPLY; > + } > + > + OvsConntrackUpdateExpiration(&conn->up, now, > + icmp_timeouts[conn->state]); > + > + return CT_UPDATE_VALID; > +} > + > +BOOLEAN > +OvsConntrackValidateIcmpPacket(const ICMPHdr *icmp) > +{ > + return icmp->type == ICMP4_ECHO_REQUEST > + || icmp->type == ICMP4_INFO_REQUEST > + || icmp->type == ICMP4_TIMESTAMP_REQUEST; > +} > + > +OVS_CT_ENTRY * > +OvsConntrackCreateIcmpEntry(UINT64 now) > +{ > + struct conn_icmp *conn; > + > + conn = OvsAllocateMemoryWithTag(sizeof(struct conn_icmp), > + OVS_CT_POOL_TAG); > + if (!conn) { > + return NULL; > + } > + > + conn->state = ICMPS_FIRST; > + > + OvsConntrackUpdateExpiration(&conn->up, now, > + icmp_timeouts[conn->state]); > + > + return &conn->up; > +} > diff --git a/datapath-windows/ovsext/Conntrack-other.c > b/datapath-windows/ovsext/Conntrack-other.c > index b853020..6c68ba8 100644 > --- a/datapath-windows/ovsext/Conntrack-other.c > +++ b/datapath-windows/ovsext/Conntrack-other.c > @@ -41,14 +41,7 @@ OvsCastConntrackEntryToOtherEntry(OVS_CT_ENTRY *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 > +enum CT_UPDATE_RES > OvsConntrackUpdateOtherEntry(OVS_CT_ENTRY *conn_, > BOOLEAN reply, > UINT64 now) > @@ -62,7 +55,8 @@ OvsConntrackUpdateOtherEntry(OVS_CT_ENTRY *conn_, > conn->state = OTHERS_MULTIPLE; > } > > - OvsConntrackUpdateExpiration(conn, now); > + OvsConntrackUpdateExpiration(&conn->up, now, > + other_timeouts[conn->state]); > > return CT_UPDATE_VALID; > } > @@ -78,6 +72,7 @@ OvsConntrackCreateOtherEntry(UINT64 now) > } > conn->up = (OVS_CT_ENTRY) {0}; > conn->state = OTHERS_FIRST; > - OvsConntrackUpdateExpiration(conn, now); > + OvsConntrackUpdateExpiration(&conn->up, now, > + other_timeouts[conn->state]); > return &conn->up; > } > diff --git a/datapath-windows/ovsext/Conntrack-tcp.c > b/datapath-windows/ovsext/Conntrack-tcp.c > index 6adf490..c7fcfa8 100644 > --- a/datapath-windows/ovsext/Conntrack-tcp.c > +++ b/datapath-windows/ovsext/Conntrack-tcp.c > @@ -199,14 +199,6 @@ OvsGetTcpPayloadLength(PNET_BUFFER_LIST nbl) > - (sizeof * tcp); > } > > -static __inline void > -OvsConntrackUpdateExpiration(struct conn_tcp *conn, > - long long now, > - long long interval) > -{ > - conn->up.expiration = now + interval; > -} > - > static __inline struct conn_tcp* > OvsCastConntrackEntryToTcpEntry(OVS_CT_ENTRY* conn) > { > @@ -383,18 +375,23 @@ 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 * > CT_INTERVAL_SEC); > + OvsConntrackUpdateExpiration(&conn->up, now, > + 30 * CT_INTERVAL_SEC); > } else if (src->state >= CT_DPIF_TCPS_CLOSING > && dst->state >= CT_DPIF_TCPS_CLOSING) { > - OvsConntrackUpdateExpiration(conn, now, 45 * > CT_INTERVAL_SEC); > + OvsConntrackUpdateExpiration(&conn->up, now, > + 45 * CT_INTERVAL_SEC); > } else if (src->state < CT_DPIF_TCPS_ESTABLISHED > || dst->state < CT_DPIF_TCPS_ESTABLISHED) { > - OvsConntrackUpdateExpiration(conn, now, 30 * > CT_INTERVAL_SEC); > + OvsConntrackUpdateExpiration(&conn->up, now, > + 30 * CT_INTERVAL_SEC); > } else if (src->state >= CT_DPIF_TCPS_CLOSING > || dst->state >= CT_DPIF_TCPS_CLOSING) { > - OvsConntrackUpdateExpiration(conn, now, 15 * 60 * > CT_INTERVAL_SEC); > + OvsConntrackUpdateExpiration(&conn->up, now, > + 15 * 60 * CT_INTERVAL_SEC); > } else { > - OvsConntrackUpdateExpiration(conn, now, 24 * 60 * 60 * > CT_INTERVAL_SEC); > + OvsConntrackUpdateExpiration(&conn->up, now, > + 24 * 60 * 60 * CT_INTERVAL_SEC); > } > } else if ((dst->state < CT_DPIF_TCPS_SYN_SENT > || dst->state >= CT_DPIF_TCPS_FIN_WAIT_2 > @@ -518,7 +515,7 @@ OvsConntrackCreateTcpEntry(const TCPHdr *tcp, > src->state = CT_DPIF_TCPS_SYN_SENT; > dst->state = CT_DPIF_TCPS_CLOSED; > > - OvsConntrackUpdateExpiration(newconn, now, CT_ENTRY_TIMEOUT); > + OvsConntrackUpdateExpiration(&newconn->up, now, CT_ENTRY_TIMEOUT); > > return &newconn->up; > } > diff --git a/datapath-windows/ovsext/Conntrack.c > b/datapath-windows/ovsext/Conntrack.c > index 74fb38c..b0846f6 100644 > --- a/datapath-windows/ovsext/Conntrack.c > +++ b/datapath-windows/ovsext/Conntrack.c > @@ -211,7 +211,28 @@ OvsCtEntryCreate(PNET_BUFFER_LIST curNbl, > return entry; > } > case IPPROTO_ICMP: > + { > + ICMPHdr storage; > + const ICMPHdr *icmp; > + icmp = OvsGetIcmp(curNbl, l4Offset, &storage); > + if (!OvsConntrackValidateIcmpPacket(icmp)) { > + goto invalid; > + } > + > + state |= OVS_CS_F_NEW; > + if (commit) { > + entry = OvsConntrackCreateIcmpEntry(currentTime); > + if (!entry) { > + return NULL; > + } > + OvsCtAddEntry(entry, ctx, currentTime); > + } > + > + OvsCtUpdateFlowKey(key, state, ctx->key.zone, 0, NULL); > + return entry; > + } > case IPPROTO_UDP: > + { > state |= OVS_CS_F_NEW; > if (commit) { > entry = OvsConntrackCreateOtherEntry(currentTime); > @@ -223,6 +244,7 @@ OvsCtEntryCreate(PNET_BUFFER_LIST curNbl, > > OvsCtUpdateFlowKey(key, state, ctx->key.zone, 0, NULL); > return entry; > + } > default: > goto invalid; > } > @@ -254,6 +276,7 @@ OvsCtUpdateEntry(OVS_CT_ENTRY* entry, > return OvsConntrackUpdateTcpEntry(entry, tcp, nbl, reply, > now); > } > case IPPROTO_ICMP: > + return OvsConntrackUpdateIcmpEntry(entry, reply, now); > case IPPROTO_UDP: > return OvsConntrackUpdateOtherEntry(entry, reply, now); > default: > @@ -338,8 +361,7 @@ OvsCtLookup(OvsConntrackKeyLookupCtx *ctx) > BOOLEAN reply = FALSE; > POVS_CT_ENTRY found = NULL; > > - if (!ctTotalEntries) > - { > + if (!ctTotalEntries) { > return found; > } > > @@ -384,6 +406,27 @@ OvsExtractLookupCtxHash(OvsConntrackKeyLookupCtx > *ctx) > hash); > } > > +static UINT8 > +OvsReverseIcmpType(UINT8 type) > +{ > + switch (type) { > + case ICMP4_ECHO_REQUEST: > + return ICMP4_ECHO_REPLY; > + case ICMP4_ECHO_REPLY: > + return ICMP4_ECHO_REQUEST; > + case ICMP4_TIMESTAMP_REQUEST: > + return ICMP4_TIMESTAMP_REPLY; > + case ICMP4_TIMESTAMP_REPLY: > + return ICMP4_TIMESTAMP_REQUEST; > + case ICMP4_INFO_REQUEST: > + return ICMP4_INFO_REPLY; > + case ICMP4_INFO_REPLY: > + return ICMP4_INFO_REQUEST; > + default: > + return 0; > + } > +} > + > static __inline NDIS_STATUS > OvsCtSetupLookupCtx(OvsFlowKey *flowKey, > UINT16 zone, > @@ -408,16 +451,31 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey, > 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_ECHO_REQUEST: > + case ICMP4_ECHO_REPLY: > + case ICMP4_TIMESTAMP_REQUEST: > + case ICMP4_TIMESTAMP_REPLY: > + case ICMP4_INFO_REQUEST: > + case ICMP4_INFO_REPLY: > + if (icmp->code != 0) { > + 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.src.icmp_type = icmp->type; > + ctx->key.dst.icmp_type = OvsReverseIcmpType(icmp->type) > ; > + break; > case ICMP4_DEST_UNREACH: > case ICMP4_TIME_EXCEEDED: > case ICMP4_PARAM_PROB: > case ICMP4_SOURCE_QUENCH: > case ICMP4_REDIRECT: { > + /* XXX Handle inner packet */ > ctx->related = TRUE; > break; > } > @@ -830,15 +888,18 @@ MapProtoTupleToNl(PNL_BUFFER nlBuf, OVS_CT_KEY *key) > || key->dl_type == ntohs(ETH_TYPE_IPV6)) { > /* ICMP and ICMPv6 Type, Code and ID are currently not tracked */ > if (key->nw_proto == IPPROTO_ICMP) { > - if (!NlMsgPutTailU16(nlBuf, CTA_PROTO_ICMP_ID, 0)) { > + if (!NlMsgPutTailU16(nlBuf, CTA_PROTO_ICMP_ID, > + htons(key->src.icmp_id))) { > status = NDIS_STATUS_FAILURE; > goto done; > } > - if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMP_TYPE, 0)) { > + if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMP_TYPE, > + key->src.icmp_type)) { > status = NDIS_STATUS_FAILURE; > goto done; > } > - if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMP_CODE, 0)) { > + if (!NlMsgPutTailU8(nlBuf, CTA_PROTO_ICMP_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 4995ff4..270e2dd 100644 > --- a/datapath-windows/ovsext/Conntrack.h > +++ b/datapath-windows/ovsext/Conntrack.h > @@ -31,7 +31,14 @@ struct ct_addr { > > struct ct_endpoint { > struct ct_addr addr; > - ovs_be16 port; > + union { > + ovs_be16 port; > + struct { > + ovs_be16 icmp_id; > + uint8_t icmp_type; > + uint8_t icmp_code; > + }; > + }; > UINT16 pad; > }; > > @@ -94,6 +101,14 @@ typedef struct OvsConntrackKeyLookupCtx { > ((STRUCT *) (void *) ((char *) (POINTER) - \ > offsetof (STRUCT, MEMBER))) > > +static __inline void > +OvsConntrackUpdateExpiration(OVS_CT_ENTRY *ctEntry, > + long long now, > + long long interval) > +{ > + ctEntry->expiration = now + interval; > +} > + > VOID OvsCleanupConntrack(VOID); > NTSTATUS OvsInitConntrack(POVS_SWITCH_CONTEXT context); > > @@ -102,20 +117,25 @@ NDIS_STATUS OvsExecuteConntrackAction(PNET_BUFFER_LIST > curNbl, > OvsFlowKey *key, > const PNL_ATTR a); > BOOLEAN OvsConntrackValidateTcpPacket(const TCPHdr *tcp); > +BOOLEAN OvsConntrackValidateIcmpPacket(const ICMPHdr *icmp); > OVS_CT_ENTRY * OvsConntrackCreateTcpEntry(const TCPHdr *tcp, > PNET_BUFFER_LIST nbl, > UINT64 now); > NDIS_STATUS OvsCtMapTcpProtoInfoToNl(PNL_BUFFER nlBuf, > OVS_CT_ENTRY *conn_); > OVS_CT_ENTRY * OvsConntrackCreateOtherEntry(UINT64 now); > +OVS_CT_ENTRY * OvsConntrackCreateIcmpEntry(UINT64 now); > enum CT_UPDATE_RES OvsConntrackUpdateTcpEntry(OVS_CT_ENTRY* conn_, > const TCPHdr *tcp, > PNET_BUFFER_LIST nbl, > BOOLEAN reply, > UINT64 now); > -enum ct_update_res OvsConntrackUpdateOtherEntry(OVS_CT_ENTRY *conn_, > +enum CT_UPDATE_RES OvsConntrackUpdateOtherEntry(OVS_CT_ENTRY *conn_, > BOOLEAN reply, > UINT64 now); > +enum CT_UPDATE_RES OvsConntrackUpdateIcmpEntry(OVS_CT_ENTRY* conn_, > + BOOLEAN reply, > + UINT64 now); > NTSTATUS > OvsCreateNlMsgFromCtEntry(POVS_CT_ENTRY entry, > PVOID outBuffer, > diff --git a/datapath-windows/ovsext/ovsext.vcxproj > b/datapath-windows/ovsext/ovsext.vcxproj > index a00deb0..77530fd 100644 > --- a/datapath-windows/ovsext/ovsext.vcxproj > +++ b/datapath-windows/ovsext/ovsext.vcxproj > @@ -178,6 +178,7 @@ > <ItemGroup> > <ClCompile Include="Actions.c" /> > <ClCompile Include="BufferMgmt.c" /> > + <ClCompile Include="Conntrack-icmp.c" /> > <ClCompile Include="Conntrack-other.c" /> > <ClCompile Include="Conntrack-tcp.c" /> > <ClCompile Include="Conntrack.c" /> > -- > 2.9.0.windows.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
