+ 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;
+ uword static_mapping_memory_size = 64 << 20;
+
+ u32 nat64_bib_buckets = 1024;
+ u32 nat64_bib_memory_size = 128 << 20;
+
+ u32 nat64_st_buckets = 2048;
+ uword nat64_st_memory_size = 256 << 20;
+
+ u32 user_buckets = 128;
+ uword user_memory_size = 64 << 20;
+ u32 translation_buckets = 1024;
+ uword 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);
+
+ if (sm->deterministic)
+ {
+ sm->in2out_node_index = snat_det_in2out_node.index;
+ sm->in2out_output_node_index = ~0;
+ sm->out2in_node_index = snat_det_out2in_node.index;
+ sm->icmp_match_in2out_cb = icmp_match_in2out_det;
+ sm->icmp_match_out2in_cb = icmp_match_out2in_det;
+ }
+ else
+ {
+ if (sm->endpoint_dependent)
+ {
+ sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
+ sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
+
+ sm->handoff_out2in_index = nat_pre_out2in_node.index;
+ sm->handoff_in2out_index = nat_pre_in2out_node.index;
+ sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
+
+ sm->in2out_node_index = nat44_ed_in2out_node.index;
+ sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
+ sm->out2in_node_index = nat44_ed_out2in_node.index;
+
+ sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
+ sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
+ nat_affinity_init (vm);
+ nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
+ nat_ha_sref_ed_cb);
+ }
+ else
+ {
+ sm->worker_in2out_cb = snat_get_worker_in2out_cb;
+ sm->worker_out2in_cb = snat_get_worker_out2in_cb;
+
+ sm->handoff_out2in_index = snat_out2in_node.index;
+ sm->handoff_in2out_index = snat_in2out_node.index;
+ sm->handoff_in2out_output_index = snat_in2out_output_node.index;
+
+ sm->in2out_node_index = snat_in2out_node.index;
+ sm->in2out_output_node_index = snat_in2out_output_node.index;
+ sm->out2in_node_index = snat_out2in_node.index;
+ sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
+ sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
+ nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
+ }
+ if (!static_mapping_only ||
+ (static_mapping_only && static_mapping_connection_tracking))
+ {
+ /* *INDENT-OFF* */
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ tsm->min_session_timeout = 0;
+
+ tsm->cleared = 0;
+ tsm->cleanup_runs = 0;
+ tsm->cleanup_timeout = 0;
+
+ pool_alloc (tsm->sessions, sm->max_translations);
+ pool_alloc (tsm->list_pool, sm->max_translations);
+ pool_alloc (tsm->global_lru_pool, sm->max_translations);
+
+ dlist_elt_t *head;
+ pool_get (tsm->global_lru_pool, head);
+ tsm->global_lru_head_index = head - tsm->global_lru_pool;
+ clib_dlist_init (tsm->global_lru_pool,
+ tsm->global_lru_head_index);
+
+ if (sm->endpoint_dependent)
+ {
+ clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
+ translation_buckets,
+ translation_memory_size);
+ clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
+ format_ed_session_kvp);
+
+ clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
+ translation_buckets,
+ translation_memory_size);
+ clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
+ format_ed_session_kvp);
+ clib_bihash_init_16_8
+ (&sm->ed_ext_ports, "ed-nat-5-tuple-port-overload-hash",
+ translation_buckets, translation_memory_size);
+ }
+ else
+ {
+ clib_bihash_init_8_8 (&tsm->in2out, "in2out",
+ translation_buckets,
+ translation_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
+ format_session_kvp);
+
+ clib_bihash_init_8_8 (&tsm->out2in, "out2in",
+ translation_buckets,
+ translation_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
+ format_session_kvp);
+ }
+
+ clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
+ user_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
+ format_user_kvp);
+ }
+ /* *INDENT-ON* */
+
+ }
+ else
+ {
+ sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
+ sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
+ }
+ clib_bihash_init_8_8 (&sm->static_mapping_by_local,
+ "static_mapping_by_local", static_mapping_buckets,
+ static_mapping_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
+ format_static_mapping_kvp);
+
+ clib_bihash_init_8_8 (&sm->static_mapping_by_external,
+ "static_mapping_by_external",
+ static_mapping_buckets,
+ static_mapping_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
+ format_static_mapping_kvp);
+ }
+
+ return 0;
+}
+
+VLIB_CONFIG_FUNCTION (snat_config, "nat");
+
+static void
+nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
+ uword opaque,
+ u32 sw_if_index,
+ ip4_address_t * address,
+ u32 address_length,
+ u32 if_address_index, u32 is_delete)
+{
+ snat_main_t *sm = &snat_main;
+ snat_static_map_resolve_t *rp;
+ snat_static_mapping_t *m;
+ snat_session_key_t m_key;
+ clib_bihash_kv_8_8_t kv, value;
+ int i, rv;
+ ip4_address_t l_addr;
+
+ for (i = 0; i < vec_len (sm->to_resolve); i++)
+ {
+ rp = sm->to_resolve + i;
+ if (rp->addr_only == 0)
+ continue;
+ if (rp->sw_if_index == sw_if_index)
+ goto match;
+ }
+
+ return;
+
+match:
+ m_key.addr.as_u32 = address->as_u32;
+ m_key.port = rp->addr_only ? 0 : rp->e_port;
+ m_key.protocol = rp->addr_only ? 0 : rp->proto;
+ m_key.fib_index = sm->outside_fib_index;
+ kv.key = m_key.as_u64;
+ if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
+ m = 0;
+ else
+ m = pool_elt_at_index (sm->static_mappings, value.value);
+
+ if (!is_delete)
+ {
+ /* Don't trip over lease renewal, static config */
+ if (m)
+ return;
+ }
+ else
+ {
+ if (!m)
+ return;
+ }
+
+ /* Indetity mapping? */
+ if (rp->l_addr.as_u32 == 0)
+ l_addr.as_u32 = address[0].as_u32;
+ else
+ l_addr.as_u32 = rp->l_addr.as_u32;
+ /* Add the static mapping */
+ rv = snat_add_static_mapping (l_addr,
+ address[0],
+ rp->l_port,
+ rp->e_port,
+ rp->vrf_id,
+ rp->addr_only, ~0 /* sw_if_index */ ,
+ rp->proto, !is_delete, rp->twice_nat,
+ rp->out2in_only, rp->tag, rp->identity_nat);
+ if (rv)
+ nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);