[ovs-dev] [PATCH 3/4] conntrack: refactoring alg handle code path

hepeng.0320 hepeng.0320 at bytedance.com
Sun Nov 29 03:32:54 UTC 2020


From: hepeng <hepeng.0320 at bytedance.com>

Just like the previous patch, split the handle_ftp_ctl into
handle_ftp_interest and handle_ftp_other, since we can infer
which one to call from the called positions.

We also introduce a simple framework which unifies the normal
conn handle path and alg conn handle path by using two hooks:
*before_conn_update_hook* and *after_conn_update_hook*.

Signed-off-by: Peng He <hepeng.0320 at bytedance.com>
---
 lib/conntrack-private.h |  16 +-
 lib/conntrack.c         | 477 ++++++++++++++++++++++++----------------
 2 files changed, 307 insertions(+), 186 deletions(-)

diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h
index 6bec43d3f..2aa828674 100644
--- a/lib/conntrack-private.h
+++ b/lib/conntrack-private.h
@@ -83,7 +83,22 @@ struct alg_exp_node {
     bool nat_rpl_dst;
 };
 
+enum ct_alg_ctl_type {
+    CT_ALG_CTL_NONE,
+    CT_ALG_CTL_FTP,
+    CT_ALG_CTL_TFTP,
+    /* SIP is not enabled through Openflow and presently only used as
+     * an example of an alg that allows a wildcard src ip. */
+    CT_ALG_CTL_SIP,
+    CT_ALG_CTL_MAX,
+};
+
 #define CONN_FLAG_NAT_MASK 0xf
+#define CONN_FLAG_CTL_FTP  (CT_ALG_CTL_FTP  << 4)
+#define CONN_FLAG_CTL_TFTP (CT_ALG_CTL_TFTP << 4)
+#define CONN_FLAG_CTL_SIP  (CT_ALG_CTL_SIP  << 4)
+/* currently only 3 algs supported */
+#define CONN_FLAG_ALG_MASK 0x70
 
 struct conn_dir {
     struct cmap_node cm_node;
@@ -99,7 +114,6 @@ struct conn {
     struct conn_key parent_key; /* Only used for orig_tuple support. */
     struct ovs_list exp_node;
     uint64_t conn_flags;
-    char *alg;
 
     /* Mutable data. */
     struct ovs_mutex lock; /* Guards all mutable fields. */
diff --git a/lib/conntrack.c b/lib/conntrack.c
index a22252a63..fffc617fb 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -69,15 +69,6 @@ enum ct_alg_mode {
     CT_TFTP_MODE,
 };
 
-enum ct_alg_ctl_type {
-    CT_ALG_CTL_NONE,
-    CT_ALG_CTL_FTP,
-    CT_ALG_CTL_TFTP,
-    /* SIP is not enabled through Openflow and presently only used as
-     * an example of an alg that allows a wildcard src ip. */
-    CT_ALG_CTL_SIP,
-};
-
 struct zone_limit {
     struct hmap_node node;
     struct conntrack_zone_limit czl;
@@ -153,30 +144,145 @@ static struct ct_l4_proto *l4_protos[] = {
 };
 
 static void
-handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
-               struct dp_packet *pkt, struct conn *ec, long long now,
-               enum ftp_ctl_pkt ftp_ctl, bool nat);
-
+handle_ftp_ctl_other(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                     struct dp_packet *pkt, struct conn *ec, long long now,
+                     bool nat);
+static void
+handle_ftp_ctl_interest(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                        struct dp_packet *pkt, struct conn *ec, long long now,
+                        bool nat);
 static void
 handle_tftp_ctl(struct conntrack *ct,
-                const struct conn_lookup_ctx *ctx OVS_UNUSED,
-                struct dp_packet *pkt, struct conn *conn_for_expectation,
-                long long now OVS_UNUSED, enum ftp_ctl_pkt ftp_ctl OVS_UNUSED,
-                bool nat OVS_UNUSED);
+                 const struct conn_lookup_ctx *ctx OVS_UNUSED,
+                 struct dp_packet *pkt, struct conn *conn_for_expectation,
+                 long long now OVS_UNUSED, bool nat OVS_UNUSED);
+
 
 typedef void (*alg_helper)(struct conntrack *ct,
                            const struct conn_lookup_ctx *ctx,
                            struct dp_packet *pkt,
                            struct conn *conn_for_expectation,
-                           long long now, enum ftp_ctl_pkt ftp_ctl,
-                           bool nat);
+                           long long now, bool nat);
+
+typedef void (*before_helper)(struct conntrack *ct,
+                              const struct conn_lookup_ctx *ctx,
+                              struct dp_packet *pkt,
+                              struct conn *conn_for_expectation,
+                              long long now, bool nat);
+
+
+typedef void (*after_helper)(struct conntrack *ct,
+                             const struct conn_lookup_ctx *ctx,
+                             struct dp_packet *pkt,
+                             struct conn *conn_for_expectation,
+                             long long now, bool nat, bool create_new_conn);
+
 
