Acked-by: Anand Kumar    <[email protected]>

On 11/9/16, 4:34 PM, "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]>
    ---
     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

Reply via email to