From 3eb56b306194b10a89bf6f66a0b5958abeb4a542 Mon Sep 17 00:00:00 2001 From: Open vSwitch CI Date: Oct 13 2023 18:53:50 +0000 Subject: Import openvswitch2.17-2.17.0-113 from Fast DataPath --- diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch index 0ef8df9..954f7cf 100644 --- a/SOURCES/openvswitch-2.17.0.patch +++ b/SOURCES/openvswitch-2.17.0.patch @@ -51391,6 +51391,82 @@ index d3b4601858..7f3e63c384 100644 } static bool +diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h +index dfdf4e676b..581f517ad1 100644 +--- a/lib/conntrack-private.h ++++ b/lib/conntrack-private.h +@@ -48,6 +48,12 @@ struct ct_endpoint { + * hashing in ct_endpoint_hash_add(). */ + BUILD_ASSERT_DECL(sizeof(struct ct_endpoint) == sizeof(union ct_addr) + 4); + ++enum key_dir { ++ CT_DIR_FWD = 0, ++ CT_DIR_REV, ++ CT_DIRS, ++}; ++ + /* Changes to this structure need to be reflected in conn_key_hash() + * and conn_key_cmp(). */ + struct conn_key { +@@ -86,21 +92,19 @@ struct alg_exp_node { + bool nat_rpl_dst; + }; + +-enum OVS_PACKED_ENUM ct_conn_type { +- CT_CONN_TYPE_DEFAULT, +- CT_CONN_TYPE_UN_NAT, ++struct conn_key_node { ++ enum key_dir dir; ++ struct conn_key key; ++ struct cmap_node cm_node; + }; + + struct conn { + /* Immutable data. */ +- struct conn_key key; +- struct conn_key rev_key; ++ struct conn_key_node key_node[CT_DIRS]; + struct conn_key parent_key; /* Only used for orig_tuple support. */ + struct ovs_list exp_node; +- struct cmap_node cm_node; + uint16_t nat_action; + char *alg; +- struct conn *nat_conn; /* The NAT 'conn' context, if there is one. */ + + /* Mutable data. */ + struct ovs_mutex lock; /* Guards all mutable fields. */ +@@ -120,7 +124,6 @@ struct conn { + + /* Immutable data. */ + bool alg_related; /* True if alg data connection. */ +- enum ct_conn_type conn_type; + + uint32_t tp_id; /* Timeout policy ID. */ + }; +diff --git a/lib/conntrack-tp.c b/lib/conntrack-tp.c +index a586d3a8d3..2bdda67110 100644 +--- a/lib/conntrack-tp.c ++++ b/lib/conntrack-tp.c +@@ -276,7 +276,8 @@ conn_update_expiration(struct conntrack *ct, struct conn *conn, + ovs_mutex_lock(&conn->lock); + VLOG_DBG_RL(&rl, "Update timeout %s zone=%u with policy id=%d " + "val=%u sec.", +- ct_timeout_str[tm], conn->key.zone, conn->tp_id, val); ++ ct_timeout_str[tm], conn->key_node[CT_DIR_FWD].key.zone, ++ conn->tp_id, val); + + conn_update_expiration__(ct, conn, tm, now, val); + } +@@ -307,7 +308,8 @@ conn_init_expiration(struct conntrack *ct, struct conn *conn, + } + + VLOG_DBG_RL(&rl, "Init timeout %s zone=%u with policy id=%d val=%u sec.", +- ct_timeout_str[tm], conn->key.zone, conn->tp_id, val); ++ ct_timeout_str[tm], conn->key_node[CT_DIR_FWD].key.zone, ++ conn->tp_id, val); + + conn_init_expiration__(ct, conn, tm, now, val); + } diff --git a/lib/conntrack-tp.h b/lib/conntrack-tp.h index 4d411d19fd..7ece2eae2f 100644 --- a/lib/conntrack-tp.h @@ -51412,10 +51488,262 @@ index 4d411d19fd..7ece2eae2f 100644 int timeout_policy_update(struct conntrack *ct, struct timeout_policy *tp); int timeout_policy_delete(struct conntrack *ct, uint32_t tp_id); diff --git a/lib/conntrack.c b/lib/conntrack.c -index 33a1a92953..fff8e77db1 100644 +index 33a1a92953..a85e9ba886 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c -@@ -723,109 +723,59 @@ handle_alg_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, +@@ -94,14 +94,13 @@ static bool valid_new(struct dp_packet *pkt, struct conn_key *); + static struct conn *new_conn(struct conntrack *ct, struct dp_packet *pkt, + struct conn_key *, long long now, + uint32_t tp_id); +-static void delete_conn_cmn(struct conn *); ++static void delete_conn__(struct conn *); + static void delete_conn(struct conn *); +-static void delete_conn_one(struct conn *conn); + static enum ct_update_res conn_update(struct conntrack *ct, struct conn *conn, + struct dp_packet *pkt, + struct conn_lookup_ctx *ctx, + long long now); +-static bool conn_expired(struct conn *, long long now); ++static bool conn_expired(const struct conn *, long long now); + static void set_mark(struct dp_packet *, struct conn *, + uint32_t val, uint32_t mask); + static void set_label(struct dp_packet *, struct conn *, +@@ -110,8 +109,7 @@ static void set_label(struct dp_packet *, struct conn *, + static void *clean_thread_main(void *f_); + + static bool +-nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, +- struct conn *nat_conn, ++nat_get_unique_tuple(struct conntrack *ct, struct conn *conn, + const struct nat_action_info_t *nat_info); + + static uint8_t +@@ -205,7 +203,7 @@ static alg_helper alg_helpers[] = { + #define ALG_WC_SRC_PORT 0 + + /* If the total number of connections goes above this value, no new connections +- * are accepted; this is for CT_CONN_TYPE_DEFAULT connections. */ ++ * are accepted. */ + #define DEFAULT_N_CONN_LIMIT 3000000 + + /* Does a member by member comparison of two conn_keys; this +@@ -231,61 +229,6 @@ conn_key_cmp(const struct conn_key *key1, const struct conn_key *key2) + return 1; + } + +-static void +-ct_print_conn_info(const struct conn *c, const char *log_msg, +- enum vlog_level vll, bool force, bool rl_on) +-{ +-#define CT_VLOG(RL_ON, LEVEL, ...) \ +- do { \ +- if (RL_ON) { \ +- static struct vlog_rate_limit rl_ = VLOG_RATE_LIMIT_INIT(5, 5); \ +- vlog_rate_limit(&this_module, LEVEL, &rl_, __VA_ARGS__); \ +- } else { \ +- vlog(&this_module, LEVEL, __VA_ARGS__); \ +- } \ +- } while (0) +- +- if (OVS_UNLIKELY(force || vlog_is_enabled(&this_module, vll))) { +- if (c->key.dl_type == htons(ETH_TYPE_IP)) { +- CT_VLOG(rl_on, vll, "%s: src ip "IP_FMT" dst ip "IP_FMT" rev src " +- "ip "IP_FMT" rev dst ip "IP_FMT" src/dst ports " +- "%"PRIu16"/%"PRIu16" rev src/dst ports " +- "%"PRIu16"/%"PRIu16" zone/rev zone " +- "%"PRIu16"/%"PRIu16" nw_proto/rev nw_proto " +- "%"PRIu8"/%"PRIu8, log_msg, +- IP_ARGS(c->key.src.addr.ipv4), +- IP_ARGS(c->key.dst.addr.ipv4), +- IP_ARGS(c->rev_key.src.addr.ipv4), +- IP_ARGS(c->rev_key.dst.addr.ipv4), +- ntohs(c->key.src.port), ntohs(c->key.dst.port), +- ntohs(c->rev_key.src.port), ntohs(c->rev_key.dst.port), +- c->key.zone, c->rev_key.zone, c->key.nw_proto, +- c->rev_key.nw_proto); +- } else { +- char ip6_s[INET6_ADDRSTRLEN]; +- inet_ntop(AF_INET6, &c->key.src.addr.ipv6, ip6_s, sizeof ip6_s); +- char ip6_d[INET6_ADDRSTRLEN]; +- inet_ntop(AF_INET6, &c->key.dst.addr.ipv6, ip6_d, sizeof ip6_d); +- char ip6_rs[INET6_ADDRSTRLEN]; +- inet_ntop(AF_INET6, &c->rev_key.src.addr.ipv6, ip6_rs, +- sizeof ip6_rs); +- char ip6_rd[INET6_ADDRSTRLEN]; +- inet_ntop(AF_INET6, &c->rev_key.dst.addr.ipv6, ip6_rd, +- sizeof ip6_rd); +- +- CT_VLOG(rl_on, vll, "%s: src ip %s dst ip %s rev src ip %s" +- " rev dst ip %s src/dst ports %"PRIu16"/%"PRIu16 +- " rev src/dst ports %"PRIu16"/%"PRIu16" zone/rev zone " +- "%"PRIu16"/%"PRIu16" nw_proto/rev nw_proto " +- "%"PRIu8"/%"PRIu8, log_msg, ip6_s, ip6_d, ip6_rs, +- ip6_rd, ntohs(c->key.src.port), ntohs(c->key.dst.port), +- ntohs(c->rev_key.src.port), ntohs(c->rev_key.dst.port), +- c->key.zone, c->rev_key.zone, c->key.nw_proto, +- c->rev_key.nw_proto); +- } +- } +-} +- + /* Initializes the connection tracker 'ct'. The caller is responsible for + * calling 'conntrack_destroy()', when the instance is not needed anymore */ + struct conntrack * +@@ -444,34 +387,31 @@ zone_limit_delete(struct conntrack *ct, uint16_t zone) + } + + static void +-conn_clean_cmn(struct conntrack *ct, struct conn *conn) ++conn_clean(struct conntrack *ct, struct conn *conn) + OVS_REQUIRES(ct->ct_lock) + { ++ uint32_t hash; ++ ++ if (conn->cleaned) { ++ return; ++ } ++ + if (conn->alg) { +- expectation_clean(ct, &conn->key); ++ expectation_clean(ct, &conn->key_node[CT_DIR_FWD].key); + } + +- uint32_t hash = conn_key_hash(&conn->key, ct->hash_basis); +- cmap_remove(&ct->conns, &conn->cm_node, hash); ++ hash = conn_key_hash(&conn->key_node[CT_DIR_FWD].key, ct->hash_basis); ++ cmap_remove(&ct->conns, &conn->key_node[CT_DIR_FWD].cm_node, hash); + + struct zone_limit *zl = zone_limit_lookup(ct, conn->admit_zone); + if (zl && zl->czl.zone_limit_seq == conn->zone_limit_seq) { + zl->czl.count--; + } +-} + +-/* Must be called with 'conn' of 'conn_type' CT_CONN_TYPE_DEFAULT. Also +- * removes the associated nat 'conn' from the lookup datastructures. */ +-static void +-conn_clean(struct conntrack *ct, struct conn *conn) +- OVS_REQUIRES(ct->ct_lock) +-{ +- ovs_assert(conn->conn_type == CT_CONN_TYPE_DEFAULT); +- +- conn_clean_cmn(ct, conn); +- if (conn->nat_conn) { +- uint32_t hash = conn_key_hash(&conn->nat_conn->key, ct->hash_basis); +- cmap_remove(&ct->conns, &conn->nat_conn->cm_node, hash); ++ if (conn->nat_action) { ++ hash = conn_key_hash(&conn->key_node[CT_DIR_REV].key, ++ ct->hash_basis); ++ cmap_remove(&ct->conns, &conn->key_node[CT_DIR_REV].cm_node, hash); + } + ovs_list_remove(&conn->exp_node); + conn->cleaned = true; +@@ -479,33 +419,27 @@ conn_clean(struct conntrack *ct, struct conn *conn) + atomic_count_dec(&ct->n_conn); + } + +-static void +-conn_clean_one(struct conntrack *ct, struct conn *conn) +- OVS_REQUIRES(ct->ct_lock) +-{ +- conn_clean_cmn(ct, conn); +- if (conn->conn_type == CT_CONN_TYPE_DEFAULT) { +- ovs_list_remove(&conn->exp_node); +- conn->cleaned = true; +- atomic_count_dec(&ct->n_conn); +- } +- ovsrcu_postpone(delete_conn_one, conn); +-} +- + /* Destroys the connection tracker 'ct' and frees all the allocated memory. + * The caller of this function must already have shut down packet input + * and PMD threads (which would have been quiesced). */ + void + conntrack_destroy(struct conntrack *ct) + { ++ struct conn_key_node *keyn; + struct conn *conn; + latch_set(&ct->clean_thread_exit); + pthread_join(ct->clean_thread, NULL); + latch_destroy(&ct->clean_thread_exit); + + ovs_mutex_lock(&ct->ct_lock); +- CMAP_FOR_EACH (conn, cm_node, &ct->conns) { +- conn_clean_one(ct, conn); ++ CMAP_FOR_EACH (keyn, cm_node, &ct->conns) { ++ if (keyn->dir == CT_DIR_FWD) { ++ conn = CONTAINER_OF(keyn, struct conn, key_node[CT_DIR_FWD]); ++ } else { ++ conn = CONTAINER_OF(keyn, struct conn, key_node[CT_DIR_REV]); ++ } ++ ++ conn_clean(ct, conn); + } + cmap_destroy(&ct->conns); + +@@ -544,31 +478,39 @@ conn_key_lookup(struct conntrack *ct, const struct conn_key *key, + uint32_t hash, long long now, struct conn **conn_out, + bool *reply) + { +- struct conn *conn; ++ struct conn_key_node *keyn; ++ struct conn *conn = NULL; + bool found = false; + +- CMAP_FOR_EACH_WITH_HASH (conn, cm_node, hash, &ct->conns) { +- if (!conn_key_cmp(&conn->key, key) && !conn_expired(conn, now)) { +- found = true; +- if (reply) { +- *reply = false; +- } +- break; ++ CMAP_FOR_EACH_WITH_HASH (keyn, cm_node, hash, &ct->conns) { ++ if (keyn->dir == CT_DIR_FWD) { ++ conn = CONTAINER_OF(keyn, struct conn, key_node[CT_DIR_FWD]); ++ } else { ++ conn = CONTAINER_OF(keyn, struct conn, key_node[CT_DIR_REV]); + } +- if (!conn_key_cmp(&conn->rev_key, key) && !conn_expired(conn, now)) { +- found = true; +- if (reply) { +- *reply = true; ++ ++ if (conn_expired(conn, now)) { ++ continue; ++ } ++ ++ for (int i = CT_DIR_FWD; i < CT_DIRS; i++) { ++ if (!conn_key_cmp(&conn->key_node[i].key, key)) { ++ found = true; ++ if (reply) { ++ *reply = (i == CT_DIR_REV); ++ } ++ goto out_found; + } +- break; + } + } + ++out_found: + if (found && conn_out) { + *conn_out = conn; + } else if (conn_out) { + *conn_out = NULL; + } ++ + return found; + } + +@@ -602,7 +544,7 @@ write_ct_md(struct dp_packet *pkt, uint16_t zone, const struct conn *conn, + if (conn->alg_related) { + key = &conn->parent_key; + } else { +- key = &conn->key; ++ key = &conn->key_node[CT_DIR_FWD].key; + } + } else if (alg_exp) { + pkt->md.ct_mark = alg_exp->parent_mark; +@@ -723,109 +665,59 @@ handle_alg_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, } static void @@ -51559,7 +51887,7 @@ index 33a1a92953..fff8e77db1 100644 { char *tail = dp_packet_tail(pkt); uint16_t pad = dp_packet_l2_pad_size(pkt); -@@ -834,98 +784,77 @@ reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) +@@ -834,98 +726,78 @@ reverse_nat_packet(struct dp_packet *pkt, const struct conn *conn) uint16_t orig_l3_ofs = pkt->l3_ofs; uint16_t orig_l4_ofs = pkt->l4_ofs; @@ -51600,13 +51928,13 @@ index 33a1a92953..fff8e77db1 100644 + /* Reverse the key for inner packet. */ + struct conn_key rev_key = *key; + conn_key_reverse(&rev_key); -+ + +- reverse_pat_packet(pkt, conn); + pat_packet(pkt, &rev_key); + + if (key->dl_type == htons(ETH_TYPE_IP)) { + nat_packet_ipv4(pkt, &rev_key, nat_action); - -- reverse_pat_packet(pkt, conn); ++ + struct icmp_header *icmp = (struct icmp_header *) l4; icmp->icmp_csum = 0; icmp->icmp_csum = csum(icmp, tail - (char *) icmp - pad); @@ -51665,7 +51993,8 @@ index 33a1a92953..fff8e77db1 100644 - nh6->ip6_dst.be32, - &conn->key.src.addr.ipv6, true); - } -+ struct conn_key *key = reply ? &conn->key : &conn->rev_key; ++ enum key_dir dir = reply ? CT_DIR_FWD : CT_DIR_REV; ++ struct conn_key *key = &conn->key_node[dir].key; + uint16_t nat_action = reply ? nat_action_reverse(conn->nat_action) + : conn->nat_action; @@ -51691,14 +52020,14 @@ index 33a1a92953..fff8e77db1 100644 + } else if (nat_action & NAT_ACTION_DST) { + pkt->md.ct_state |= CS_DST_NAT; + } -+ + + /* Reverse the key for outer header. */ + if (key->dl_type == htons(ETH_TYPE_IP)) { + nat_packet_ipv4(pkt, key, nat_action); + } else { + nat_packet_ipv6(pkt, key, nat_action); + } - ++ + if (nat_action & NAT_ACTION_SRC || nat_action & NAT_ACTION_DST) { if (OVS_UNLIKELY(related)) { - reverse_nat_packet(pkt, conn); @@ -51710,16 +52039,133 @@ index 33a1a92953..fff8e77db1 100644 } } } -@@ -1044,7 +973,7 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, - memcpy(nc, nat_conn, sizeof *nc); +@@ -937,7 +809,7 @@ conn_seq_skew_set(struct conntrack *ct, const struct conn *conn_in, + { + struct conn *conn; + ovs_mutex_unlock(&conn_in->lock); +- conn_lookup(ct, &conn_in->key, now, &conn, NULL); ++ conn_lookup(ct, &conn_in->key_node[CT_DIR_FWD].key, now, &conn, NULL); + ovs_mutex_lock(&conn_in->lock); + + if (conn && seq_skew) { +@@ -975,7 +847,6 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, + OVS_REQUIRES(ct->ct_lock) + { + struct conn *nc = NULL; +- struct conn *nat_conn = NULL; + + if (!valid_new(pkt, &ctx->key)) { + pkt->md.ct_state = CS_INVALID; +@@ -989,6 +860,7 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, + } + + if (commit) { ++ struct conn_key_node *fwd_key_node, *rev_key_node; + struct zone_limit *zl = zone_limit_lookup_or_default(ct, + ctx->key.zone); + if (zl && zl->czl.count >= zl->czl.limit) { +@@ -1003,9 +875,12 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, + } + + nc = new_conn(ct, pkt, &ctx->key, now, tp_id); +- memcpy(&nc->key, &ctx->key, sizeof nc->key); +- memcpy(&nc->rev_key, &nc->key, sizeof nc->rev_key); +- conn_key_reverse(&nc->rev_key); ++ fwd_key_node = &nc->key_node[CT_DIR_FWD]; ++ rev_key_node = &nc->key_node[CT_DIR_REV]; ++ memcpy(&fwd_key_node->key, &ctx->key, sizeof fwd_key_node->key); ++ memcpy(&rev_key_node->key, &fwd_key_node->key, ++ sizeof rev_key_node->key); ++ conn_key_reverse(&rev_key_node->key); + + if (ct_verify_helper(helper, ct_alg_ctl)) { + nc->alg = nullable_xstrdup(helper); +@@ -1020,45 +895,33 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, + + if (nat_action_info) { + nc->nat_action = nat_action_info->nat_action; +- nat_conn = xzalloc(sizeof *nat_conn); + + if (alg_exp) { + if (alg_exp->nat_rpl_dst) { +- nc->rev_key.dst.addr = alg_exp->alg_nat_repl_addr; ++ rev_key_node->key.dst.addr = alg_exp->alg_nat_repl_addr; + nc->nat_action = NAT_ACTION_SRC; + } else { +- nc->rev_key.src.addr = alg_exp->alg_nat_repl_addr; ++ rev_key_node->key.src.addr = alg_exp->alg_nat_repl_addr; + nc->nat_action = NAT_ACTION_DST; + } + } else { +- memcpy(nat_conn, nc, sizeof *nat_conn); +- bool nat_res = nat_get_unique_tuple(ct, nc, nat_conn, +- nat_action_info); ++ bool nat_res = nat_get_unique_tuple(ct, nc, nat_action_info); + + if (!nat_res) { + goto nat_res_exhaustion; + } +- +- /* Update nc with nat adjustments made to nat_conn by +- * nat_get_unique_tuple(). */ +- memcpy(nc, nat_conn, sizeof *nc); } - nat_packet(pkt, nc, ctx->icmp_related); +- memcpy(&nat_conn->key, &nc->rev_key, sizeof nat_conn->key); +- memcpy(&nat_conn->rev_key, &nc->key, sizeof nat_conn->rev_key); +- nat_conn->conn_type = CT_CONN_TYPE_UN_NAT; +- nat_conn->nat_action = 0; +- nat_conn->alg = NULL; +- nat_conn->nat_conn = NULL; +- uint32_t nat_hash = conn_key_hash(&nat_conn->key, ct->hash_basis); +- cmap_insert(&ct->conns, &nat_conn->cm_node, nat_hash); + nat_packet(pkt, nc, false, ctx->icmp_related); - memcpy(&nat_conn->key, &nc->rev_key, sizeof nat_conn->key); - memcpy(&nat_conn->rev_key, &nc->key, sizeof nat_conn->rev_key); - nat_conn->conn_type = CT_CONN_TYPE_UN_NAT; -@@ -1148,11 +1077,8 @@ handle_nat(struct dp_packet *pkt, struct conn *conn, ++ uint32_t rev_hash = conn_key_hash(&rev_key_node->key, ++ ct->hash_basis); ++ cmap_insert(&ct->conns, &rev_key_node->cm_node, rev_hash); + } + +- nc->nat_conn = nat_conn; + ovs_mutex_init_adaptive(&nc->lock); +- nc->conn_type = CT_CONN_TYPE_DEFAULT; +- cmap_insert(&ct->conns, &nc->cm_node, ctx->hash); ++ fwd_key_node->dir = CT_DIR_FWD; ++ rev_key_node->dir = CT_DIR_REV; ++ cmap_insert(&ct->conns, &fwd_key_node->cm_node, ctx->hash); + atomic_count_inc(&ct->n_conn); + ctx->conn = nc; /* For completeness. */ + if (zl) { +@@ -1078,9 +941,8 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, + * firewall rules or a separate firewall. Also using zone partitioning + * can limit DoS impact. */ + nat_res_exhaustion: +- free(nat_conn); + ovs_list_remove(&nc->exp_node); +- delete_conn_cmn(nc); ++ delete_conn__(nc); + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + VLOG_WARN_RL(&rl, "Unable to NAT due to tuple space exhaustion - " + "if DoS attack, use firewalling and/or zone partitioning."); +@@ -1092,7 +954,6 @@ conn_update_state(struct conntrack *ct, struct dp_packet *pkt, + struct conn_lookup_ctx *ctx, struct conn *conn, + long long now) + { +- ovs_assert(conn->conn_type == CT_CONN_TYPE_DEFAULT); + bool create_new_conn = false; + + if (ctx->icmp_related) { +@@ -1120,7 +981,8 @@ conn_update_state(struct conntrack *ct, struct dp_packet *pkt, + break; + case CT_UPDATE_NEW: + ovs_mutex_lock(&ct->ct_lock); +- if (conn_lookup(ct, &conn->key, now, NULL, NULL)) { ++ if (conn_lookup(ct, &conn->key_node[CT_DIR_FWD].key, ++ now, NULL, NULL)) { + conn_clean(ct, conn); + } + ovs_mutex_unlock(&ct->ct_lock); +@@ -1148,11 +1010,8 @@ handle_nat(struct dp_packet *pkt, struct conn *conn, if (pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) { pkt->md.ct_state &= ~(CS_SRC_NAT | CS_DST_NAT); } @@ -51733,7 +52179,66 @@ index 33a1a92953..fff8e77db1 100644 } } -@@ -1526,14 +1452,14 @@ set_label(struct dp_packet *pkt, struct conn *conn, +@@ -1300,8 +1159,10 @@ initial_conn_lookup(struct conntrack *ct, struct conn_lookup_ctx *ctx, + + if (natted) { + if (OVS_LIKELY(ctx->conn)) { ++ enum key_dir dir; + ctx->reply = !ctx->reply; +- ctx->key = ctx->reply ? ctx->conn->rev_key : ctx->conn->key; ++ dir = ctx->reply ? CT_DIR_REV : CT_DIR_FWD; ++ ctx->key = ctx->conn->key_node[dir].key; + ctx->hash = conn_key_hash(&ctx->key, ct->hash_basis); + } else { + /* A lookup failure does not necessarily imply that an +@@ -1335,32 +1196,14 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, + /* Delete found entry if in wrong direction. 'force' implies commit. */ + if (OVS_UNLIKELY(force && ctx->reply && conn)) { + ovs_mutex_lock(&ct->ct_lock); +- if (conn_lookup(ct, &conn->key, now, NULL, NULL)) { ++ if (conn_lookup(ct, &conn->key_node[CT_DIR_FWD].key, ++ now, NULL, NULL)) { + conn_clean(ct, conn); + } + ovs_mutex_unlock(&ct->ct_lock); + conn = NULL; + } + +- if (OVS_LIKELY(conn)) { +- if (conn->conn_type == CT_CONN_TYPE_UN_NAT) { +- +- ctx->reply = true; +- struct conn *rev_conn = conn; /* Save for debugging. */ +- uint32_t hash = conn_key_hash(&conn->rev_key, ct->hash_basis); +- conn_key_lookup(ct, &ctx->key, hash, now, &conn, &ctx->reply); +- +- if (!conn) { +- pkt->md.ct_state |= CS_INVALID; +- write_ct_md(pkt, zone, NULL, NULL, NULL); +- char *log_msg = xasprintf("Missing parent conn %p", rev_conn); +- ct_print_conn_info(rev_conn, log_msg, VLL_INFO, true, true); +- free(log_msg); +- return; +- } +- } +- } +- + enum ct_alg_ctl_type ct_alg_ctl = get_alg_ctl_type(pkt, tp_src, tp_dst, + helper); + +@@ -1453,8 +1296,9 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, + struct conn *conn = packet->md.conn; + 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)) { ++ } else if (conn && ++ conn->key_node[CT_DIR_FWD].key.zone == zone && !force && ++ !get_alg_ctl_type(packet, tp_src, tp_dst, helper)) { + process_one_fast(zone, setmark, setlabel, nat_action_info, + conn, packet); + } else if (OVS_UNLIKELY(!conn_key_extract(ct, packet, dl_type, &ctx, +@@ -1526,14 +1370,14 @@ set_label(struct dp_packet *pkt, struct conn *conn, static long long ct_sweep(struct conntrack *ct, long long now, size_t limit) { @@ -51750,16 +52255,36 @@ index 33a1a92953..fff8e77db1 100644 ovs_mutex_lock(&conn->lock); if (now < conn->expiration || count >= limit) { min_expiration = MIN(min_expiration, conn->expiration); -@@ -2242,7 +2168,7 @@ nat_range_hash(const struct conn *conn, uint32_t basis, +@@ -2234,7 +2078,7 @@ nat_ipv6_addr_increment(struct in6_addr *ipv6, uint32_t increment) + } + + static uint32_t +-nat_range_hash(const struct conn *conn, uint32_t basis, ++nat_range_hash(const struct conn_key *key, uint32_t basis, + const struct nat_action_info_t *nat_info) + { + uint32_t hash = basis; +@@ -2242,13 +2086,13 @@ nat_range_hash(const struct conn *conn, uint32_t basis, hash = ct_addr_hash_add(hash, &nat_info->min_addr); hash = ct_addr_hash_add(hash, &nat_info->max_addr); hash = hash_add(hash, - (nat_info->max_port << 16) + ((uint32_t) nat_info->max_port << 16) | nat_info->min_port); - hash = ct_endpoint_hash_add(hash, &conn->key.src); - hash = ct_endpoint_hash_add(hash, &conn->key.dst); -@@ -2265,8 +2191,16 @@ set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k, +- hash = ct_endpoint_hash_add(hash, &conn->key.src); +- hash = ct_endpoint_hash_add(hash, &conn->key.dst); +- hash = hash_add(hash, (OVS_FORCE uint32_t) conn->key.dl_type); +- hash = hash_add(hash, conn->key.nw_proto); +- hash = hash_add(hash, conn->key.zone); ++ hash = ct_endpoint_hash_add(hash, &key->src); ++ hash = ct_endpoint_hash_add(hash, &key->dst); ++ hash = hash_add(hash, (OVS_FORCE uint32_t) key->dl_type); ++ hash = hash_add(hash, key->nw_proto); ++ hash = hash_add(hash, key->zone); + + /* The purpose of the second parameter is to distinguish hashes of data of + * different length; our data always has the same length so there is no +@@ -2265,8 +2109,16 @@ set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k, if (((ni->nat_action & NAT_ACTION_SNAT_ALL) == NAT_ACTION_SRC) || ((ni->nat_action & NAT_ACTION_DST))) { *curr = ntohs(k->src.port); @@ -51778,12 +52303,33 @@ index 33a1a92953..fff8e77db1 100644 } else { *min = ni->min_port; *max = ni->max_port; -@@ -2389,6 +2323,26 @@ next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min, +@@ -2314,7 +2166,7 @@ get_addr_in_range(union ct_addr *min, union ct_addr *max, + } + + static void +-get_initial_addr(const struct conn *conn, union ct_addr *min, ++get_initial_addr(const struct conn_key *key, union ct_addr *min, + union ct_addr *max, union ct_addr *curr, + uint32_t hash, bool ipv4, + const struct nat_action_info_t *nat_info) +@@ -2324,9 +2176,9 @@ get_initial_addr(const struct conn *conn, union ct_addr *min, + /* All-zero case. */ + if (!memcmp(min, &zero_ip, sizeof *min)) { + if (nat_info->nat_action & NAT_ACTION_SRC) { +- *curr = conn->key.src.addr; ++ *curr = key->src.addr; + } else if (nat_info->nat_action & NAT_ACTION_DST) { +- *curr = conn->key.dst.addr; ++ *curr = key->dst.addr; + } + } else { + get_addr_in_range(min, max, curr, hash, ipv4); +@@ -2389,6 +2241,25 @@ next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min, return exhausted; } +static bool -+nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn, ++nat_get_unique_l4(struct conntrack *ct, struct conn_key *rev_key, + ovs_be16 *port, uint16_t curr, uint16_t min, + uint16_t max) +{ @@ -51791,8 +52337,7 @@ index 33a1a92953..fff8e77db1 100644 + + FOR_EACH_PORT_IN_RANGE (curr, min, max) { + *port = htons(curr); -+ if (!conn_lookup(ct, &nat_conn->rev_key, -+ time_msec(), NULL, NULL)) { ++ if (!conn_lookup(ct, rev_key, time_msec(), NULL, NULL)) { + return true; + } + } @@ -51805,7 +52350,7 @@ index 33a1a92953..fff8e77db1 100644 /* This function tries to get a unique tuple. * Every iteration checks that the reverse tuple doesn't * collide with any existing one. -@@ -2403,9 +2357,11 @@ next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min, +@@ -2403,61 +2274,72 @@ next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min, * * In case of DNAT: * - For each dst IP address in the range (if any). @@ -51820,19 +52365,61 @@ index 33a1a92953..fff8e77db1 100644 * * If none can be found, return exhaustion to the caller. */ static bool -@@ -2436,6 +2392,11 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, - set_dport_range(nat_info, &conn->key, hash, &curr_dport, +-nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, +- struct conn *nat_conn, ++nat_get_unique_tuple(struct conntrack *ct, struct conn *conn, + const struct nat_action_info_t *nat_info) + { ++ struct conn_key *fwd_key = &conn->key_node[CT_DIR_FWD].key; ++ struct conn_key *rev_key = &conn->key_node[CT_DIR_REV].key; + union ct_addr min_addr = {0}, max_addr = {0}, curr_addr = {0}, + guard_addr = {0}; +- uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info); +- bool pat_proto = conn->key.nw_proto == IPPROTO_TCP || +- conn->key.nw_proto == IPPROTO_UDP; ++ bool pat_proto = fwd_key->nw_proto == IPPROTO_TCP || ++ fwd_key->nw_proto == IPPROTO_UDP; + uint16_t min_dport, max_dport, curr_dport; + uint16_t min_sport, max_sport, curr_sport; ++ uint32_t hash; + ++ hash = nat_range_hash(fwd_key, ct->hash_basis, nat_info); + min_addr = nat_info->min_addr; + max_addr = nat_info->max_addr; + +- get_initial_addr(conn, &min_addr, &max_addr, &curr_addr, hash, +- (conn->key.dl_type == htons(ETH_TYPE_IP)), nat_info); ++ get_initial_addr(fwd_key, &min_addr, &max_addr, &curr_addr, hash, ++ (fwd_key->dl_type == htons(ETH_TYPE_IP)), nat_info); + + /* Save the address we started from so that + * we can stop once we reach it. */ + guard_addr = curr_addr; + +- set_sport_range(nat_info, &conn->key, hash, &curr_sport, ++ set_sport_range(nat_info, fwd_key, hash, &curr_sport, + &min_sport, &max_sport); +- set_dport_range(nat_info, &conn->key, hash, &curr_dport, ++ set_dport_range(nat_info, fwd_key, hash, &curr_dport, &min_dport, &max_dport); + if (pat_proto) { -+ nat_conn->rev_key.src.port = htons(curr_dport); -+ nat_conn->rev_key.dst.port = htons(curr_sport); ++ rev_key->src.port = htons(curr_dport); ++ rev_key->dst.port = htons(curr_sport); + } + another_round: - store_addr_to_key(&curr_addr, &nat_conn->rev_key, - nat_info->nat_action); -@@ -2449,15 +2410,19 @@ another_round: +- store_addr_to_key(&curr_addr, &nat_conn->rev_key, +- nat_info->nat_action); ++ store_addr_to_key(&curr_addr, rev_key, nat_info->nat_action); + + if (!pat_proto) { +- if (!conn_lookup(ct, &nat_conn->rev_key, +- time_msec(), NULL, NULL)) { ++ if (!conn_lookup(ct, rev_key, time_msec(), NULL, NULL)) { + return true; + } + goto next_addr; } @@ -51847,12 +52434,12 @@ index 33a1a92953..fff8e77db1 100644 - } + bool found = false; + if (nat_info->nat_action & NAT_ACTION_DST_PORT) { -+ found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.src.port, ++ found = nat_get_unique_l4(ct, rev_key, &rev_key->src.port, + curr_dport, min_dport, max_dport); + } + + if (!found) { -+ found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.dst.port, ++ found = nat_get_unique_l4(ct, rev_key, &rev_key->dst.port, + curr_sport, min_sport, max_sport); + } + @@ -51861,7 +52448,175 @@ index 33a1a92953..fff8e77db1 100644 } /* Check if next IP is in range and respin. Otherwise, notify -@@ -2857,8 +2822,8 @@ expectation_clean(struct conntrack *ct, const struct conn_key *parent_key) +@@ -2465,7 +2347,7 @@ another_round: + next_addr: + if (next_addr_in_range_guarded(&curr_addr, &min_addr, + &max_addr, &guard_addr, +- conn->key.dl_type == htons(ETH_TYPE_IP))) { ++ fwd_key->dl_type == htons(ETH_TYPE_IP))) { + return false; + } + +@@ -2477,23 +2359,20 @@ conn_update(struct conntrack *ct, struct conn *conn, struct dp_packet *pkt, + struct conn_lookup_ctx *ctx, long long now) + { + ovs_mutex_lock(&conn->lock); ++ uint8_t nw_proto = conn->key_node[CT_DIR_FWD].key.nw_proto; + enum ct_update_res update_res = +- l4_protos[conn->key.nw_proto]->conn_update(ct, conn, pkt, ctx->reply, +- now); ++ l4_protos[nw_proto]->conn_update(ct, conn, pkt, ctx->reply, now); + ovs_mutex_unlock(&conn->lock); + return update_res; + } + + static bool +-conn_expired(struct conn *conn, long long now) ++conn_expired(const struct conn *conn, long long now) + { +- if (conn->conn_type == CT_CONN_TYPE_DEFAULT) { +- ovs_mutex_lock(&conn->lock); +- bool expired = now >= conn->expiration ? true : false; +- ovs_mutex_unlock(&conn->lock); +- return expired; +- } +- return false; ++ ovs_mutex_lock(&conn->lock); ++ bool expired = now >= conn->expiration ? true : false; ++ ovs_mutex_unlock(&conn->lock); ++ return expired; + } + + static bool +@@ -2510,7 +2389,7 @@ new_conn(struct conntrack *ct, struct dp_packet *pkt, struct conn_key *key, + } + + static void +-delete_conn_cmn(struct conn *conn) ++delete_conn__(struct conn *conn) + { + free(conn->alg); + free(conn); +@@ -2519,20 +2398,8 @@ delete_conn_cmn(struct conn *conn) + static void + delete_conn(struct conn *conn) + { +- ovs_assert(conn->conn_type == CT_CONN_TYPE_DEFAULT); + ovs_mutex_destroy(&conn->lock); +- free(conn->nat_conn); +- delete_conn_cmn(conn); +-} +- +-/* Only used by conn_clean_one(). */ +-static void +-delete_conn_one(struct conn *conn) +-{ +- if (conn->conn_type == CT_CONN_TYPE_DEFAULT) { +- ovs_mutex_destroy(&conn->lock); +- } +- delete_conn_cmn(conn); ++ delete_conn__(conn); + } + + /* Convert a conntrack address 'a' into an IP address 'b' based on 'dl_type'. +@@ -2623,11 +2490,14 @@ static void + conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, + long long now) + { ++ const struct conn_key *rev_key = &conn->key_node[CT_DIR_REV].key; ++ const struct conn_key *key = &conn->key_node[CT_DIR_FWD].key; ++ + memset(entry, 0, sizeof *entry); +- conn_key_to_tuple(&conn->key, &entry->tuple_orig); +- conn_key_to_tuple(&conn->rev_key, &entry->tuple_reply); ++ conn_key_to_tuple(key, &entry->tuple_orig); ++ conn_key_to_tuple(rev_key, &entry->tuple_reply); + +- entry->zone = conn->key.zone; ++ entry->zone = key->zone; + + ovs_mutex_lock(&conn->lock); + entry->mark = conn->mark; +@@ -2635,7 +2505,7 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, + + long long expiration = conn->expiration - now; + +- struct ct_l4_proto *class = l4_protos[conn->key.nw_proto]; ++ struct ct_l4_proto *class = l4_protos[key->nw_proto]; + if (class->conn_get_protoinfo) { + class->conn_get_protoinfo(conn, &entry->protoinfo); + } +@@ -2683,10 +2553,21 @@ conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry *entry) + if (!cm_node) { + break; + } ++ struct conn_key_node *keyn; + struct conn *conn; +- INIT_CONTAINER(conn, cm_node, cm_node); +- if ((!dump->filter_zone || conn->key.zone == dump->zone) && +- (conn->conn_type != CT_CONN_TYPE_UN_NAT)) { ++ ++ INIT_CONTAINER(keyn, cm_node, cm_node); ++ ++ if (keyn->dir != CT_DIR_FWD) { ++ continue; ++ } ++ ++ conn = CONTAINER_OF(keyn, struct conn, key_node[CT_DIR_FWD]); ++ if (conn_expired(conn, now)) { ++ continue; ++ } ++ ++ if ((!dump->filter_zone || keyn->key.zone == dump->zone)) { + conn_to_ct_dpif_entry(conn, entry, now); + return 0; + } +@@ -2704,12 +2585,18 @@ conntrack_dump_done(struct conntrack_dump *dump OVS_UNUSED) + int + conntrack_flush(struct conntrack *ct, const uint16_t *zone) + { ++ struct conn_key_node *keyn; + struct conn *conn; + + ovs_mutex_lock(&ct->ct_lock); +- CMAP_FOR_EACH (conn, cm_node, &ct->conns) { +- if (!zone || *zone == conn->key.zone) { +- conn_clean_one(ct, conn); ++ CMAP_FOR_EACH (keyn, cm_node, &ct->conns) { ++ if (keyn->dir != CT_DIR_FWD) { ++ continue; ++ } ++ ++ conn = CONTAINER_OF(keyn, struct conn, key_node[CT_DIR_FWD]); ++ if (!zone || *zone == keyn->key.zone) { ++ conn_clean(ct, conn); + } + } + ovs_mutex_unlock(&ct->ct_lock); +@@ -2721,19 +2608,19 @@ int + conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple *tuple, + uint16_t zone) + { +- int error = 0; + struct conn_key key; + struct conn *conn; ++ int error = 0; + + memset(&key, 0, sizeof(key)); + tuple_to_conn_key(tuple, zone, &key); + ovs_mutex_lock(&ct->ct_lock); + conn_lookup(ct, &key, time_msec(), &conn, NULL); + +- if (conn && conn->conn_type == CT_CONN_TYPE_DEFAULT) { ++ if (conn) { + conn_clean(ct, conn); + } else { +- VLOG_WARN("Must flush tuple using the original pre-NATed tuple"); ++ VLOG_WARN("Tuple not found"); + error = ENOENT; + } + +@@ -2857,8 +2744,8 @@ expectation_clean(struct conntrack *ct, const struct conn_key *parent_key) { ovs_rwlock_wrlock(&ct->resources_lock); @@ -51872,6 +52627,143 @@ index 33a1a92953..fff8e77db1 100644 conn_key_hash(parent_key, ct->hash_basis), &ct->alg_expectation_refs) { if (!conn_key_cmp(&node->parent_key, parent_key)) { +@@ -2877,50 +2764,54 @@ expectation_create(struct conntrack *ct, ovs_be16 dst_port, + const struct conn *parent_conn, bool reply, bool src_ip_wc, + bool skip_nat) + { ++ const struct conn_key *pconn_key, *pconn_rev_key; + union ct_addr src_addr; + union ct_addr dst_addr; + union ct_addr alg_nat_repl_addr; + struct alg_exp_node *alg_exp_node = xzalloc(sizeof *alg_exp_node); + ++ pconn_key = &parent_conn->key_node[CT_DIR_FWD].key; ++ pconn_rev_key = &parent_conn->key_node[CT_DIR_REV].key; ++ + if (reply) { +- src_addr = parent_conn->key.src.addr; +- dst_addr = parent_conn->key.dst.addr; ++ src_addr = pconn_key->src.addr; ++ dst_addr = pconn_key->dst.addr; + alg_exp_node->nat_rpl_dst = true; + if (skip_nat) { + alg_nat_repl_addr = dst_addr; + } else if (parent_conn->nat_action & NAT_ACTION_DST) { +- alg_nat_repl_addr = parent_conn->rev_key.src.addr; ++ alg_nat_repl_addr = pconn_rev_key->src.addr; + alg_exp_node->nat_rpl_dst = false; + } else { +- alg_nat_repl_addr = parent_conn->rev_key.dst.addr; ++ alg_nat_repl_addr = pconn_rev_key->dst.addr; + } + } else { +- src_addr = parent_conn->rev_key.src.addr; +- dst_addr = parent_conn->rev_key.dst.addr; ++ src_addr = pconn_rev_key->src.addr; ++ dst_addr = pconn_rev_key->dst.addr; + alg_exp_node->nat_rpl_dst = false; + if (skip_nat) { + alg_nat_repl_addr = src_addr; + } else if (parent_conn->nat_action & NAT_ACTION_DST) { +- alg_nat_repl_addr = parent_conn->key.dst.addr; ++ alg_nat_repl_addr = pconn_key->dst.addr; + alg_exp_node->nat_rpl_dst = true; + } else { +- alg_nat_repl_addr = parent_conn->key.src.addr; ++ alg_nat_repl_addr = pconn_key->src.addr; + } + } + if (src_ip_wc) { + memset(&src_addr, 0, sizeof src_addr); + } + +- alg_exp_node->key.dl_type = parent_conn->key.dl_type; +- alg_exp_node->key.nw_proto = parent_conn->key.nw_proto; +- alg_exp_node->key.zone = parent_conn->key.zone; ++ alg_exp_node->key.dl_type = pconn_key->dl_type; ++ alg_exp_node->key.nw_proto = pconn_key->nw_proto; ++ alg_exp_node->key.zone = pconn_key->zone; + alg_exp_node->key.src.addr = src_addr; + alg_exp_node->key.dst.addr = dst_addr; + alg_exp_node->key.src.port = ALG_WC_SRC_PORT; + alg_exp_node->key.dst.port = dst_port; + alg_exp_node->parent_mark = parent_conn->mark; + alg_exp_node->parent_label = parent_conn->label; +- memcpy(&alg_exp_node->parent_key, &parent_conn->key, ++ memcpy(&alg_exp_node->parent_key, pconn_key, + sizeof alg_exp_node->parent_key); + /* Take the write lock here because it is almost 100% + * likely that the lookup will fail and +@@ -3172,12 +3063,16 @@ process_ftp_ctl_v4(struct conntrack *ct, + + switch (mode) { + case CT_FTP_MODE_ACTIVE: +- *v4_addr_rep = conn_for_expectation->rev_key.dst.addr.ipv4; +- conn_ipv4_addr = conn_for_expectation->key.src.addr.ipv4; ++ *v4_addr_rep = ++ conn_for_expectation->key_node[CT_DIR_REV].key.dst.addr.ipv4; ++ conn_ipv4_addr = ++ conn_for_expectation->key_node[CT_DIR_FWD].key.src.addr.ipv4; + break; + case CT_FTP_MODE_PASSIVE: +- *v4_addr_rep = conn_for_expectation->key.dst.addr.ipv4; +- conn_ipv4_addr = conn_for_expectation->rev_key.src.addr.ipv4; ++ *v4_addr_rep = ++ conn_for_expectation->key_node[CT_DIR_FWD].key.dst.addr.ipv4; ++ conn_ipv4_addr = ++ conn_for_expectation->key_node[CT_DIR_REV].key.src.addr.ipv4; + break; + case CT_TFTP_MODE: + default: +@@ -3209,7 +3104,7 @@ skip_ipv6_digits(char *str) + static enum ftp_ctl_pkt + process_ftp_ctl_v6(struct conntrack *ct, + struct dp_packet *pkt, +- const struct conn *conn_for_expectation, ++ const struct conn *conn_for_exp, + union ct_addr *v6_addr_rep, char **ftp_data_start, + size_t *addr_offset_from_ftp_data_start, + size_t *addr_size, enum ct_alg_mode *mode) +@@ -3277,24 +3172,25 @@ process_ftp_ctl_v6(struct conntrack *ct, + + switch (*mode) { + case CT_FTP_MODE_ACTIVE: +- *v6_addr_rep = conn_for_expectation->rev_key.dst.addr; ++ *v6_addr_rep = conn_for_exp->key_node[CT_DIR_REV].key.dst.addr; + /* Although most servers will block this exploit, there may be some + * less well managed. */ + if (memcmp(&ip6_addr, &v6_addr_rep->ipv6, sizeof ip6_addr) && +- memcmp(&ip6_addr, &conn_for_expectation->key.src.addr.ipv6, ++ memcmp(&ip6_addr, ++ &conn_for_exp->key_node[CT_DIR_FWD].key.src.addr.ipv6, + sizeof ip6_addr)) { + return CT_FTP_CTL_INVALID; + } + break; + case CT_FTP_MODE_PASSIVE: +- *v6_addr_rep = conn_for_expectation->key.dst.addr; ++ *v6_addr_rep = conn_for_exp->key_node[CT_DIR_FWD].key.dst.addr; + break; + case CT_TFTP_MODE: + default: + OVS_NOT_REACHED(); + } + +- expectation_create(ct, port, conn_for_expectation, ++ expectation_create(ct, port, conn_for_exp, + !!(pkt->md.ct_state & CS_REPLY_DIR), false, false); + return CT_FTP_CTL_INTEREST; + } +@@ -3448,7 +3344,8 @@ handle_tftp_ctl(struct conntrack *ct, + long long now OVS_UNUSED, enum ftp_ctl_pkt ftp_ctl OVS_UNUSED, + bool nat OVS_UNUSED) + { +- expectation_create(ct, conn_for_expectation->key.src.port, ++ expectation_create(ct, ++ conn_for_expectation->key_node[CT_DIR_FWD].key.src.port, + conn_for_expectation, + !!(pkt->md.ct_state & CS_REPLY_DIR), false, false); + } diff --git a/lib/cpu.c b/lib/cpu.c index 2df003c51b..e7cbfcfe6e 100644 --- a/lib/cpu.c diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec index 3707218..475348a 100644 --- a/SPECS/openvswitch2.17.spec +++ b/SPECS/openvswitch2.17.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.17.0 -Release: 112%{?dist} +Release: 113%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -751,6 +751,13 @@ exit 0 %endif %changelog +* Fri Oct 13 2023 Open vSwitch CI - 2.17.0-113 +- Merging upstream branch-2.17 [RH git: aa85ffacfd] + Commit list: + be1a8f7ecb conntrack: Remove nat_conn introducing key directionality. + f179c7c07f conntrack: simplify cleanup path + + * Thu Oct 12 2023 Timothy Redaelli - 2.17.0-112 - redhat: use rhpkg push instead of git push [RH git: 7b22bbc0dd]