-static alg_helper alg_helpers[] = {
-    [CT_ALG_CTL_NONE] = NULL,
-    [CT_ALG_CTL_FTP] = handle_ftp_ctl,
-    [CT_ALG_CTL_TFTP] = handle_tftp_ctl,
+struct alg_helper_hook {
+    before_helper before_conn_update_hook;
+    after_helper  after_conn_update_hook;
+    alg_helper alg_helper_hook;
 };
 
+static void ftp_ctl_before_hook(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                                struct dp_packet *pkt, struct conn *ec, long long now,
+                                bool nat)
+{
+    enum ftp_ctl_pkt pkt_type = detect_ftp_ctl_type(ctx, pkt);
+    if (pkt_type == CT_FTP_CTL_INTEREST)
+        return;
+
+    ovs_mutex_lock(&ec->lock);
+    if (ctx->reply != ec->seq_skew_dir) {
+        handle_ftp_ctl_other(ct, ctx, pkt, ec, now, nat);
+    }
+    ovs_mutex_unlock(&ec->lock);
+}
+
+static void ftp_ctl_after_hook(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                               struct dp_packet *pkt, struct conn *ec, long long now,
+                               bool nat, bool create_new_conn)
+{
+    enum ftp_ctl_pkt pkt_type = detect_ftp_ctl_type(ctx, pkt);
+    if (pkt_type == CT_FTP_CTL_INTEREST)
+        return;
+
+    if (create_new_conn == false) {
+        ovs_mutex_lock(&ec->lock);
+        if (ctx->reply == ec->seq_skew_dir) {
+            handle_ftp_ctl_other(ct, ctx, pkt, ec, now, nat);
+        }
+        ovs_mutex_unlock(&ec->lock);
+    }
+}
+
+static void handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                           struct dp_packet *pkt, struct conn *ec, long long now,
+                           bool nat)
+{
+    if (detect_ftp_ctl_type(ctx, pkt) != CT_FTP_CTL_INTEREST)
+        return;
+
+    ovs_mutex_lock(&ec->lock);
+    handle_ftp_ctl_interest(ct, ctx, pkt, ec, now, nat);
+    ovs_mutex_unlock(&ec->lock);
+}
+
+static struct alg_helper_hook alg_helper_hooks[] = {
+    [CT_ALG_CTL_NONE] = { .before_conn_update_hook = NULL, \
+                          .after_conn_update_hook = NULL, \
+                          .alg_helper_hook = NULL },
+    [CT_ALG_CTL_FTP]  = { .before_conn_update_hook = ftp_ctl_before_hook, \
+                          .after_conn_update_hook = ftp_ctl_after_hook, \
+                          .alg_helper_hook = handle_ftp_ctl },
+    [CT_ALG_CTL_TFTP] = { .before_conn_update_hook = NULL, \
+                          .after_conn_update_hook = NULL, \
+                          .alg_helper_hook = handle_tftp_ctl },
+};
+
+static void
+conn_update_before_hook(enum ct_alg_ctl_type type, struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                        struct dp_packet *pkt, struct conn *ec, long long now,
+                        bool nat)
+{
+    if (OVS_LIKELY(type == CT_ALG_CTL_NONE)) {
+        return;
+    }
+
+    if (alg_helper_hooks[type].before_conn_update_hook)
+        alg_helper_hooks[type].before_conn_update_hook(ct, ctx, pkt, ec, now, nat);
+}
+
+static void
+conn_update_after_hook(enum ct_alg_ctl_type type, struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                       struct dp_packet *pkt, struct conn *ec, long long now,
+                       bool nat, bool create_new_conn)
+{
+    if (OVS_LIKELY(type == CT_ALG_CTL_NONE)) {
+        return;
+    }
+
+    if (alg_helper_hooks[type].after_conn_update_hook)
+        alg_helper_hooks[type].after_conn_update_hook(ct, ctx, pkt, ec, now, nat, create_new_conn);
+}
+
+static void
+handle_alg_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+               struct dp_packet *pkt, enum ct_alg_ctl_type ct_alg_ctl,
+               struct conn *conn, long long now, bool nat)
+{
+    /* ALG control packet handling with expectation creation. */
+    if (OVS_LIKELY(!(conn && conn->conn_flags & CONN_FLAG_ALG_MASK))) {
+        return;
+    }
+
+    if (alg_helper_hooks[ct_alg_ctl].alg_helper_hook && conn) {
+        alg_helper_hooks[ct_alg_ctl].alg_helper_hook(ct, ctx, pkt, conn, now, nat);
+    }
+}
+
+
+
 /* The maximum TCP or UDP port number. */
 #define CT_MAX_L4_PORT 65535
 /* String buffer used for parsing FTP string messages.
@@ -433,7 +539,7 @@ static void
 conn_clean_cmn(struct conntrack *ct, struct conn *conn)
     OVS_REQUIRES(ct->ct_lock)
 {
-    if (conn->alg) {
+    if (conn->conn_flags & CONN_FLAG_ALG_MASK) {
         expectation_clean(ct, &conn->key);
     }
 
@@ -634,12 +740,6 @@ get_ip_proto(const struct dp_packet *pkt)
     return ip_proto;
 }
 
-static bool
-is_ftp_ctl(const enum ct_alg_ctl_type ct_alg_ctl)
-{
-    return ct_alg_ctl == CT_ALG_CTL_FTP;
-}
-
 static enum ct_alg_ctl_type
 get_alg_ctl_type(const struct dp_packet *pkt, ovs_be16 tp_src, ovs_be16 tp_dst,
                  const char *helper)
@@ -649,32 +749,59 @@ get_alg_ctl_type(const struct dp_packet *pkt, ovs_be16 tp_src, ovs_be16 tp_dst,
      * the external dependency. */
     enum { CT_IPPORT_FTP = 21 };
     enum { CT_IPPORT_TFTP = 69 };
