diff mbox

[ovs-dev,v3,4/4] datapath-windows: Conntrack - Enable FTP support

Message ID 20161216222812.128904-5-vsairam@vmware.com
State Accepted
Headers show

Commit Message

Sairam Venugopal Dec. 16, 2016, 10:28 p.m. UTC
Enable the support for tracking FTP connections in the Connection tracker.
This checks an incoming ftp control connection to extract the related data
connection. When a matching data connection arrives, it would then update
the connection entry to point to the original control connection.

Signed-off-by: Sairam Venugopal <vsairam@vmware.com>
---
 datapath-windows/ovsext/Conntrack.c       | 61 ++++++++++++++++++++++++++++++-
 datapath-windows/ovsext/Conntrack.h       |  8 ++++
 datapath-windows/ovsext/Netlink/Netlink.c | 16 ++++++++
 datapath-windows/ovsext/Netlink/Netlink.h |  1 +
 datapath-windows/ovsext/Switch.c          |  8 ++++
 5 files changed, 92 insertions(+), 2 deletions(-)

Comments

Alin Serdean Dec. 20, 2016, 5:09 p.m. UTC | #1
Acked-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>


> -----Original Message-----
> From: ovs-dev-bounces@openvswitch.org [mailto:ovs-dev-
> bounces@openvswitch.org] On Behalf Of Sairam Venugopal
> Sent: Saturday, December 17, 2016 12:28 AM
> To: dev@openvswitch.org
> Subject: [ovs-dev] [PATCH v3 4/4] datapath-windows: Conntrack - Enable FTP
> support
> 
> Enable the support for tracking FTP connections in the Connection tracker.
> This checks an incoming ftp control connection to extract the related data
> connection. When a matching data connection arrives, it would then update
> the connection entry to point to the original control connection.
> 
> Signed-off-by: Sairam Venugopal <vsairam@vmware.com>
> ---
>  datapath-windows/ovsext/Conntrack.c       | 61
> ++++++++++++++++++++++++++++++-
>  datapath-windows/ovsext/Conntrack.h       |  8 ++++
>  datapath-windows/ovsext/Netlink/Netlink.c | 16 ++++++++  datapath-
> windows/ovsext/Netlink/Netlink.h |  1 +
>  datapath-windows/ovsext/Switch.c          |  8 ++++
>  5 files changed, 92 insertions(+), 2 deletions(-)
> 
> diff --git a/datapath-windows/ovsext/Conntrack.c b/datapath-
> windows/ovsext/Conntrack.c
> index 70c32a4..53d2cf9 100644
> --- a/datapath-windows/ovsext/Conntrack.c
> +++ b/datapath-windows/ovsext/Conntrack.c
> @@ -192,11 +192,21 @@ OvsCtEntryCreate(PNET_BUFFER_LIST curNbl,
>              }
> 
>              state |= OVS_CS_F_NEW;
> +            POVS_CT_ENTRY parentEntry = NULL;
> +            parentEntry = OvsCtRelatedLookup(ctx->key, currentTime);
> +            if (parentEntry != NULL) {
> +                state |= OVS_CS_F_RELATED;
> +            }
> +
>              if (commit) {
>                  entry = OvsConntrackCreateTcpEntry(tcp, curNbl, currentTime);
>                  if (!entry) {
>                      return NULL;
>                  }
> +                /* If this is related entry, then update parent */
> +                if (parentEntry != NULL) {
> +                    entry->parent = parentEntry;
> +                }
>                  OvsCtAddEntry(entry, ctx, currentTime);
>              }
> 
> @@ -492,6 +502,13 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
>      return NDIS_STATUS_SUCCESS;
>  }
> 
> +static __inline BOOLEAN
> +OvsDetectFtpPacket(OvsFlowKey *key) {
> +    return (key->ipKey.nwProto == IPPROTO_TCP &&
> +            (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP ||
> +            ntohs(key->ipKey.l4.tpSrc) == IPPORT_FTP)); }
> +
>  /*
>   *----------------------------------------------------------------------------
>   * OvsProcessConntrackEntry
> @@ -542,6 +559,21 @@ OvsProcessConntrackEntry(PNET_BUFFER_LIST
> curNbl,
>              break;
>          }
>      }
> +
> +    if (key->ipKey.nwProto == IPPROTO_TCP && entry) {
> +        /* Update the related bit if there is a parent */
> +        if (entry->parent) {
> +            state |= OVS_CS_F_RELATED;
> +        } else {
> +            POVS_CT_ENTRY parentEntry;
> +            parentEntry = OvsCtRelatedLookup(ctx->key, currentTime);
> +            if (parentEntry != NULL) {
> +                entry->parent = parentEntry;
> +                state |= OVS_CS_F_RELATED;
> +            }
> +        }
> +    }
> +
>      /* Copy mark and label from entry into flowKey. If actions specify
>         different mark and label, update the flowKey. */
>      if (entry != NULL) {
> @@ -592,7 +624,8 @@ OvsCtExecute_(PNET_BUFFER_LIST curNbl,
>                BOOLEAN commit,
>                UINT16 zone,
>                MD_MARK *mark,
> -              MD_LABELS *labels)
> +              MD_LABELS *labels,
> +              PCHAR helper)
>  {
>      NDIS_STATUS status = NDIS_STATUS_SUCCESS;
>      POVS_CT_ENTRY entry = NULL;
> @@ -629,6 +662,17 @@ OvsCtExecute_(PNET_BUFFER_LIST curNbl,
>          OvsConntrackSetLabels(key, entry, &labels->value, &labels->mask);
>      }
> 
> +    if (entry && OvsDetectFtpPacket(key)) {
> +        /* FTP parser will always be loaded */
> +        UNREFERENCED_PARAMETER(helper);
> +
> +        status = OvsCtHandleFtp(curNbl, key, layers, currentTime, entry,
> +                                (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP));
> +        if (status != NDIS_STATUS_SUCCESS) {
> +            OVS_LOG_ERROR("Error while parsing the FTP packet");
> +        }
> +    }
> +
>      NdisReleaseRWLock(ovsConntrackLockObj, &lockState);
> 
>      return status;
> @@ -651,6 +695,8 @@ OvsExecuteConntrackAction(PNET_BUFFER_LIST
> curNbl,
>      UINT16 zone = 0;
>      MD_MARK *mark = NULL;
>      MD_LABELS *labels = NULL;
> +    PCHAR helper = NULL;
> +
>      NDIS_STATUS status;
> 
>      status = OvsDetectCtPacket(key);
> @@ -674,9 +720,20 @@ OvsExecuteConntrackAction(PNET_BUFFER_LIST
> curNbl,
>      if (ctAttr) {
>          labels = NlAttrGet(ctAttr);
>      }
> +    ctAttr = NlAttrFindNested(a, OVS_CT_ATTR_HELPER);
> +    if (ctAttr) {
> +        helper = NlAttrGetString(ctAttr);
> +        if (helper == NULL) {
> +            return NDIS_STATUS_INVALID_PARAMETER;
> +        }
> +        if (strcmp("ftp", helper) != 0) {
> +            /* Only support FTP */
> +            return NDIS_STATUS_NOT_SUPPORTED;
> +        }
> +    }
> 
>      status = OvsCtExecute_(curNbl, key, layers,
> -                           commit, zone, mark, labels);
> +                           commit, zone, mark, labels, helper);
>      return status;
>  }
> 
> diff --git a/datapath-windows/ovsext/Conntrack.h b/datapath-
> windows/ovsext/Conntrack.h
> index 7f1ec6f..af99885 100644
> --- a/datapath-windows/ovsext/Conntrack.h
> +++ b/datapath-windows/ovsext/Conntrack.h
> @@ -85,6 +85,7 @@ typedef struct OVS_CT_ENTRY {
>      UINT32      mark;
>      UINT64      timestampStart;
>      struct ovs_key_ct_labels labels;
> +    PVOID       parent; /* Points to main connection */
>  } OVS_CT_ENTRY, *POVS_CT_ENTRY;
> 
>  typedef struct OVS_CT_REL_ENTRY {
> @@ -200,4 +201,11 @@ NDIS_STATUS OvsCtRelatedEntryCreate(UINT8
> ipProto,
>                                      POVS_CT_ENTRY parent);  POVS_CT_ENTRY
> OvsCtRelatedLookup(OVS_CT_KEY key, UINT64 currentTime);
> 
> +NDIS_STATUS OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
> +                           OvsFlowKey *key,
> +                           OVS_PACKET_HDR_INFO *layers,
> +                           UINT64 currentTime,
> +                           POVS_CT_ENTRY entry,
> +                           BOOLEAN request);
> +
>  #endif /* __OVS_CONNTRACK_H_ */
> diff --git a/datapath-windows/ovsext/Netlink/Netlink.c b/datapath-
> windows/ovsext/Netlink/Netlink.c
> index 2432205..a63f066 100644
> --- a/datapath-windows/ovsext/Netlink/Netlink.c
> +++ b/datapath-windows/ovsext/Netlink/Netlink.c
> @@ -992,6 +992,22 @@ NlAttrGetU64(const PNL_ATTR nla)
> 
>  /*
>   * ---------------------------------------------------------------------------
> + * Returns the string value in 'nla''s payload.
> + * Returns NULL if it is not a proper '\0' terminated string.
> + *
> +-----------------------------------------------------------------------
> +----
> + */
> +PCHAR
> +NlAttrGetString(const PNL_ATTR nla)
> +{
> +    ASSERT(nla->nlaLen >= NLA_HDRLEN);
> +    if (!memchr(NlAttrGet(nla), '\0', nla->nlaLen - NLA_HDRLEN)) {
> +        return NULL;
> +    }
> +    return NlAttrGet(nla);
> +}
> +
> +/*
> + *
> +-----------------------------------------------------------------------
> +----
>   * Validate the netlink attribute against the policy
>   * ---------------------------------------------------------------------------
>   */
> diff --git a/datapath-windows/ovsext/Netlink/Netlink.h b/datapath-
> windows/ovsext/Netlink/Netlink.h
> index 363f575..964c0e5 100644
> --- a/datapath-windows/ovsext/Netlink/Netlink.h
> +++ b/datapath-windows/ovsext/Netlink/Netlink.h
> @@ -138,6 +138,7 @@ UINT8 NlAttrGetU8(const PNL_ATTR nla);
>  UINT16 NlAttrGetU16(const PNL_ATTR nla);
>  UINT32 NlAttrGetU32(const PNL_ATTR nla);
>  UINT64 NlAttrGetU64(const PNL_ATTR nla);
> +PCHAR NlAttrGetString(const PNL_ATTR nla);
>  const PNL_ATTR NlAttrFind__(const PNL_ATTR attrs,
>                              UINT32 size, UINT16 type);  const PNL_ATTR
> NlAttrFindNested(const PNL_ATTR nla, diff --git a/datapath-
> windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c
> index db023e9..138a656 100644
> --- a/datapath-windows/ovsext/Switch.c
> +++ b/datapath-windows/ovsext/Switch.c
> @@ -225,6 +225,13 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
>          goto create_switch_done;
>      }
> 
> +    status = OvsInitCtRelated(switchContext);
> +    if (status != STATUS_SUCCESS) {
> +        OvsUninitSwitchContext(switchContext);
> +        OVS_LOG_ERROR("Exit: Failed to initialize Connection tracking");
> +        goto create_switch_done;
> +    }
> +
>      *switchContextOut = switchContext;
> 
>  create_switch_done:
> @@ -257,6 +264,7 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext)
>      OvsCleanupIpHelper();
>      OvsCleanupSttDefragmentation();
>      OvsCleanupConntrack();
> +    OvsCleanupCtRelated();
>      /* This completes the cleanup, and a new attach can be handled now. */
> 
>      OVS_LOG_TRACE("Exit: OvsDetach Successfully");
> --
> 2.9.0.windows.1
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Gurucharan Shetty Dec. 20, 2016, 5:34 p.m. UTC | #2
On 16 December 2016 at 14:28, Sairam Venugopal <vsairam@vmware.com> wrote:

> Enable the support for tracking FTP connections in the Connection tracker.
> This checks an incoming ftp control connection to extract the related data
> connection. When a matching data connection arrives, it would then update
> the connection entry to point to the original control connection.
>
> Signed-off-by: Sairam Venugopal <vsairam@vmware.com>
>

I applied the series, thank you!


> ---
>  datapath-windows/ovsext/Conntrack.c       | 61
> ++++++++++++++++++++++++++++++-
>  datapath-windows/ovsext/Conntrack.h       |  8 ++++
>  datapath-windows/ovsext/Netlink/Netlink.c | 16 ++++++++
>  datapath-windows/ovsext/Netlink/Netlink.h |  1 +
>  datapath-windows/ovsext/Switch.c          |  8 ++++
>  5 files changed, 92 insertions(+), 2 deletions(-)
>
> diff --git a/datapath-windows/ovsext/Conntrack.c
> b/datapath-windows/ovsext/Conntrack.c
> index 70c32a4..53d2cf9 100644
> --- a/datapath-windows/ovsext/Conntrack.c
> +++ b/datapath-windows/ovsext/Conntrack.c
> @@ -192,11 +192,21 @@ OvsCtEntryCreate(PNET_BUFFER_LIST curNbl,
>              }
>
>              state |= OVS_CS_F_NEW;
> +            POVS_CT_ENTRY parentEntry = NULL;
> +            parentEntry = OvsCtRelatedLookup(ctx->key, currentTime);
> +            if (parentEntry != NULL) {
> +                state |= OVS_CS_F_RELATED;
> +            }
> +
>              if (commit) {
>                  entry = OvsConntrackCreateTcpEntry(tcp, curNbl,
> currentTime);
>                  if (!entry) {
>                      return NULL;
>                  }
> +                /* If this is related entry, then update parent */
> +                if (parentEntry != NULL) {
> +                    entry->parent = parentEntry;
> +                }
>                  OvsCtAddEntry(entry, ctx, currentTime);
>              }
>
> @@ -492,6 +502,13 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
>      return NDIS_STATUS_SUCCESS;
>  }
>
> +static __inline BOOLEAN
> +OvsDetectFtpPacket(OvsFlowKey *key) {
> +    return (key->ipKey.nwProto == IPPROTO_TCP &&
> +            (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP ||
> +            ntohs(key->ipKey.l4.tpSrc) == IPPORT_FTP));
> +}
> +
>  /*
>   *-----------------------------------------------------------
> -----------------
>   * OvsProcessConntrackEntry
> @@ -542,6 +559,21 @@ OvsProcessConntrackEntry(PNET_BUFFER_LIST curNbl,
>              break;
>          }
>      }
> +
> +    if (key->ipKey.nwProto == IPPROTO_TCP && entry) {
> +        /* Update the related bit if there is a parent */
> +        if (entry->parent) {
> +            state |= OVS_CS_F_RELATED;
> +        } else {
> +            POVS_CT_ENTRY parentEntry;
> +            parentEntry = OvsCtRelatedLookup(ctx->key, currentTime);
> +            if (parentEntry != NULL) {
> +                entry->parent = parentEntry;
> +                state |= OVS_CS_F_RELATED;
> +            }
> +        }
> +    }
> +
>      /* Copy mark and label from entry into flowKey. If actions specify
>         different mark and label, update the flowKey. */
>      if (entry != NULL) {
> @@ -592,7 +624,8 @@ OvsCtExecute_(PNET_BUFFER_LIST curNbl,
>                BOOLEAN commit,
>                UINT16 zone,
>                MD_MARK *mark,
> -              MD_LABELS *labels)
> +              MD_LABELS *labels,
> +              PCHAR helper)
>  {
>      NDIS_STATUS status = NDIS_STATUS_SUCCESS;
>      POVS_CT_ENTRY entry = NULL;
> @@ -629,6 +662,17 @@ OvsCtExecute_(PNET_BUFFER_LIST curNbl,
>          OvsConntrackSetLabels(key, entry, &labels->value, &labels->mask);
>      }
>
> +    if (entry && OvsDetectFtpPacket(key)) {
> +        /* FTP parser will always be loaded */
> +        UNREFERENCED_PARAMETER(helper);
> +
> +        status = OvsCtHandleFtp(curNbl, key, layers, currentTime, entry,
> +                                (ntohs(key->ipKey.l4.tpDst) ==
> IPPORT_FTP));
> +        if (status != NDIS_STATUS_SUCCESS) {
> +            OVS_LOG_ERROR("Error while parsing the FTP packet");
> +        }
> +    }
> +
>      NdisReleaseRWLock(ovsConntrackLockObj, &lockState);
>
>      return status;
> @@ -651,6 +695,8 @@ OvsExecuteConntrackAction(PNET_BUFFER_LIST curNbl,
>      UINT16 zone = 0;
>      MD_MARK *mark = NULL;
>      MD_LABELS *labels = NULL;
> +    PCHAR helper = NULL;
> +
>      NDIS_STATUS status;
>
>      status = OvsDetectCtPacket(key);
> @@ -674,9 +720,20 @@ OvsExecuteConntrackAction(PNET_BUFFER_LIST curNbl,
>      if (ctAttr) {
>          labels = NlAttrGet(ctAttr);
>      }
> +    ctAttr = NlAttrFindNested(a, OVS_CT_ATTR_HELPER);
> +    if (ctAttr) {
> +        helper = NlAttrGetString(ctAttr);
> +        if (helper == NULL) {
> +            return NDIS_STATUS_INVALID_PARAMETER;
> +        }
> +        if (strcmp("ftp", helper) != 0) {
> +            /* Only support FTP */
> +            return NDIS_STATUS_NOT_SUPPORTED;
> +        }
> +    }
>
>      status = OvsCtExecute_(curNbl, key, layers,
> -                           commit, zone, mark, labels);
> +                           commit, zone, mark, labels, helper);
>      return status;
>  }
>
> diff --git a/datapath-windows/ovsext/Conntrack.h
> b/datapath-windows/ovsext/Conntrack.h
> index 7f1ec6f..af99885 100644
> --- a/datapath-windows/ovsext/Conntrack.h
> +++ b/datapath-windows/ovsext/Conntrack.h
> @@ -85,6 +85,7 @@ typedef struct OVS_CT_ENTRY {
>      UINT32      mark;
>      UINT64      timestampStart;
>      struct ovs_key_ct_labels labels;
> +    PVOID       parent; /* Points to main connection */
>  } OVS_CT_ENTRY, *POVS_CT_ENTRY;
>
>  typedef struct OVS_CT_REL_ENTRY {
> @@ -200,4 +201,11 @@ NDIS_STATUS OvsCtRelatedEntryCreate(UINT8 ipProto,
>                                      POVS_CT_ENTRY parent);
>  POVS_CT_ENTRY OvsCtRelatedLookup(OVS_CT_KEY key, UINT64 currentTime);
>
> +NDIS_STATUS OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
> +                           OvsFlowKey *key,
> +                           OVS_PACKET_HDR_INFO *layers,
> +                           UINT64 currentTime,
> +                           POVS_CT_ENTRY entry,
> +                           BOOLEAN request);
> +
>  #endif /* __OVS_CONNTRACK_H_ */
> diff --git a/datapath-windows/ovsext/Netlink/Netlink.c
> b/datapath-windows/ovsext/Netlink/Netlink.c
> index 2432205..a63f066 100644
> --- a/datapath-windows/ovsext/Netlink/Netlink.c
> +++ b/datapath-windows/ovsext/Netlink/Netlink.c
> @@ -992,6 +992,22 @@ NlAttrGetU64(const PNL_ATTR nla)
>
>  /*
>   * ------------------------------------------------------------
> ---------------
> + * Returns the string value in 'nla''s payload.
> + * Returns NULL if it is not a proper '\0' terminated string.
> + * ------------------------------------------------------------
> ---------------
> + */
> +PCHAR
> +NlAttrGetString(const PNL_ATTR nla)
> +{
> +    ASSERT(nla->nlaLen >= NLA_HDRLEN);
> +    if (!memchr(NlAttrGet(nla), '\0', nla->nlaLen - NLA_HDRLEN)) {
> +        return NULL;
> +    }
> +    return NlAttrGet(nla);
> +}
> +
> +/*
> + * ------------------------------------------------------------
> ---------------
>   * Validate the netlink attribute against the policy
>   * ------------------------------------------------------------
> ---------------
>   */
> diff --git a/datapath-windows/ovsext/Netlink/Netlink.h
> b/datapath-windows/ovsext/Netlink/Netlink.h
> index 363f575..964c0e5 100644
> --- a/datapath-windows/ovsext/Netlink/Netlink.h
> +++ b/datapath-windows/ovsext/Netlink/Netlink.h
> @@ -138,6 +138,7 @@ UINT8 NlAttrGetU8(const PNL_ATTR nla);
>  UINT16 NlAttrGetU16(const PNL_ATTR nla);
>  UINT32 NlAttrGetU32(const PNL_ATTR nla);
>  UINT64 NlAttrGetU64(const PNL_ATTR nla);
> +PCHAR NlAttrGetString(const PNL_ATTR nla);
>  const PNL_ATTR NlAttrFind__(const PNL_ATTR attrs,
>                              UINT32 size, UINT16 type);
>  const PNL_ATTR NlAttrFindNested(const PNL_ATTR nla,
> diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/
> Switch.c
> index db023e9..138a656 100644
> --- a/datapath-windows/ovsext/Switch.c
> +++ b/datapath-windows/ovsext/Switch.c
> @@ -225,6 +225,13 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
>          goto create_switch_done;
>      }
>
> +    status = OvsInitCtRelated(switchContext);
> +    if (status != STATUS_SUCCESS) {
> +        OvsUninitSwitchContext(switchContext);
> +        OVS_LOG_ERROR("Exit: Failed to initialize Connection tracking");
> +        goto create_switch_done;
> +    }
> +
>      *switchContextOut = switchContext;
>
>  create_switch_done:
> @@ -257,6 +264,7 @@ OvsExtDetach(NDIS_HANDLE filterModuleContext)
>      OvsCleanupIpHelper();
>      OvsCleanupSttDefragmentation();
>      OvsCleanupConntrack();
> +    OvsCleanupCtRelated();
>      /* This completes the cleanup, and a new attach can be handled now. */
>
>      OVS_LOG_TRACE("Exit: OvsDetach Successfully");
> --
> 2.9.0.windows.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox

Patch

diff --git a/datapath-windows/ovsext/Conntrack.c b/datapath-windows/ovsext/Conntrack.c
index 70c32a4..53d2cf9 100644
--- a/datapath-windows/ovsext/Conntrack.c
+++ b/datapath-windows/ovsext/Conntrack.c
@@ -192,11 +192,21 @@  OvsCtEntryCreate(PNET_BUFFER_LIST curNbl,
             }
 
             state |= OVS_CS_F_NEW;
+            POVS_CT_ENTRY parentEntry = NULL;
+            parentEntry = OvsCtRelatedLookup(ctx->key, currentTime);
+            if (parentEntry != NULL) {
+                state |= OVS_CS_F_RELATED;
+            }
+
             if (commit) {
                 entry = OvsConntrackCreateTcpEntry(tcp, curNbl, currentTime);
                 if (!entry) {
                     return NULL;
                 }
+                /* If this is related entry, then update parent */
+                if (parentEntry != NULL) {
+                    entry->parent = parentEntry;
+                }
                 OvsCtAddEntry(entry, ctx, currentTime);
             }
 
@@ -492,6 +502,13 @@  OvsCtSetupLookupCtx(OvsFlowKey *flowKey,
     return NDIS_STATUS_SUCCESS;
 }
 
+static __inline BOOLEAN
+OvsDetectFtpPacket(OvsFlowKey *key) {
+    return (key->ipKey.nwProto == IPPROTO_TCP &&
+            (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP ||
+            ntohs(key->ipKey.l4.tpSrc) == IPPORT_FTP));
+}
+
 /*
  *----------------------------------------------------------------------------
  * OvsProcessConntrackEntry
@@ -542,6 +559,21 @@  OvsProcessConntrackEntry(PNET_BUFFER_LIST curNbl,
             break;
         }
     }
+
+    if (key->ipKey.nwProto == IPPROTO_TCP && entry) {
+        /* Update the related bit if there is a parent */
+        if (entry->parent) {
+            state |= OVS_CS_F_RELATED;
+        } else {
+            POVS_CT_ENTRY parentEntry;
+            parentEntry = OvsCtRelatedLookup(ctx->key, currentTime);
+            if (parentEntry != NULL) {
+                entry->parent = parentEntry;
+                state |= OVS_CS_F_RELATED;
+            }
+        }
+    }
+
     /* Copy mark and label from entry into flowKey. If actions specify
        different mark and label, update the flowKey. */
     if (entry != NULL) {
@@ -592,7 +624,8 @@  OvsCtExecute_(PNET_BUFFER_LIST curNbl,
               BOOLEAN commit,
               UINT16 zone,
               MD_MARK *mark,
-              MD_LABELS *labels)
+              MD_LABELS *labels,
+              PCHAR helper)
 {
     NDIS_STATUS status = NDIS_STATUS_SUCCESS;
     POVS_CT_ENTRY entry = NULL;
@@ -629,6 +662,17 @@  OvsCtExecute_(PNET_BUFFER_LIST curNbl,
         OvsConntrackSetLabels(key, entry, &labels->value, &labels->mask);
     }
 
+    if (entry && OvsDetectFtpPacket(key)) {
+        /* FTP parser will always be loaded */
+        UNREFERENCED_PARAMETER(helper);
+
+        status = OvsCtHandleFtp(curNbl, key, layers, currentTime, entry,
+                                (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP));
+        if (status != NDIS_STATUS_SUCCESS) {
+            OVS_LOG_ERROR("Error while parsing the FTP packet");
+        }
+    }
+
     NdisReleaseRWLock(ovsConntrackLockObj, &lockState);
 
     return status;
@@ -651,6 +695,8 @@  OvsExecuteConntrackAction(PNET_BUFFER_LIST curNbl,
     UINT16 zone = 0;
     MD_MARK *mark = NULL;
     MD_LABELS *labels = NULL;
+    PCHAR helper = NULL;
+
     NDIS_STATUS status;
 
     status = OvsDetectCtPacket(key);
@@ -674,9 +720,20 @@  OvsExecuteConntrackAction(PNET_BUFFER_LIST curNbl,
     if (ctAttr) {
         labels = NlAttrGet(ctAttr);
     }
+    ctAttr = NlAttrFindNested(a, OVS_CT_ATTR_HELPER);
+    if (ctAttr) {
+        helper = NlAttrGetString(ctAttr);
+        if (helper == NULL) {
+            return NDIS_STATUS_INVALID_PARAMETER;
+        }
+        if (strcmp("ftp", helper) != 0) {
+            /* Only support FTP */
+            return NDIS_STATUS_NOT_SUPPORTED;
+        }
+    }
 
     status = OvsCtExecute_(curNbl, key, layers,
-                           commit, zone, mark, labels);
+                           commit, zone, mark, labels, helper);
     return status;
 }
 
diff --git a/datapath-windows/ovsext/Conntrack.h b/datapath-windows/ovsext/Conntrack.h
index 7f1ec6f..af99885 100644
--- a/datapath-windows/ovsext/Conntrack.h
+++ b/datapath-windows/ovsext/Conntrack.h
@@ -85,6 +85,7 @@  typedef struct OVS_CT_ENTRY {
     UINT32      mark;
     UINT64      timestampStart;
     struct ovs_key_ct_labels labels;
+    PVOID       parent; /* Points to main connection */
 } OVS_CT_ENTRY, *POVS_CT_ENTRY;
 
 typedef struct OVS_CT_REL_ENTRY {
@@ -200,4 +201,11 @@  NDIS_STATUS OvsCtRelatedEntryCreate(UINT8 ipProto,
                                     POVS_CT_ENTRY parent);
 POVS_CT_ENTRY OvsCtRelatedLookup(OVS_CT_KEY key, UINT64 currentTime);
 
+NDIS_STATUS OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
+                           OvsFlowKey *key,
+                           OVS_PACKET_HDR_INFO *layers,
+                           UINT64 currentTime,
+                           POVS_CT_ENTRY entry,
+                           BOOLEAN request);
+
 #endif /* __OVS_CONNTRACK_H_ */
diff --git a/datapath-windows/ovsext/Netlink/Netlink.c b/datapath-windows/ovsext/Netlink/Netlink.c
index 2432205..a63f066 100644
--- a/datapath-windows/ovsext/Netlink/Netlink.c
+++ b/datapath-windows/ovsext/Netlink/Netlink.c
@@ -992,6 +992,22 @@  NlAttrGetU64(const PNL_ATTR nla)
 
 /*
  * ---------------------------------------------------------------------------
+ * Returns the string value in 'nla''s payload.
+ * Returns NULL if it is not a proper '\0' terminated string.
+ * ---------------------------------------------------------------------------
+ */
+PCHAR
+NlAttrGetString(const PNL_ATTR nla)
+{
+    ASSERT(nla->nlaLen >= NLA_HDRLEN);
+    if (!memchr(NlAttrGet(nla), '\0', nla->nlaLen - NLA_HDRLEN)) {
+        return NULL;
+    }
+    return NlAttrGet(nla);
+}
+
+/*
+ * ---------------------------------------------------------------------------
  * Validate the netlink attribute against the policy
  * ---------------------------------------------------------------------------
  */
diff --git a/datapath-windows/ovsext/Netlink/Netlink.h b/datapath-windows/ovsext/Netlink/Netlink.h
index 363f575..964c0e5 100644
--- a/datapath-windows/ovsext/Netlink/Netlink.h
+++ b/datapath-windows/ovsext/Netlink/Netlink.h
@@ -138,6 +138,7 @@  UINT8 NlAttrGetU8(const PNL_ATTR nla);
 UINT16 NlAttrGetU16(const PNL_ATTR nla);
 UINT32 NlAttrGetU32(const PNL_ATTR nla);
 UINT64 NlAttrGetU64(const PNL_ATTR nla);
+PCHAR NlAttrGetString(const PNL_ATTR nla);
 const PNL_ATTR NlAttrFind__(const PNL_ATTR attrs,
                             UINT32 size, UINT16 type);
 const PNL_ATTR NlAttrFindNested(const PNL_ATTR nla,
diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c
index db023e9..138a656 100644
--- a/datapath-windows/ovsext/Switch.c
+++ b/datapath-windows/ovsext/Switch.c
@@ -225,6 +225,13 @@  OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
         goto create_switch_done;
     }
 
+    status = OvsInitCtRelated(switchContext);
+    if (status != STATUS_SUCCESS) {
+        OvsUninitSwitchContext(switchContext);
+        OVS_LOG_ERROR("Exit: Failed to initialize Connection tracking");
+        goto create_switch_done;
+    }
+
     *switchContextOut = switchContext;
 
 create_switch_done:
@@ -257,6 +264,7 @@  OvsExtDetach(NDIS_HANDLE filterModuleContext)
     OvsCleanupIpHelper();
     OvsCleanupSttDefragmentation();
     OvsCleanupConntrack();
+    OvsCleanupCtRelated();
     /* This completes the cleanup, and a new attach can be handled now. */
 
     OVS_LOG_TRACE("Exit: OvsDetach Successfully");