+static u32
+nat_calc_bihash_buckets (u32 n_elts)
+{
+ return 1 << (max_log2 (n_elts >> 1) + 1);
+}
+
+static u32
+nat_calc_bihash_memory (u32 n_buckets, uword kv_size)
+{
+ return n_buckets * (8 + kv_size * 4);
+}
+
+u32
+nat44_get_max_session_limit ()
+{
+ snat_main_t *sm = &snat_main;
+ u32 max_limit = 0, len = 0;
+
+ for (; len < vec_len (sm->max_translations_per_fib); len++)
+ {
+ if (max_limit < sm->max_translations_per_fib[len])
+ max_limit = sm->max_translations_per_fib[len];
+ }
+ return max_limit;
+}
+
+int
+nat44_set_session_limit (u32 session_limit, u32 vrf_id)
+{
+ snat_main_t *sm = &snat_main;
+ u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+ u32 len = vec_len (sm->max_translations_per_fib);
+
+ if (len <= fib_index)
+ {
+ vec_validate (sm->max_translations_per_fib, fib_index + 1);
+
+ for (; len < vec_len (sm->max_translations_per_fib); len++)
+ sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
+ }
+
+ sm->max_translations_per_fib[fib_index] = session_limit;
+ return 0;
+}
+
+int
+nat44_update_session_limit (u32 session_limit, u32 vrf_id)
+{
+ snat_main_t *sm = &snat_main;
+
+ if (nat44_set_session_limit (session_limit, vrf_id))
+ return 1;
+ sm->max_translations_per_thread = nat44_get_max_session_limit ();
+
+ sm->translation_buckets =
+ nat_calc_bihash_buckets (sm->max_translations_per_thread);
+
+ if (!sm->translation_memory_size_set)
+ {
+ sm->translation_memory_size =
+ nat_calc_bihash_memory (sm->translation_buckets,
+ sizeof (clib_bihash_16_8_t));
+ }
+
+ nat44_sessions_clear ();
+ return 0;
+}
+
+void
+nat44_db_init (snat_main_per_thread_data_t * tsm)
+{
+ snat_main_t *sm = &snat_main;
+
+ pool_alloc (tsm->sessions, sm->max_translations_per_thread);
+ pool_alloc (tsm->lru_pool, sm->max_translations_per_thread);
+
+ dlist_elt_t *head;
+
+ pool_get (tsm->lru_pool, head);
+ tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->udp_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->icmp_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
+
+ pool_get (tsm->lru_pool, head);
+ tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
+ clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
+
+ if (sm->endpoint_dependent)
+ {
+ clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
+ sm->translation_buckets,
+ sm->translation_memory_size);
+ clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
+ format_ed_session_kvp);
+
+ }
+ else
+ {
+ clib_bihash_init_8_8 (&tsm->in2out, "in2out",
+ sm->translation_buckets,
+ sm->translation_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp);
+ clib_bihash_init_8_8 (&tsm->out2in, "out2in",
+ sm->translation_buckets,
+ sm->translation_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp);
+ }
+
+ // TODO: resolve static mappings (put only to !ED)
+ pool_alloc (tsm->list_pool, sm->max_translations_per_thread);
+ clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets,
+ sm->user_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
+}
+
+void
+nat44_db_free (snat_main_per_thread_data_t * tsm)
+{
+ snat_main_t *sm = &snat_main;
+
+ pool_free (tsm->sessions);
+ pool_free (tsm->lru_pool);
+
+ if (sm->endpoint_dependent)
+ {
+ clib_bihash_free_16_8 (&tsm->in2out_ed);
+ vec_free (tsm->per_vrf_sessions_vec);
+ }
+ else
+ {
+ clib_bihash_free_8_8 (&tsm->in2out);
+ clib_bihash_free_8_8 (&tsm->out2in);
+ }
+
+ // TODO: resolve static mappings (put only to !ED)
+ pool_free (tsm->users);
+ pool_free (tsm->list_pool);
+ clib_bihash_free_8_8 (&tsm->user_hash);
+}
+
+void
+nat44_sessions_clear ()
+{
+ snat_main_t *sm = &snat_main;
+ snat_main_per_thread_data_t *tsm;
+
+ if (sm->endpoint_dependent)
+ {
+ clib_bihash_free_16_8 (&sm->out2in_ed);
+ clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
+ clib_max (1, sm->num_workers) *
+ sm->translation_buckets,
+ clib_max (1, sm->num_workers) *
+ sm->translation_memory_size);
+ clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
+ format_ed_session_kvp);
+ }
+
+ /* *INDENT-OFF* */
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ u32 ti;
+
+ nat44_db_free (tsm);
+ nat44_db_init (tsm);
+
+ ti = tsm->snat_thread_index;
+ vlib_set_simple_counter (&sm->total_users, ti, 0, 0);
+ vlib_set_simple_counter (&sm->total_sessions, ti, 0, 0);
+ }
+ /* *INDENT-ON* */
+}
+