-    uint8_t ip_proto = get_ip_proto(pkt);
-    struct udp_header *uh = dp_packet_l4(pkt);
-    struct tcp_header *th = dp_packet_l4(pkt);
     ovs_be16 ftp_src_port = htons(CT_IPPORT_FTP);
     ovs_be16 ftp_dst_port = htons(CT_IPPORT_FTP);
     ovs_be16 tftp_dst_port = htons(CT_IPPORT_TFTP);
 
-    if (OVS_UNLIKELY(tp_dst)) {
-        if (helper && !strncmp(helper, "ftp", strlen("ftp"))) {
+    if (OVS_UNLIKELY(tp_dst && helper)) {
+        if (!strncmp(helper, "ftp", strlen("ftp"))) {
             ftp_dst_port = tp_dst;
-        } else if (helper && !strncmp(helper, "tftp", strlen("tftp"))) {
+        } else if (!strncmp(helper, "tftp", strlen("tftp"))) {
             tftp_dst_port = tp_dst;
         }
-    } else if (OVS_UNLIKELY(tp_src)) {
-        if (helper && !strncmp(helper, "ftp", strlen("ftp"))) {
+    } else if (OVS_UNLIKELY(tp_src && helper)) {
+        if (!strncmp(helper, "ftp", strlen("ftp"))) {
             ftp_src_port = tp_src;
         }
     }
 
-    if (ip_proto == IPPROTO_UDP && uh->udp_dst == tftp_dst_port) {
-        return CT_ALG_CTL_TFTP;
-    } else if (ip_proto == IPPROTO_TCP &&
-               (th->tcp_src == ftp_src_port || th->tcp_dst == ftp_dst_port)) {
-        return CT_ALG_CTL_FTP;
+
+    enum ct_alg_ctl_type type = CT_ALG_CTL_NONE;
+    if (helper) {
+        enum ct_alg_ctl_type helper_type = CT_ALG_CTL_NONE;
+
+        if (!strncmp(helper, "ftp", strlen("ftp"))) {
+            helper_type = CT_ALG_CTL_FTP;
+        } else if (!strncmp(helper, "tftp", strlen("tftp"))) {
+            helper_type = CT_ALG_CTL_TFTP;
+        }
+
+        uint8_t ip_proto = get_ip_proto(pkt);
+        struct udp_header *uh = dp_packet_l4(pkt);
+        struct tcp_header *th = dp_packet_l4(pkt);
+        if (ip_proto == IPPROTO_UDP && uh->udp_dst == tftp_dst_port) {
+            type = CT_ALG_CTL_TFTP;
+        } else if (ip_proto == IPPROTO_TCP &&
+                (th->tcp_src == ftp_src_port || th->tcp_dst == ftp_dst_port)) {
+            type = CT_ALG_CTL_FTP;
+        }
+
+        if (type == CT_ALG_CTL_NONE)
+            type = helper_type;
+        else if (type != helper_type)
+            type = CT_ALG_CTL_NONE;
+        /*
+        this case helper_type is not NONE, however type is not consisted with helper_type
+        we should set type = CT_ALG_NONE, this means the belowing:
+
+        else if (type != helper_type)
+            type = CT_ALG_CTL_NONE
+        else
+            in this case type == helper_type, return type
+
+        */
     }
-    return CT_ALG_CTL_NONE;
+    return type;
 }
 
 static bool
@@ -686,20 +813,6 @@ alg_src_ip_wc(enum ct_alg_ctl_type alg_ctl_type)
     return false;
 }
 
-static void
-handle_alg_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
-               struct dp_packet *pkt, enum ct_alg_ctl_type ct_alg_ctl,
-               struct conn *conn, long long now, bool nat)
-{
-    /* ALG control packet handling with expectation creation. */
-    if (OVS_UNLIKELY(alg_helpers[ct_alg_ctl] && conn && conn->alg)) {
-        ovs_mutex_lock(&conn->lock);
-        alg_helpers[ct_alg_ctl](ct, ctx, pkt, conn, now, CT_FTP_CTL_INTEREST,
-                                nat);
-        ovs_mutex_unlock(&conn->lock);
-    }
-}
-
 static void
 pat_packet_src(struct dp_packet *pkt, const struct conn *conn)
 {
@@ -970,31 +1083,32 @@ conn_seq_skew_set(struct conntrack *ct, const struct conn *conn_in,
     }
 }
 
-static bool
-ct_verify_helper(const char *helper, enum ct_alg_ctl_type ct_alg_ctl)
+static void
+ct_set_alg(struct conn *conn , enum ct_alg_ctl_type ct_alg_ctl)
 {
-    if (ct_alg_ctl == CT_ALG_CTL_NONE) {
-        return true;
-    } else if (helper) {
-        if ((ct_alg_ctl == CT_ALG_CTL_FTP) &&
-             !strncmp(helper, "ftp", strlen("ftp"))) {
-            return true;
-        } else if ((ct_alg_ctl == CT_ALG_CTL_TFTP) &&
-                   !strncmp(helper, "tftp", strlen("tftp"))) {
-            return true;
-        } else {
-            return false;
-        }
-    } else {
-        return false;
+    if (ct_alg_ctl == CT_ALG_CTL_FTP) {
+        conn->conn_flags |= CONN_FLAG_CTL_FTP;
+    } else if (ct_alg_ctl == CT_ALG_CTL_TFTP) {
+        conn->conn_flags |= CONN_FLAG_CTL_TFTP;
     }
 }
 
+static enum ct_alg_ctl_type ct_get_alg(struct conn *conn)
+{
+    if (OVS_UNLIKELY(conn->conn_flags & CONN_FLAG_CTL_FTP))
+        return CT_ALG_CTL_FTP;
+
+    if (OVS_UNLIKELY(conn->conn_flags & CONN_FLAG_CTL_TFTP))
+        return CT_ALG_CTL_TFTP;
+
+    return CT_ALG_CTL_NONE;
+}
+
 static struct conn *
 conn_not_found(struct conntrack *ct, struct dp_packet *pkt,
                struct conn_lookup_ctx *ctx, bool commit, long long now,
                const struct nat_action_info_t *nat_action_info,
-               const char *helper, const struct alg_exp_node *alg_exp,
+               const struct alg_exp_node *alg_exp,
                enum ct_alg_ctl_type ct_alg_ctl, uint32_t tp_id)
     OVS_REQUIRES(ct->ct_lock)
 {
@@ -1032,9 +1146,7 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt,
         nc->orig.orig = true;
         nc->rev.orig = !nc->orig.orig;
 
-        if (ct_verify_helper(helper, ct_alg_ctl)) {
-            nc->alg = nullable_xstrdup(helper);
-        }
+        ct_set_alg(nc, ct_alg_ctl);
 
         if (alg_exp) {
             nc->alg_related = true;
@@ -1218,39 +1330,6 @@ check_orig_tuple(struct conntrack *ct, struct dp_packet *pkt,
     return *conn ? true : false;
 }
 
-static bool
-conn_update_state_alg(struct conntrack *ct, struct dp_packet *pkt,
-                      struct conn_lookup_ctx *ctx, struct conn *conn,
-                      const struct nat_action_info_t *nat_action_info,
-                      enum ct_alg_ctl_type ct_alg_ctl, long long now,
-                      bool *create_new_conn)
-{
-    if (is_ftp_ctl(ct_alg_ctl)) {
-        /* Keep sequence tracking in sync with the source of the
-         * sequence skew. */
-        ovs_mutex_lock(&conn->lock);
-        if (ctx->reply != conn->seq_skew_dir) {
-            handle_ftp_ctl(ct, ctx, pkt, conn, now, CT_FTP_CTL_OTHER,
-                           !!nat_action_info);
-            /* conn_update_state locks for unrelated fields, so unlock. */
-            ovs_mutex_unlock(&conn->lock);
-            *create_new_conn = conn_update_state(ct, pkt, ctx, conn, now);
-        } else {
-            /* conn_update_state locks for unrelated fields, so unlock. */
-            ovs_mutex_unlock(&conn->lock);
-            *create_new_conn = conn_update_state(ct, pkt, ctx, conn, now);
-            ovs_mutex_lock(&conn->lock);
-            if (*create_new_conn == false) {
-                handle_ftp_ctl(ct, ctx, pkt, conn, now, CT_FTP_CTL_OTHER,
-                               !!nat_action_info);
-            }
-            ovs_mutex_unlock(&conn->lock);
-        }
-        return true;
-    }
-    return false;
-}
-
 static void
 set_cached_conn(const struct nat_action_info_t *nat_action_info,
                 const struct conn_lookup_ctx *ctx, struct conn *conn,
@@ -1319,20 +1398,16 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,
         conn = NULL;
     }
 
-    enum ct_alg_ctl_type ct_alg_ctl = get_alg_ctl_type(pkt, tp_src, tp_dst,
-                                                       helper);
+    enum ct_alg_ctl_type ct_alg_ctl = CT_ALG_CTL_NONE;
 
     if (OVS_LIKELY(conn)) {
-        if (OVS_LIKELY(!conn_update_state_alg(ct, pkt, ctx, conn,
-                                              nat_action_info,
-                                              ct_alg_ctl, now,
-                                              &create_new_conn))) {
-            create_new_conn = conn_update_state(ct, pkt, ctx, conn, now);
-        }
+        ct_alg_ctl = ct_get_alg(conn);
+        conn_update_before_hook(ct_alg_ctl, ct, ctx, pkt, conn, now, !!nat_action_info);
+        create_new_conn = conn_update_state(ct, pkt, ctx, conn, now);
+        conn_update_after_hook(ct_alg_ctl, ct, ctx, pkt, conn, now, !!nat_action_info, create_new_conn);
         if (nat_action_info && !create_new_conn) {
             handle_nat(pkt, conn, zone, ctx->reply, ctx->icmp_related);
         }
-
     } else if (check_orig_tuple(ct, pkt, ctx, now, &conn, nat_action_info)) {
         create_new_conn = conn_update_state(ct, pkt, ctx, conn, now);
     } else {
@@ -1360,10 +1435,11 @@ process_one(struct conntrack *ct, struct dp_packet *pkt,
         }
         ovs_rwlock_unlock(&ct->resources_lock);
 
+        ct_alg_ctl = get_alg_ctl_type(pkt, tp_src, tp_dst, helper);
         ovs_mutex_lock(&ct->ct_lock);
         if (!conn_lookup(ct, &ctx->key, now, NULL, NULL)) {
             conn = conn_not_found(ct, pkt, ctx, commit, now, nat_action_info,
-                                  helper, alg_exp, ct_alg_ctl, tp_id);
+                                  alg_exp, ct_alg_ctl, tp_id);
         }
         ovs_mutex_unlock(&ct->ct_lock);
     }
@@ -1412,7 +1488,7 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch,
         if (OVS_UNLIKELY(packet->md.ct_state == CS_INVALID)) {
             write_ct_md(packet, zone, NULL, NULL, NULL);
         } else if (conn && conn->key.zone == zone && !force
-                   && !get_alg_ctl_type(packet, tp_src, tp_dst, helper)) {
+                   && !(conn->conn_flags & CONN_FLAG_ALG_MASK)) {
             process_one_fast(zone, setmark, setlabel, nat_action_info,
                              conn, packet);
         } else if (OVS_UNLIKELY(!conn_key_extract(ct, packet, dl_type, &ctx,
@@ -2368,7 +2444,6 @@ new_conn(struct conntrack *ct, struct dp_packet *pkt, struct conn_key *key,
 static void
 delete_conn_cmn(struct conn *conn)
 {
-    free(conn->alg);
     free(conn);
 }
 
@@ -2463,6 +2538,16 @@ tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone,
     key->zone = zone;
 }
 
+static char*
+ct_get_alg_helper(const struct conn *conn)
+{
+    if (conn->conn_flags & CONN_FLAG_CTL_FTP)
+        return xstrdup("ftp");
+    if (conn->conn_flags & CONN_FLAG_CTL_TFTP)
+        return xstrdup("tftp");
+    return NULL;
+}
+
 static void
 conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry,
                       long long now)
@@ -2487,9 +2572,9 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry,
 
     entry->timeout = (expiration > 0) ? expiration / 1000 : 0;
 
-    if (conn->alg) {
+    if (conn->conn_flags & CONN_FLAG_ALG_MASK) {
         /* Caller is responsible for freeing. */
-        entry->helper.name = xstrdup(conn->alg);
+        entry->helper.name = ct_get_alg_helper(conn);
     }
 }
 
@@ -3193,9 +3278,9 @@ adj_seqnum(ovs_16aligned_be32 *val, int32_t inc)
 }
 
 static void
-handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
-               struct dp_packet *pkt, struct conn *ec, long long now,
-               enum ftp_ctl_pkt ftp_ctl, bool nat)
+handle_ftp_ctl_interest(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
+                        struct dp_packet *pkt, struct conn *ec, long long now,
+                        bool nat)
 {
     struct ip_header *l3_hdr = dp_packet_l3(pkt);
     ovs_be32 v4_addr_rep = 0;
@@ -3205,67 +3290,61 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
     char *ftp_data_start;
     enum ct_alg_mode mode = CT_FTP_MODE_ACTIVE;
 
-    if (detect_ftp_ctl_type(ctx, pkt) != ftp_ctl) {
-        return;
-    }
-
     struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt);
     int64_t seq_skew = 0;
 
-    if (ftp_ctl == CT_FTP_CTL_INTEREST) {
-        enum ftp_ctl_pkt rc;
-        if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
-            rc = process_ftp_ctl_v6(ct, pkt, ec,
-                                    &v6_addr_rep, &ftp_data_start,
-                                    &addr_offset_from_ftp_data_start,
-                                    &addr_size, &mode);
-        } else {
-            rc = process_ftp_ctl_v4(ct, pkt, ec,
-                                    &v4_addr_rep, &ftp_data_start,
-                                    &addr_offset_from_ftp_data_start,
-                                    &addr_size);
-        }
-        if (rc == CT_FTP_CTL_INVALID) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
-            VLOG_WARN_RL(&rl, "Invalid FTP control packet format");
-            pkt->md.ct_state |= CS_TRACKED | CS_INVALID;
-            return;
-        } else if (rc == CT_FTP_CTL_INTEREST) {
-            uint16_t ip_len;
+    enum ftp_ctl_pkt rc;
+    if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
+        rc = process_ftp_ctl_v6(ct, pkt, ec,
+                &v6_addr_rep, &ftp_data_start,
+                &addr_offset_from_ftp_data_start,
+                &addr_size, &mode);
+    } else {
+        rc = process_ftp_ctl_v4(ct, pkt, ec,
+                &v4_addr_rep, &ftp_data_start,
+                &addr_offset_from_ftp_data_start,
+                &addr_size);
+    }
+    if (rc == CT_FTP_CTL_INVALID) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
+        VLOG_WARN_RL(&rl, "Invalid FTP control packet format");
+        pkt->md.ct_state |= CS_TRACKED | CS_INVALID;
+        return;
+    } else if (rc == CT_FTP_CTL_INTEREST) {
+        uint16_t ip_len;
 
-            if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
-                if (nat) {
-                    seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep,
-                                   ftp_data_start,
-                                   addr_offset_from_ftp_data_start,
-                                   addr_size, mode);
-                }
+        if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
+            if (nat) {
+                seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep,
+                        ftp_data_start,
+                        addr_offset_from_ftp_data_start,
+                        addr_size, mode);
+            }
 
