- u32 next_worker_index = 0;
-
- /* first try static mappings without port */
- if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
- {
- m_key.addr = ip0->dst_address;
- m_key.port = 0;
- m_key.protocol = 0;
- m_key.fib_index = rx_fib_index0;
- kv.key = m_key.as_u64;
- if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
- {
- m = pool_elt_at_index (sm->static_mappings, value.value);
- return m->worker_index;
- }
- }
-
- proto = ip_proto_to_snat_proto (ip0->protocol);
- udp = ip4_next_header (ip0);
- port = udp->dst_port;
-
- if (PREDICT_FALSE (ip4_is_fragment (ip0)))
- {
- if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
- return vlib_get_thread_index ();
-
- if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
- {
- nat_reass_ip4_t *reass;
-
- reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
- ip0->fragment_id, ip0->protocol);
-
- if (reass && (reass->thread_index != (u32) ~ 0))
- return reass->thread_index;
- else
- return vlib_get_thread_index ();
- }
- }
-
- /* unknown protocol */
- if (PREDICT_FALSE (proto == ~0))
- {
- key.l_addr = ip0->dst_address;
- key.r_addr = ip0->src_address;
- key.fib_index = rx_fib_index0;
- key.proto = ip0->protocol;
- key.r_port = 0;
- key.l_port = 0;
- s_kv.key[0] = key.as_u64[0];
- s_kv.key[1] = key.as_u64[1];
-
- if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
- {
- for (i = 0; i < _vec_len (sm->per_thread_data); i++)
- {
- tsm = vec_elt_at_index (sm->per_thread_data, i);
- if (!pool_is_free_index(tsm->sessions, s_value.value))
- {
- s = pool_elt_at_index (tsm->sessions, s_value.value);
- if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
- s->out2in.port == ip0->protocol &&
- snat_is_unk_proto_session (s))
- return i;
- }
- }
- }
-
- /* if no session use current thread */
- return vlib_get_thread_index ();
- }
-
- if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
- {
- icmp46_header_t * icmp = (icmp46_header_t *) udp;
- icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
- if (!icmp_is_error_message (icmp))
- port = echo->identifier;
- else
- {
- ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
- proto = ip_proto_to_snat_proto (inner_ip->protocol);
- void *l4_header = ip4_next_header (inner_ip);
- switch (proto)
- {
- case SNAT_PROTOCOL_ICMP:
- icmp = (icmp46_header_t*)l4_header;
- echo = (icmp_echo_header_t *)(icmp + 1);
- port = echo->identifier;
- break;
- case SNAT_PROTOCOL_UDP:
- case SNAT_PROTOCOL_TCP:
- port = ((tcp_udp_header_t*)l4_header)->src_port;
- break;
- default:
- return vlib_get_thread_index ();
- }
- }
- }
-
- /* try static mappings with port */
- if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
- {
- m_key.addr = ip0->dst_address;
- m_key.port = clib_net_to_host_u16 (port);
- m_key.protocol = proto;
- m_key.fib_index = rx_fib_index0;
- kv.key = m_key.as_u64;
- if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
- {
- m = pool_elt_at_index (sm->static_mappings, value.value);
- return m->worker_index;
- }
- }
-
- /* worker by outside port */
- next_worker_index = sm->first_worker_index;
- next_worker_index +=
- sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
- return next_worker_index;
-}
-
-static clib_error_t *
-snat_config (vlib_main_t * vm, unformat_input_t * input)
-{
- snat_main_t * sm = &snat_main;
- u32 translation_buckets = 1024;
- u32 translation_memory_size = 128<<20;
- u32 user_buckets = 128;
- u32 user_memory_size = 64<<20;
- u32 max_translations_per_user = 100;
- u32 outside_vrf_id = 0;
- u32 inside_vrf_id = 0;
- 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;
- u8 static_mapping_only = 0;
- u8 static_mapping_connection_tracking = 0;
- snat_main_per_thread_data_t *tsm;
- dslite_main_t * dm = &dslite_main;
-
- sm->deterministic = 0;
- sm->out2in_dpo = 0;
-
- while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (input, "translation hash buckets %d", &translation_buckets))
- ;
- 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, "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
- return clib_error_return (0, "unknown input '%U'",
- format_unformat_error, input);
- }
-
- /* for show commands, etc. */
- 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->user_buckets = user_buckets;
- sm->user_memory_size = user_memory_size;
- sm->max_translations_per_user = 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,
- FIB_SOURCE_PLUGIN_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,
- FIB_SOURCE_PLUGIN_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
- {
- sm->worker_in2out_cb = snat_get_worker_in2out_cb;
- sm->worker_out2in_cb = snat_get_worker_out2in_cb;
- 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;
- if (!static_mapping_only ||
- (static_mapping_only && static_mapping_connection_tracking))
- {
- sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
- sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
-
- vec_foreach (tsm, sm->per_thread_data)
- {
- clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
- translation_memory_size);
-
- clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
- translation_memory_size);
-
- clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
- user_memory_size);
- }
-
- clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
- translation_buckets, translation_memory_size);
-
- clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
- translation_buckets, translation_memory_size);
- }
- 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_init_8_8 (&sm->static_mapping_by_external,
- "static_mapping_by_external", static_mapping_buckets,
- static_mapping_memory_size);
- }
-
- return 0;
-}
-
-VLIB_CONFIG_FUNCTION (snat_config, "nat");
-
-u8 * format_snat_session_state (u8 * s, va_list * args)
-{
- u32 i = va_arg (*args, u32);
- u8 *t = 0;
-
- switch (i)
- {
-#define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
- foreach_snat_session_state
-#undef _
- default:
- t = format (t, "unknown");
- }
- s = format (s, "%s", t);
- return s;
-}
-
-u8 * format_snat_key (u8 * s, va_list * args)
-{
- snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
-
- s = format (s, "%U proto %U port %d fib %d",
- format_ip4_address, &key->addr,
- format_snat_protocol, key->protocol,
- clib_net_to_host_u16 (key->port), key->fib_index);
- return s;
-}
-
-u8 * format_snat_session (u8 * s, va_list * args)
-{
- snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
- snat_session_t * sess = va_arg (*args, snat_session_t *);