From: hepeng <[email protected]> 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 <[email protected]> --- 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 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