-                if (seq_skew) {
-                    ip_len = ntohs(nh6->ip6_ctlun.ip6_un1.ip6_un1_plen) +
-                        seq_skew;
-                    nh6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ip_len);
-                }
-            } else {
-                if (nat) {
-                    seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep,
-                                   ftp_data_start,
-                                   addr_offset_from_ftp_data_start,
-                                   addr_size);
-                }
-                if (seq_skew) {
-                    ip_len = ntohs(l3_hdr->ip_tot_len) + seq_skew;
-                    if (!dp_packet_hwol_is_ipv4(pkt)) {
-                        l3_hdr->ip_csum = recalc_csum16(l3_hdr->ip_csum,
-                                                        l3_hdr->ip_tot_len,
-                                                        htons(ip_len));
-                    }
-                    l3_hdr->ip_tot_len = htons(ip_len);
-                }
+            if (seq_skew) {
+                ip_len = ntohs(nh6->ip6_ctlun.ip6_un1.ip6_un1_plen) +
+                    seq_skew;
+                nh6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ip_len);
             }
         } else {
-            OVS_NOT_REACHED();
+            if (nat) {
+                seq_skew = repl_ftp_v4_addr(pkt, v4_addr_rep,
+                        ftp_data_start,
+                        addr_offset_from_ftp_data_start,
+                        addr_size);
+            }
+            if (seq_skew) {
+                ip_len = ntohs(l3_hdr->ip_tot_len) + seq_skew;
+                if (!dp_packet_hwol_is_ipv4(pkt)) {
+                    l3_hdr->ip_csum = recalc_csum16(l3_hdr->ip_csum,
+                            l3_hdr->ip_tot_len,
+                            htons(ip_len));
+                }
+                l3_hdr->ip_tot_len = htons(ip_len);
+            }
         }
