conntrack_init(void)
{
    static struct ovsthread_once setup_l4_once = OVSTHREAD_ONCE_INITIALIZER;
    struct conntrack *ct = xzalloc(sizeof *ct);

    ovs_rwlock_init(&ct->resources_lock);
    ovs_rwlock_wrlock(&ct->resources_lock);
    hmap_init(&ct->alg_expectations);
    hindex_init(&ct->alg_expectation_refs);
    ovs_rwlock_unlock(&ct->resources_lock);

    ovs_mutex_init_adaptive(&ct->ct_lock);
    ovs_mutex_lock(&ct->ct_lock);
    cmap_init(&ct->conns);
    for (unsigned i = 0; i < ARRAY_SIZE(ct->exp_lists); i++) {
        ovs_list_init(&ct->exp_lists[i]);
    }
    hmap_init(&ct->zone_limits);
    ct->zone_limit_seq = 0;
    timeout_policy_init(ct);
    ovs_mutex_unlock(&ct->ct_lock);

    ct->hash_basis = random_uint32();
    atomic_count_init(&ct->n_conn, 0);
    atomic_init(&ct->n_conn_limit, DEFAULT_N_CONN_LIMIT);
    atomic_init(&ct->tcp_seq_chk, true);
    latch_init(&ct->clean_thread_exit);
    ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct);
    ct->ipf = ipf_init();

    /* Initialize the l4 protocols. */
    if (ovsthread_once_start(&setup_l4_once)) {
        for (int i = 0; i < ARRAY_SIZE(l4_protos); i++) {
            l4_protos[i] = &ct_proto_other;
        }
        /* IPPROTO_UDP uses ct_proto_other, so no need to initialize it. */
        l4_protos[IPPROTO_TCP] = &ct_proto_tcp;
        l4_protos[IPPROTO_ICMP] = &ct_proto_icmp4;
        l4_protos[IPPROTO_ICMPV6] = &ct_proto_icmp6;

        ovsthread_once_done(&setup_l4_once);
    }
    return ct;
}
conntrack_init(void)
{
    static struct ovsthread_once setup_l4_once = OVSTHREAD_ONCE_INITIALIZER;
    struct conntrack *ct = xzalloc(sizeof *ct);

    ovs_rwlock_init(&ct->resources_lock);
    ovs_rwlock_wrlock(&ct->resources_lock);
    hmap_init(&ct->alg_expectations);
    hindex_init(&ct->alg_expectation_refs);
    ovs_rwlock_unlock(&ct->resources_lock);

    ovs_mutex_init_adaptive(&ct->ct_lock);
    ovs_mutex_lock(&ct->ct_lock);
    cmap_init(&ct->conns);
    for (unsigned i = 0; i < ARRAY_SIZE(ct->exp_lists); i++) {
        ovs_list_init(&ct->exp_lists[i]);
    }
    hmap_init(&ct->zone_limits);
    ct->zone_limit_seq = 0;
    timeout_policy_init(ct);
    ovs_mutex_unlock(&ct->ct_lock);

    ct->hash_basis = random_uint32();
    atomic_count_init(&ct->n_conn, 0);
    atomic_init(&ct->n_conn_limit, DEFAULT_N_CONN_LIMIT);
    atomic_init(&ct->tcp_seq_chk, true);
    latch_init(&ct->clean_thread_exit);
    ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct);
    ct->ipf = ipf_init();

     
    if (ovsthread_once_start(&setup_l4_once)) {
        for (int i = 0; i < ARRAY_SIZE(l4_protos); i++) {
            l4_protos[i] = &ct_proto_other;
        }
         
        l4_protos[IPPROTO_TCP] = &ct_proto_tcp;
        l4_protos[IPPROTO_ICMP] = &ct_proto_icmp4;
        l4_protos[IPPROTO_ICMPV6] = &ct_proto_icmp6;

        ovsthread_once_done(&setup_l4_once);
    }
    return ct;
}