expectation_create(struct conntrack *ct,
                   ovs_be16 dst_port,
                   const long long now,
                   enum ct_alg_mode mode,
                   const struct conn *master_conn)
{
    struct ct_addr src_addr;
    struct ct_addr dst_addr;
    struct ct_addr alg_nat_repl_addr;

    switch (mode) {
    case CT_FTP_MODE_ACTIVE:
    case CT_TFTP_MODE:
        src_addr = master_conn->rev_key.src.addr;
        dst_addr = master_conn->rev_key.dst.addr;
        alg_nat_repl_addr = master_conn->key.src.addr;
        break;
    case CT_FTP_MODE_PASSIVE:
        src_addr = master_conn->key.src.addr;
        dst_addr = master_conn->key.dst.addr;
        alg_nat_repl_addr = master_conn->rev_key.dst.addr;
        break;
    default:
        OVS_NOT_REACHED();
    }

    struct alg_exp_node *alg_exp_node =
        xzalloc(sizeof *alg_exp_node);
    alg_exp_node->key.dl_type = master_conn->key.dl_type;
    alg_exp_node->key.nw_proto = master_conn->key.nw_proto;
    alg_exp_node->key.zone = master_conn->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->master_mark = master_conn->mark;
    alg_exp_node->master_label = master_conn->label;
    alg_exp_node->master_key = master_conn->key;
    alg_exp_node->passive_mode = mode == CT_FTP_MODE_PASSIVE;
    /* Take the write lock here because it is almost 100%
     * likely that the lookup will fail and
     * expectation_create() will be called below. */
    ct_rwlock_wrlock(&ct->resources_lock);
    struct alg_exp_node *alg_exp = expectation_lookup(
        &ct->alg_expectations, &alg_exp_node->key, ct->hash_basis);
    if (alg_exp) {
        free(alg_exp_node);
        ct_rwlock_unlock(&ct->resources_lock);
        return;
    }

    alg_exp_node->alg_nat_repl_addr = alg_nat_repl_addr;
    uint32_t alg_exp_conn_key_hash =
        conn_key_hash(&alg_exp_node->key,
                      ct->hash_basis);
    hmap_insert(&ct->alg_expectations,
                &alg_exp_node->node,
                alg_exp_conn_key_hash);

    alg_exp_init_expiration(ct, alg_exp_node, now);
    ct_rwlock_unlock(&ct->resources_lock);
}
expectation_create(struct conntrack *ct,
                   ovs_be16 dst_port,
                   const long long now,
                   enum ct_alg_mode mode,
                   const struct conn *master_conn)
{
    struct ct_addr src_addr;
    struct ct_addr dst_addr;
    struct ct_addr alg_nat_repl_addr;

    switch (mode) {
    case CT_FTP_MODE_ACTIVE:
    case CT_TFTP_MODE:
        src_addr = master_conn->rev_key.src.addr;
        dst_addr = master_conn->rev_key.dst.addr;
        alg_nat_repl_addr = master_conn->key.src.addr;
        break;
    case CT_FTP_MODE_PASSIVE:
        src_addr = master_conn->key.src.addr;
        dst_addr = master_conn->key.dst.addr;
        alg_nat_repl_addr = master_conn->rev_key.dst.addr;
        break;
    default:
        OVS_NOT_REACHED();
    }

    struct alg_exp_node *alg_exp_node =
        xzalloc(sizeof *alg_exp_node);
    alg_exp_node->key.dl_type = master_conn->key.dl_type;
    alg_exp_node->key.nw_proto = master_conn->key.nw_proto;
    alg_exp_node->key.zone = master_conn->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->master_mark = master_conn->mark;
    alg_exp_node->master_label = master_conn->label;
    alg_exp_node->master_key = master_conn->key;
    alg_exp_node->passive_mode = mode == CT_FTP_MODE_PASSIVE;
     
    ct_rwlock_wrlock(&ct->resources_lock);
    struct alg_exp_node *alg_exp = expectation_lookup(
        &ct->alg_expectations, &alg_exp_node->key, ct->hash_basis);
    if (alg_exp) {
        free(alg_exp_node);
        ct_rwlock_unlock(&ct->resources_lock);
        return;
    }

    alg_exp_node->alg_nat_repl_addr = alg_nat_repl_addr;
    uint32_t alg_exp_conn_key_hash =
        conn_key_hash(&alg_exp_node->key,
                      ct->hash_basis);
    hmap_insert(&ct->alg_expectations,
                &alg_exp_node->node,
                alg_exp_conn_key_hash);

    alg_exp_init_expiration(ct, alg_exp_node, now);
    ct_rwlock_unlock(&ct->resources_lock);
}