+    } else {
+        OVS_NOT_REACHED();
     }
 
     struct tcp_header *th = dp_packet_l4(pkt);
@@ -3280,11 +3359,11 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
     if (!dp_packet_hwol_tx_l4_checksum(pkt)) {
         if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
             th->tcp_csum = packet_csum_upperlayer6(nh6, th, ctx->key.nw_proto,
-                               dp_packet_l4_size(pkt));
+                    dp_packet_l4_size(pkt));
         } else {
             uint32_t tcp_csum = packet_csum_pseudoheader(l3_hdr);
             th->tcp_csum = csum_finish(
-                 csum_continue(tcp_csum, th, dp_packet_l4_size(pkt)));
+                    csum_continue(tcp_csum, th, dp_packet_l4_size(pkt)));
         }
     }
 
@@ -3294,14 +3373,42 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx,
     }
 }
 
+static void
+handle_ftp_ctl_other(struct conntrack *ct OVS_UNUSED, const struct conn_lookup_ctx *ctx,
+                     struct dp_packet *pkt, struct conn *ec, long long now OVS_UNUSED,
+                     bool nat)
+{
+    struct tcp_header *th = dp_packet_l4(pkt);
+    struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt);
+    struct ip_header *l3_hdr = dp_packet_l3(pkt);
+
+    if (nat && ec->seq_skew != 0) {
+        ctx->reply != ec->seq_skew_dir ?
+            adj_seqnum(&th->tcp_ack, -ec->seq_skew) :
+            adj_seqnum(&th->tcp_seq, ec->seq_skew);
+        th->tcp_csum = 0;
+        if (!dp_packet_hwol_tx_l4_checksum(pkt)) {
+            if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) {
+                th->tcp_csum = packet_csum_upperlayer6(nh6, th, ctx->key.nw_proto,
+                        dp_packet_l4_size(pkt));
+            } else {
+                uint32_t tcp_csum = packet_csum_pseudoheader(l3_hdr);
+                th->tcp_csum = csum_finish(
+                        csum_continue(tcp_csum, th, dp_packet_l4_size(pkt)));
+            }
+        }
+    }
+}
+
 static void
 handle_tftp_ctl(struct conntrack *ct,
                 const struct conn_lookup_ctx *ctx OVS_UNUSED,
                 struct dp_packet *pkt, struct conn *conn_for_expectation,
-                long long now OVS_UNUSED, enum ftp_ctl_pkt ftp_ctl OVS_UNUSED,
-                bool nat OVS_UNUSED)
+                long long now OVS_UNUSED, bool nat OVS_UNUSED)
 {
+    ovs_mutex_lock(&conn_for_expectation->lock);
     expectation_create(ct, conn_for_expectation->key.src.port,
                        conn_for_expectation,
                        !!(pkt->md.ct_state & CS_REPLY_DIR), false, false);
+    ovs_mutex_unlock(&conn_for_expectation->lock);
 }
-- 
2.20.1



More information about the dev mailing list