+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ s->out2in = key;
+ kv.value = s - tsm->sessions;
+
+ key.addr.as_u32 = in_addr->as_u32;
+ key.port = in_port;
+ key.fib_index = fib_index;
+ s->in2out = key;
+
+ make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
+ snat_proto_to_ip_proto (proto), fib_index, in_port,
+ s->ext_host_nat_port);
+ if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
+ nat_elog_warn ("in2out key add failed");
+
+ make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
+ s->out2in.fib_index, out_port, eh_port);
+ if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
+ nat_elog_warn ("out2in key add failed");
+}
+
+void
+nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+ u32 fib_index, u32 ti)
+{
+ snat_main_t *sm = &snat_main;
+ nat_ed_ses_key_t key;
+ clib_bihash_kv_16_8_t kv, value;
+ u32 thread_index;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ if (sm->num_workers > 1)
+ thread_index =
+ sm->first_worker_index +
+ (sm->workers[(clib_net_to_host_u16 (out_port) -
+ 1024) / sm->port_per_thread]);
+ else
+ thread_index = sm->num_workers;
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.l_addr.as_u32 = out_addr->as_u32;
+ key.l_port = out_port;
+ key.r_addr.as_u32 = eh_addr->as_u32;
+ key.r_port = eh_port;
+ key.proto = proto;
+ key.fib_index = fib_index;
+ kv.key[0] = key.as_u64[0];
+ kv.key[1] = key.as_u64[1];
+ if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ nat_free_session_data (sm, s, thread_index, 1);
+ nat44_delete_session (sm, s, thread_index);
+}
+
+void
+nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+ u32 fib_index, u32 total_pkts, u64 total_bytes,
+ u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ nat_ed_ses_key_t key;
+ clib_bihash_kv_16_8_t kv, value;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.l_addr.as_u32 = out_addr->as_u32;
+ key.l_port = out_port;
+ key.r_addr.as_u32 = eh_addr->as_u32;
+ key.r_port = eh_port;
+ key.proto = proto;
+ key.fib_index = fib_index;
+ kv.key[0] = key.as_u64[0];
+ kv.key[1] = key.as_u64[1];
+ if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ s->total_pkts = total_pkts;
+ s->total_bytes = total_bytes;
+}
+
+static clib_error_t *
+snat_config (vlib_main_t * vm, unformat_input_t * input)
+{
+ snat_main_t *sm = &snat_main;
+ nat66_main_t *nm = &nat66_main;
+ //dslite_main_t *dm = &dslite_main;
+ snat_main_per_thread_data_t *tsm;
+
+ u32 static_mapping_buckets = 1024;
+ u32 static_mapping_memory_size = 64 << 20;
+
+ u32 nat64_bib_buckets = 1024;
+ u32 nat64_bib_memory_size = 128 << 20;
+
+ u32 nat64_st_buckets = 2048;
+ u32 nat64_st_memory_size = 256 << 20;
+
+ u32 user_buckets = 128;
+ u32 user_memory_size = 64 << 20;
+ u32 translation_buckets = 1024;
+ u32 translation_memory_size = 128 << 20;
+
+ u32 max_translations_per_user = ~0;
+
+ u32 outside_vrf_id = 0;
+ u32 outside_ip6_vrf_id = 0;
+ u32 inside_vrf_id = 0;
+ u8 static_mapping_only = 0;
+ u8 static_mapping_connection_tracking = 0;
+
+ // configurable timeouts
+ u32 udp_timeout = SNAT_UDP_TIMEOUT;
+ u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
+ u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
+ u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
+
+ sm->deterministic = 0;
+ sm->out2in_dpo = 0;
+ sm->endpoint_dependent = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat
+ (input, "translation hash buckets %d", &translation_buckets))
+ ;
+ else if (unformat (input, "udp timeout %d", &udp_timeout))
+ ;
+ else if (unformat (input, "icmp timeout %d", &icmp_timeout))
+ ;
+ else if (unformat (input, "tcp transitory timeout %d",
+ &tcp_transitory_timeout));
+ else if (unformat (input, "tcp established timeout %d",
+ &tcp_established_timeout));
+ else if (unformat (input, "translation hash memory %d",
+ &translation_memory_size));
+ else if (unformat (input, "user hash buckets %d", &user_buckets))
+ ;
+ else if (unformat (input, "user hash memory %d", &user_memory_size))
+ ;
+ else if (unformat (input, "max translations per user %d",
+ &max_translations_per_user))
+ ;
+ else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
+ ;
+ else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
+ ;
+ else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
+ ;
+ else if (unformat (input, "static mapping only"))
+ {
+ static_mapping_only = 1;
+ if (unformat (input, "connection tracking"))
+ static_mapping_connection_tracking = 1;
+ }
+ else if (unformat (input, "deterministic"))
+ sm->deterministic = 1;
+ else if (unformat (input, "nat64 bib hash buckets %d",
+ &nat64_bib_buckets))
+ ;
+ else if (unformat (input, "nat64 bib hash memory %d",
+ &nat64_bib_memory_size))
+ ;
+ else
+ if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
+ ;
+ else if (unformat (input, "nat64 st hash memory %d",
+ &nat64_st_memory_size))
+ ;
+ else if (unformat (input, "out2in dpo"))
+ sm->out2in_dpo = 1;
+ //else if (unformat (input, "dslite ce"))
+ //dslite_set_ce (dm, 1);
+ else if (unformat (input, "endpoint-dependent"))
+ sm->endpoint_dependent = 1;
+ else
+ return clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, input);
+ }
+
+ if (sm->deterministic && sm->endpoint_dependent)
+ return clib_error_return (0,
+ "deterministic and endpoint-dependent modes are mutually exclusive");
+
+ if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
+ return clib_error_return (0,
+ "static mapping only mode available only for simple nat");
+
+ if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
+ return clib_error_return (0,
+ "out2in dpo mode available only for simple nat");
+
+ /* optionally configurable timeouts for testing purposes */
+ sm->udp_timeout = udp_timeout;
+ sm->tcp_transitory_timeout = tcp_transitory_timeout;
+ sm->tcp_established_timeout = tcp_established_timeout;
+ sm->icmp_timeout = icmp_timeout;
+
+ sm->min_timeout = nat44_minimal_timeout (sm);
+
+ sm->user_buckets = user_buckets;
+ sm->user_memory_size = user_memory_size;
+
+ sm->translation_buckets = translation_buckets;
+ sm->translation_memory_size = translation_memory_size;
+
+ /* do not exceed load factor 10 */
+ sm->max_translations = 10 * translation_buckets;
+ sm->max_translations_per_user = max_translations_per_user == ~0 ?
+ sm->max_translations : max_translations_per_user;
+
+ sm->outside_vrf_id = outside_vrf_id;
+ sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+ outside_vrf_id,
+ nat_fib_src_hi);
+ nm->outside_vrf_id = outside_ip6_vrf_id;
+ nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
+ outside_ip6_vrf_id,
+ nat_fib_src_hi);
+ sm->inside_vrf_id = inside_vrf_id;
+ sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+ inside_vrf_id,
+ nat_fib_src_hi);
+ sm->static_mapping_only = static_mapping_only;
+ sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
+
+ nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
+ nat64_st_memory_size);