X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fnat.c;h=c2c812d114b48f8e3db152964e7ae80555074fe4;hb=fd0d50879f475a1b15cedb4ab49059a02c45ccfd;hp=efca4404dddc026725d4424092bac8d07a7d8da3;hpb=ab395ec884d0ec9279893b1695379e97acd1f24d;p=vpp.git diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index efca4404ddd..c2c812d114b 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -236,6 +237,13 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) ed_kv.key[1] = ed_key.as_u64[1]; if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)) nat_log_warn ("in2out_ed key del failed"); + + nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index, + &s->in2out.addr, s->in2out.port, + &s->ext_host_nat_addr, s->ext_host_nat_port, + &s->out2in.addr, s->out2in.port, + &s->ext_host_addr, s->ext_host_port, + s->in2out.protocol, is_twice_nat_session (s)); } else { @@ -245,6 +253,11 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) kv.key = s->out2in.as_u64; if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0)) nat_log_warn ("out2in key del failed"); + + nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index, + &s->in2out.addr, s->in2out.port, + &s->out2in.addr, s->out2in.port, + s->in2out.protocol); } if (snat_is_unk_proto_session (s)) @@ -293,7 +306,7 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index, { /* no, make a new one */ pool_get (tsm->users, u); - memset (u, 0, sizeof (*u)); + clib_memset (u, 0, sizeof (*u)); u->addr.as_u32 = addr->as_u32; u->fib_index = fib_index; @@ -309,6 +322,9 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index, /* add user */ if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1)) nat_log_warn ("user_hash keay add failed"); + + vlib_set_simple_counter (&sm->total_users, thread_index, 0, + pool_elts (tsm->users)); } else { @@ -368,7 +384,7 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u, else { pool_get (tsm->sessions, s); - memset (s, 0, sizeof (*s)); + clib_memset (s, 0, sizeof (*s)); /* Create list elts */ pool_get (tsm->list_pool, per_user_translation_list_elt); @@ -382,42 +398,88 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u, clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, per_user_translation_list_elt - tsm->list_pool); + + s->user_index = u - tsm->users; + vlib_set_simple_counter (&sm->total_sessions, thread_index, 0, + pool_elts (tsm->sessions)); } return s; } snat_session_t * -nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index) +nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index, + f64 now) { snat_session_t *s; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - dlist_elt_t *per_user_translation_list_elt; + dlist_elt_t *per_user_translation_list_elt, *oldest_elt; + u32 oldest_index; + u64 sess_timeout_time; - if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user) + if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions))) + goto alloc_new; + + oldest_index = + clib_dlist_remove_head (tsm->list_pool, + u->sessions_per_user_list_head_index); + oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index); + s = pool_elt_at_index (tsm->sessions, oldest_elt->value); + sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s); + if (now >= sess_timeout_time) { - nat_log_warn ("max translations per user %U", format_ip4_address, - &u->addr); - snat_ipfix_logging_max_entries_per_user (sm->max_translations_per_user, - u->addr.as_u32); - return 0; + clib_dlist_addtail (tsm->list_pool, + u->sessions_per_user_list_head_index, oldest_index); + nat_free_session_data (sm, s, thread_index); + if (snat_is_session_static (s)) + u->nstaticsessions--; + else + u->nsessions--; + s->flags = 0; + s->total_bytes = 0; + s->total_pkts = 0; + s->state = 0; + s->ext_host_addr.as_u32 = 0; + s->ext_host_port = 0; + s->ext_host_nat_addr.as_u32 = 0; + s->ext_host_nat_port = 0; } + else + { + clib_dlist_addhead (tsm->list_pool, + u->sessions_per_user_list_head_index, oldest_index); + if ((u->nsessions + u->nstaticsessions) >= + sm->max_translations_per_user) + { + nat_log_warn ("max translations per user %U", format_ip4_address, + &u->addr); + snat_ipfix_logging_max_entries_per_user + (sm->max_translations_per_user, u->addr.as_u32); + return 0; + } + else + { + alloc_new: + pool_get (tsm->sessions, s); + clib_memset (s, 0, sizeof (*s)); + + /* Create list elts */ + pool_get (tsm->list_pool, per_user_translation_list_elt); + clib_dlist_init (tsm->list_pool, + per_user_translation_list_elt - tsm->list_pool); + + per_user_translation_list_elt->value = s - tsm->sessions; + s->per_user_index = per_user_translation_list_elt - tsm->list_pool; + s->per_user_list_head_index = u->sessions_per_user_list_head_index; + + clib_dlist_addtail (tsm->list_pool, + s->per_user_list_head_index, + per_user_translation_list_elt - tsm->list_pool); + } - pool_get (tsm->sessions, s); - memset (s, 0, sizeof (*s)); - - /* Create list elts */ - pool_get (tsm->list_pool, per_user_translation_list_elt); - clib_dlist_init (tsm->list_pool, - per_user_translation_list_elt - tsm->list_pool); - - per_user_translation_list_elt->value = s - tsm->sessions; - s->per_user_index = per_user_translation_list_elt - tsm->list_pool; - s->per_user_list_head_index = u->sessions_per_user_list_head_index; - - clib_dlist_addtail (tsm->list_pool, - s->per_user_list_head_index, - per_user_translation_list_elt - tsm->list_pool); + vlib_set_simple_counter (&sm->total_sessions, thread_index, 0, + pool_elts (tsm->sessions)); + } return s; } @@ -522,6 +584,10 @@ is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr) /* *INDENT-OFF* */ pool_foreach (m, sm->static_mappings, ({ + if (is_addr_only_static_mapping (m) || + is_out2in_only_static_mapping (m) || + is_identity_static_mapping (m)) + continue; if (m->external_addr.as_u32 == addr.as_u32) return 1; })); @@ -547,7 +613,9 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, u16 e_port, u32 vrf_id, snat_protocol_t proto, - int addr_only, int is_add, u8 * tag) + int addr_only, int is_add, u8 * tag, + int twice_nat, int out2in_only, + int identity_nat) { snat_static_map_resolve_t *rp; @@ -560,6 +628,9 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, rp->proto = proto; rp->addr_only = addr_only; rp->is_add = is_add; + rp->twice_nat = twice_nat; + rp->out2in_only = out2in_only; + rp->identity_nat = identity_nat; rp->tag = vec_dup (tag); } @@ -577,34 +648,12 @@ get_thread_idx_by_port (u16 e_port) return thread_idx; } -/** - * @brief Add static mapping. - * - * Create static mapping between local addr+port and external addr+port. - * - * @param l_addr Local IPv4 address. - * @param e_addr External IPv4 address. - * @param l_port Local port number. - * @param e_port External port number. - * @param vrf_id VRF ID. - * @param addr_only If 0 address port and pair mapping, otherwise address only. - * @param sw_if_index External port instead of specific IP address. - * @param is_add If 0 delete static mapping, otherwise add. - * @param twice_nat If value is TWICE_NAT then translate external host address - * and port. - * If value is TWICE_NAT_SELF then translate external host - * address and port whenever external host address equals - * local address of internal host. - * @param out2in_only If 1 rule match only out2in direction - * @param tag - opaque string tag - * - * @returns - */ int snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, u32 sw_if_index, snat_protocol_t proto, int is_add, - twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag) + twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag, + u8 identity_nat) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; @@ -612,7 +661,6 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, clib_bihash_kv_8_8_t kv, value; snat_address_t *a = 0; u32 fib_index = ~0; - uword *p; snat_interface_t *interface; int i; snat_main_per_thread_data_t *tsm; @@ -624,6 +672,8 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, u64 user_index; snat_session_t *s; snat_static_map_resolve_t *rp, *rp_match = 0; + nat44_lb_addr_port_t *local; + u32 find = ~0; if (!sm->endpoint_dependent) { @@ -666,7 +716,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, snat_add_static_mapping_when_resolved (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto, - addr_only, is_add, tag); + addr_only, is_add, tag, twice_nat, out2in_only, identity_nat); /* DHCP resolution required? */ if (first_int_addr == 0) @@ -713,19 +763,42 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (is_add) { if (m) - return VNET_API_ERROR_VALUE_EXIST; + { + if (is_identity_static_mapping (m)) + { + /* *INDENT-OFF* */ + pool_foreach (local, m->locals, + ({ + if (local->vrf_id == vrf_id) + return VNET_API_ERROR_VALUE_EXIST; + })); + /* *INDENT-ON* */ + pool_get (m->locals, local); + local->vrf_id = vrf_id; + local->fib_index = + fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, + FIB_SOURCE_PLUGIN_LOW); + m_key.addr = m->local_addr; + m_key.port = m->local_port; + m_key.protocol = m->proto; + m_key.fib_index = local->fib_index; + kv.key = m_key.as_u64; + kv.value = m - sm->static_mappings; + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); + return 0; + } + else + return VNET_API_ERROR_VALUE_EXIST; + } if (twice_nat && addr_only) return VNET_API_ERROR_UNSUPPORTED; /* Convert VRF id to FIB index */ if (vrf_id != ~0) - { - p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id); - if (!p) - return VNET_API_ERROR_NO_SUCH_FIB; - fib_index = p[0]; - } + fib_index = + fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, + FIB_SOURCE_PLUGIN_LOW); /* If not specified use inside VRF id from SNAT plugin startup config */ else { @@ -733,7 +806,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, vrf_id = sm->inside_vrf_id; } - if (!out2in_only) + if (!(out2in_only || identity_nat)) { m_key.addr = l_addr; m_key.port = addr_only ? 0 : l_port; @@ -802,15 +875,27 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, } pool_get (sm->static_mappings, m); - memset (m, 0, sizeof (*m)); + clib_memset (m, 0, sizeof (*m)); m->tag = vec_dup (tag); m->local_addr = l_addr; m->external_addr = e_addr; - m->addr_only = addr_only; - m->vrf_id = vrf_id; - m->fib_index = fib_index; m->twice_nat = twice_nat; - m->out2in_only = out2in_only; + if (out2in_only) + m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY; + if (addr_only) + m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY; + if (identity_nat) + { + m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT; + pool_get (m->locals, local); + local->vrf_id = vrf_id; + local->fib_index = fib_index; + } + else + { + m->vrf_id = vrf_id; + m->fib_index = fib_index; + } if (!addr_only) { m->local_port = l_port; @@ -832,7 +917,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, m_key.addr = m->local_addr; m_key.port = m->local_port; m_key.protocol = m->proto; - m_key.fib_index = m->fib_index; + m_key.fib_index = fib_index; kv.key = m_key.as_u64; kv.value = m - sm->static_mappings; if (!out2in_only) @@ -897,6 +982,28 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, return VNET_API_ERROR_NO_SUCH_ENTRY; } + if (identity_nat) + { + if (vrf_id == ~0) + vrf_id = sm->inside_vrf_id; + + /* *INDENT-OFF* */ + pool_foreach (local, m->locals, + ({ + if (local->vrf_id == vrf_id) + find = local - m->locals; + })); + /* *INDENT-ON* */ + if (find == ~0) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + local = pool_elt_at_index (m->locals, find); + fib_index = local->fib_index; + pool_put (m->locals, local); + } + else + fib_index = m->fib_index; + /* Free external address port */ if (!(addr_only || sm->static_mapping_only || out2in_only)) { @@ -935,23 +1042,17 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, m_key.addr = m->local_addr; m_key.port = m->local_port; m_key.protocol = m->proto; - m_key.fib_index = m->fib_index; + m_key.fib_index = fib_index; kv.key = m_key.as_u64; if (!out2in_only) clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0); - m_key.addr = m->external_addr; - m_key.port = m->external_port; - m_key.fib_index = 0; - kv.key = m_key.as_u64; - clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0); - /* Delete session(s) for static mapping if exist */ if (!(sm->static_mapping_only) || (sm->static_mapping_only && sm->static_mapping_connection_tracking)) { u_key.addr = m->local_addr; - u_key.fib_index = m->fib_index; + u_key.fib_index = fib_index; kv.key = u_key.as_u64; if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { @@ -995,6 +1096,16 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, } } + fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW); + if (pool_elts (m->locals)) + return 0; + + m_key.addr = m->external_addr; + m_key.port = m->external_port; + m_key.fib_index = 0; + kv.key = m_key.as_u64; + clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0); + vec_free (m->tag); vec_free (m->workers); /* Delete static mapping from pool */ @@ -1108,14 +1219,15 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, } pool_get (sm->static_mappings, m); - memset (m, 0, sizeof (*m)); + clib_memset (m, 0, sizeof (*m)); m->tag = vec_dup (tag); m->external_addr = e_addr; - m->addr_only = 0; m->external_port = e_port; m->proto = proto; m->twice_nat = twice_nat; - m->out2in_only = out2in_only; + m->flags |= NAT_STATIC_MAPPING_FLAG_LB; + if (out2in_only) + m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY; m->affinity = affinity; if (affinity) @@ -1154,7 +1266,8 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, } locals[i].prefix = (i == 0) ? locals[i].probability : (locals[i - 1].prefix + locals[i].probability); - vec_add1 (m->locals, locals[i]); + pool_get (m->locals, local); + *local = locals[i]; if (sm->num_workers > 1) { ip4_header_t ip = { @@ -1182,6 +1295,9 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (!m) return VNET_API_ERROR_NO_SUCH_ENTRY; + if (!is_lb_static_mapping (m)) + return VNET_API_ERROR_INVALID_VALUE; + /* Free external address port */ if (!(sm->static_mapping_only || out2in_only)) { @@ -1224,8 +1340,8 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, } /* *INDENT-OFF* */ - vec_foreach (local, m->locals) - { + pool_foreach (local, m->locals, + ({ fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW); m_key.addr = local->addr; @@ -1254,7 +1370,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, /* Delete sessions */ u_key.addr = local->addr; - u_key.fib_index = m->fib_index; + u_key.fib_index = local->fib_index; kv.key = u_key.as_u64; if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) { @@ -1284,11 +1400,11 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, } } } - } + })); /* *INDENT-ON* */ if (m->affinity) nat_affinity_flush_service (m->affinity_per_service_list_head_index); - vec_free (m->locals); + pool_free (m->locals); vec_free (m->tag); vec_free (m->workers); @@ -1298,6 +1414,187 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, return 0; } +int +nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port, + ip4_address_t l_addr, u16 l_port, + snat_protocol_t proto, u32 vrf_id, + u8 probability, u8 is_add) +{ + snat_main_t *sm = &snat_main; + snat_static_mapping_t *m = 0; + snat_session_key_t m_key; + clib_bihash_kv_8_8_t kv, value; + nat44_lb_addr_port_t *local, *prev_local, *match_local = 0; + snat_main_per_thread_data_t *tsm; + snat_user_key_t u_key; + snat_user_t *u; + snat_session_t *s; + dlist_elt_t *head, *elt; + u32 elt_index, head_index, ses_index, *locals = 0; + uword *bitmap = 0; + int i; + + if (!sm->endpoint_dependent) + return VNET_API_ERROR_FEATURE_DISABLED; + + m_key.addr = e_addr; + m_key.port = e_port; + m_key.protocol = proto; + m_key.fib_index = 0; + 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); + + if (!m) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + if (!is_lb_static_mapping (m)) + return VNET_API_ERROR_INVALID_VALUE; + + /* *INDENT-OFF* */ + pool_foreach (local, m->locals, + ({ + if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) && + (local->vrf_id == vrf_id)) + { + match_local = local; + break; + } + })); + /* *INDENT-ON* */ + + if (is_add) + { + if (match_local) + return VNET_API_ERROR_VALUE_EXIST; + + pool_get (m->locals, local); + clib_memset (local, 0, sizeof (*local)); + local->addr.as_u32 = l_addr.as_u32; + local->port = l_port; + local->probability = probability; + local->vrf_id = vrf_id; + local->fib_index = + fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, + FIB_SOURCE_PLUGIN_LOW); + + if (!is_out2in_only_static_mapping (m)) + { + m_key.addr = l_addr; + m_key.port = l_port; + m_key.fib_index = local->fib_index; + kv.key = m_key.as_u64; + kv.value = m - sm->static_mappings; + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1)) + nat_log_err ("static_mapping_by_local key add failed"); + } + } + else + { + if (!match_local) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + if (pool_elts (m->locals) < 3) + return VNET_API_ERROR_UNSPECIFIED; + + fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4, + FIB_SOURCE_PLUGIN_LOW); + + if (!is_out2in_only_static_mapping (m)) + { + m_key.addr = l_addr; + m_key.port = l_port; + m_key.fib_index = match_local->fib_index; + kv.key = m_key.as_u64; + if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0)) + nat_log_err ("static_mapping_by_local key del failed"); + } + + if (sm->num_workers > 1) + { + ip4_header_t ip = { + .src_address = local->addr, + }; + tsm = vec_elt_at_index (sm->per_thread_data, + sm->worker_in2out_cb (&ip, m->fib_index)); + } + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + + /* Delete sessions */ + u_key.addr = match_local->addr; + u_key.fib_index = match_local->fib_index; + kv.key = u_key.as_u64; + if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) + { + u = pool_elt_at_index (tsm->users, value.value); + if (u->nstaticsessions) + { + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (tsm->list_pool, head_index); + elt_index = head->next; + elt = pool_elt_at_index (tsm->list_pool, elt_index); + ses_index = elt->value; + while (ses_index != ~0) + { + s = pool_elt_at_index (tsm->sessions, ses_index); + elt = pool_elt_at_index (tsm->list_pool, elt->next); + ses_index = elt->value; + + if (!(is_lb_session (s))) + continue; + + if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) || + (clib_net_to_host_u16 (s->in2out.port) != + match_local->port)) + continue; + + nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat44_delete_session (sm, s, tsm - sm->per_thread_data); + } + } + } + + pool_put (m->locals, match_local); + } + + vec_free (m->workers); + + /* *INDENT-OFF* */ + pool_foreach (local, m->locals, + ({ + vec_add1 (locals, local - m->locals); + if (sm->num_workers > 1) + { + ip4_header_t ip; + ip.src_address.as_u32 = local->addr.as_u32, + bitmap = clib_bitmap_set (bitmap, + sm->worker_in2out_cb (&ip, local->fib_index), + 1); + } + })); + /* *INDENT-ON* */ + + local = pool_elt_at_index (m->locals, locals[0]); + local->prefix = local->probability; + for (i = 1; i < vec_len (locals); i++) + { + local = pool_elt_at_index (m->locals, locals[i]); + prev_local = pool_elt_at_index (m->locals, locals[i - 1]); + local->prefix = local->probability + prev_local->prefix; + } + + /* Assign workers */ + if (sm->num_workers > 1) + { + /* *INDENT-OFF* */ + clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); })); + /* *INDENT-ON* */ + } + + return 0; +} + int snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm, u8 twice_nat) @@ -1332,9 +1629,9 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm, if (m->external_addr.as_u32 == addr.as_u32) (void) snat_add_static_mapping (m->local_addr, m->external_addr, m->local_port, m->external_port, - m->vrf_id, m->addr_only, ~0, + m->vrf_id, is_addr_only_static_mapping(m), ~0, m->proto, 0, m->twice_nat, - m->out2in_only, m->tag); + is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m)); })); /* *INDENT-ON* */ } @@ -1646,7 +1943,7 @@ fib: pool_foreach (m, sm->static_mappings, ({ - if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32)) + if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32)) continue; snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); @@ -1774,7 +2071,7 @@ fib: pool_foreach (m, sm->static_mappings, ({ - if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32)) + if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32)) continue; snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); @@ -1918,6 +2215,16 @@ snat_init (vlib_main_t * vm) nat_dpo_module_init (); + /* Init counters */ + sm->total_users.name = "total-users"; + sm->total_users.stat_segment_name = "/nat44/total-users"; + vlib_validate_simple_counter (&sm->total_users, 0); + vlib_zero_simple_counter (&sm->total_users, 0); + sm->total_sessions.name = "total-sessions"; + sm->total_sessions.stat_segment_name = "/nat44/total-sessions"; + vlib_validate_simple_counter (&sm->total_sessions, 0); + vlib_zero_simple_counter (&sm->total_sessions, 0); + /* Init IPFIX logging */ snat_ipfix_logging_init (vm); @@ -1981,14 +2288,16 @@ snat_static_mapping_match (snat_main_t * sm, u8 by_external, u8 * is_addr_only, twice_nat_type_t * twice_nat, - lb_nat_type_t * lb, ip4_address_t * ext_host_addr) + lb_nat_type_t * lb, ip4_address_t * ext_host_addr, + u8 * is_identity_nat) { clib_bihash_kv_8_8_t kv, value; snat_static_mapping_t *m; snat_session_key_t m_key; clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; - u32 rand, lo = 0, hi, mid; + u32 rand, lo = 0, hi, mid, *tmp = 0, i; u8 backend_index; + nat44_lb_addr_port_t *local; m_key.fib_index = match.fib_index; if (by_external) @@ -2017,7 +2326,7 @@ snat_static_mapping_match (snat_main_t * sm, if (by_external) { - if (vec_len (m->locals)) + if (is_lb_static_mapping (m)) { if (PREDICT_FALSE (lb != 0)) *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT; @@ -2028,42 +2337,52 @@ snat_static_mapping_match (snat_main_t * sm, &backend_index)) goto get_local; - mapping->addr = m->locals[backend_index].addr; - mapping->port = - clib_host_to_net_u16 (m->locals[backend_index].port); - mapping->fib_index = m->locals[backend_index].fib_index; + local = pool_elt_at_index (m->locals, backend_index); + mapping->addr = local->addr; + mapping->port = clib_host_to_net_u16 (local->port); + mapping->fib_index = local->fib_index; goto end; } get_local: - hi = vec_len (m->locals) - 1; - rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix); + /* *INDENT-OFF* */ + pool_foreach_index (i, m->locals, + ({ + vec_add1 (tmp, i); + })); + /* *INDENT-ON* */ + hi = vec_len (tmp) - 1; + local = pool_elt_at_index (m->locals, tmp[hi]); + rand = 1 + (random_u32 (&sm->random_seed) % local->prefix); while (lo < hi) { mid = ((hi - lo) >> 1) + lo; - (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid); + local = pool_elt_at_index (m->locals, tmp[mid]); + (rand > local->prefix) ? (lo = mid + 1) : (hi = mid); } - if (!(m->locals[lo].prefix >= rand)) + local = pool_elt_at_index (m->locals, tmp[lo]); + if (!(local->prefix >= rand)) return 1; if (PREDICT_FALSE (sm->num_workers > 1)) { ip4_header_t ip = { - .src_address = m->locals[lo].addr, + .src_address = local->addr, }; if (sm->worker_in2out_cb (&ip, m->fib_index) != vlib_get_thread_index ()) goto get_local; } - mapping->addr = m->locals[lo].addr; - mapping->port = clib_host_to_net_u16 (m->locals[lo].port); - mapping->fib_index = m->locals[lo].fib_index; + mapping->addr = local->addr; + mapping->port = clib_host_to_net_u16 (local->port); + mapping->fib_index = local->fib_index; if (m->affinity) { if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr, match.protocol, match.port, - lo, m->affinity, + tmp[lo], m->affinity, m->affinity_per_service_list_head_index)) nat_log_info ("create affinity record failed"); } + vec_free (tmp); } else { @@ -2072,7 +2391,7 @@ snat_static_mapping_match (snat_main_t * sm, mapping->fib_index = m->fib_index; mapping->addr = m->local_addr; /* Address only mapping doesn't change port */ - mapping->port = m->addr_only ? match.port + mapping->port = is_addr_only_static_mapping (m) ? match.port : clib_host_to_net_u16 (m->local_port); } mapping->protocol = m->proto; @@ -2081,18 +2400,21 @@ snat_static_mapping_match (snat_main_t * sm, { mapping->addr = m->external_addr; /* Address only mapping doesn't change port */ - mapping->port = m->addr_only ? match.port + mapping->port = is_addr_only_static_mapping (m) ? match.port : clib_host_to_net_u16 (m->external_port); mapping->fib_index = sm->outside_fib_index; } end: if (PREDICT_FALSE (is_addr_only != 0)) - *is_addr_only = m->addr_only; + *is_addr_only = is_addr_only_static_mapping (m); if (PREDICT_FALSE (twice_nat != 0)) *twice_nat = m->twice_nat; + if (PREDICT_FALSE (is_identity_nat != 0)) + *is_identity_nat = is_identity_static_mapping (m); + return 0; } @@ -2585,7 +2907,7 @@ nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index) (&sm->static_mapping_by_external, &kv, &value)) { m = pool_elt_at_index (sm->static_mappings, value.value); - if (!vec_len (m->locals)) + if (!is_lb_static_mapping (m)) return m->workers[0]; hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) + @@ -2883,7 +3205,8 @@ match: rp->e_port, rp->vrf_id, rp->addr_only, ~0 /* sw_if_index */ , - rp->proto, !is_delete, 0, 0, rp->tag); + rp->proto, !is_delete, rp->twice_nat, + rp->out2in_only, rp->tag, rp->identity_nat); if (rv) nat_log_notice ("snat_add_static_mapping returned %d", rv); } @@ -2952,7 +3275,9 @@ match: rp->addr_only, ~0 /* sw_if_index */ , rp->proto, - rp->is_add, 0, 0, rp->tag); + rp->is_add, rp->twice_nat, + rp->out2in_only, rp->tag, + rp->identity_nat); if (rv) nat_log_notice ("snat_add_static_mapping returned %d", rv); }