From 68d7c546fa7e6c801031f2922c9be067d64e0f59 Mon Sep 17 00:00:00 2001 From: Filip Varga Date: Mon, 21 Dec 2020 18:20:00 +0100 Subject: nat: refactor and split fo EI/ED features p.2 Patch n. 2 aimed at moving EI features out of NAT44 plugin & split of EI/ED functions. Type: refactor Change-Id: Ida20c1c084449b146344b6c3d8442f49efb6f3fa Signed-off-by: Filip Varga --- src/plugins/nat/nat.c | 526 +++++++++---------- src/plugins/nat/nat.h | 44 +- src/plugins/nat/nat44-ei/nat44_ei.c | 787 ++++++++++++++++++++++++++++- src/plugins/nat/nat44-ei/nat44_ei.h | 98 +++- src/plugins/nat/nat44-ei/nat44_ei_in2out.c | 27 +- src/plugins/nat/nat44-ei/nat44_ei_out2in.c | 48 +- src/plugins/nat/nat44_api.c | 13 +- src/plugins/nat/nat44_cli.c | 24 +- 8 files changed, 1216 insertions(+), 351 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 156b6ddf369..81af143ab2c 100644 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -40,6 +40,39 @@ snat_main_t snat_main; +#define skip_if_disabled() \ + do \ + { \ + snat_main_t *sm = &snat_main; \ + if (PREDICT_FALSE (!sm->enabled)) \ + return; \ + } \ + while (0) + +#define fail_if_enabled() \ + do \ + { \ + snat_main_t *sm = &snat_main; \ + if (PREDICT_FALSE (sm->enabled)) \ + { \ + nat_log_err ("plugin enabled"); \ + return 1; \ + } \ + } \ + while (0) + +#define fail_if_disabled() \ + do \ + { \ + snat_main_t *sm = &snat_main; \ + if (PREDICT_FALSE (!sm->enabled)) \ + { \ + nat_log_err ("plugin disabled"); \ + return 1; \ + } \ + } \ + while (0) + /* *INDENT-OFF* */ /* Hook up input features */ VNET_FEATURE_INIT (nat_pre_in2out, static) = { @@ -181,6 +214,11 @@ VLIB_PLUGIN_REGISTER () = { }; /* *INDENT-ON* */ +static void nat44_ed_db_init (u32 translations, u32 translation_buckets, + u32 user_buckets); + +static void nat44_ed_db_free (); + static u32 nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip, u32 rx_fib_index, u8 is_output); @@ -189,7 +227,7 @@ static u32 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index, u8 is_output); -static u32 nat_calc_bihash_buckets (u32 n_elts); +u32 nat_calc_bihash_buckets (u32 n_elts); u8 * format_session_kvp (u8 * s, va_list * args) @@ -647,16 +685,11 @@ is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr) } static void -snat_add_static_mapping_when_resolved (snat_main_t * sm, - ip4_address_t l_addr, - u16 l_port, - u32 sw_if_index, - u16 e_port, - u32 vrf_id, - nat_protocol_t proto, - int addr_only, int is_add, u8 * tag, - int twice_nat, int out2in_only, - int identity_nat, +snat_add_static_mapping_when_resolved (snat_main_t *sm, ip4_address_t l_addr, + u16 l_port, u32 sw_if_index, u16 e_port, + u32 vrf_id, nat_protocol_t proto, + int addr_only, u8 *tag, int twice_nat, + int out2in_only, int identity_nat, ip4_address_t pool_addr, int exact) { snat_static_map_resolve_t *rp; @@ -669,7 +702,6 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, rp->vrf_id = vrf_id; 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; @@ -678,7 +710,7 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, rp->exact = exact; } -static u32 +u32 get_thread_idx_by_port (u16 e_port) { snat_main_t *sm = &snat_main; @@ -738,12 +770,14 @@ nat_ed_static_mapping_del_sessions (snat_main_t * sm, vec_free (indexes_to_free); } -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, nat_protocol_t proto, int is_add, - twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag, - u8 identity_nat, ip4_address_t pool_addr, int exact) +static_always_inline int +nat44_ed_add_del_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, + nat_protocol_t proto, int is_add, + twice_nat_type_t twice_nat, u8 out2in_only, + u8 *tag, u8 identity_nat, + ip4_address_t pool_addr, int exact) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; @@ -803,10 +837,9 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (rp_match) return VNET_API_ERROR_VALUE_EXIST; - snat_add_static_mapping_when_resolved - (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto, - addr_only, is_add, tag, twice_nat, out2in_only, - identity_nat, pool_addr, exact); + snat_add_static_mapping_when_resolved ( + sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto, addr_only, + tag, twice_nat, out2in_only, identity_nat, pool_addr, exact); /* DHCP resolution required? */ if (first_int_addr == 0) @@ -1002,10 +1035,12 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, else tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, - m - sm->static_mappings); if (!out2in_only) - clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); + { + init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, + m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); + } init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, m - sm->static_mappings); @@ -1183,6 +1218,31 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, return 0; } +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, nat_protocol_t proto, int is_add, + twice_nat_type_t twice_nat, u8 out2in_only, u8 *tag, + u8 identity_nat, ip4_address_t pool_addr, int exact) +{ + snat_main_t *sm = &snat_main; + int rv; + + if (sm->endpoint_dependent) + { + rv = nat44_ed_add_del_static_mapping ( + l_addr, e_addr, l_port, e_port, vrf_id, addr_only, sw_if_index, proto, + is_add, twice_nat, out2in_only, tag, identity_nat, pool_addr, exact); + } + else + { + rv = nat44_ei_add_del_static_mapping ( + l_addr, e_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only, + identity_nat, tag, is_add); + } + return rv; +} + int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, nat_protocol_t proto, @@ -2655,51 +2715,34 @@ nat_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (nat_init); -int -nat44_plugin_enable (nat44_config_t c) +static int +nat44_ed_plugin_enable (nat44_config_t c) { snat_main_t *sm = &snat_main; - u32 static_mapping_buckets = 1024; - u32 static_mapping_memory_size = 64 << 20; - if (sm->enabled) + if (c.static_mapping_only && !c.connection_tracking) { - nat_log_err ("nat44 is enabled"); + nat_log_err ("unsupported combination of configuration"); return 1; } - // c.static_mapping_only + c.connection_tracking - // - supported in NAT EI & NAT ED - // c.out2in_dpo, c.static_mapping_only - // - supported in NAT EI - - if (c.endpoint_dependent) - { - if ((c.static_mapping_only && !c.connection_tracking) || c.out2in_dpo) - { - nat_log_err ("unsupported combination of configuration"); - return 1; - } - if (c.users || c.user_sessions) - { - nat_log_err ("unsupported combination of configuration"); - return 1; - } - } - - nat_reset_timeouts (&sm->timeouts); - // nat44 feature configuration sm->endpoint_dependent = c.endpoint_dependent; sm->static_mapping_only = c.static_mapping_only; sm->static_mapping_connection_tracking = c.connection_tracking; + + // EI only feature (could break ED) sm->out2in_dpo = c.out2in_dpo; + sm->forwarding_enabled = 0; sm->mss_clamping = 0; + sm->pat = (!c.static_mapping_only || + (c.static_mapping_only && c.connection_tracking)); if (!c.users) c.users = 1024; + // EI only feature (could break ED) sm->max_users_per_thread = c.users; sm->user_buckets = nat_calc_bihash_buckets (c.users); @@ -2709,65 +2752,34 @@ nat44_plugin_enable (nat44_config_t c) sm->max_translations_per_thread = c.sessions; sm->translation_buckets = nat_calc_bihash_buckets (c.sessions); + // ED only feature vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread); + + // EI only feature (could break ED) sm->max_translations_per_user = c.user_sessions ? c.user_sessions : sm->max_translations_per_thread; - sm->outside_vrf_id = c.outside_vrf; - sm->outside_fib_index = - fib_table_find_or_create_and_lock - (FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi); - sm->inside_vrf_id = c.inside_vrf; sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, c.inside_vrf, sm->fib_src_hi); - if (c.endpoint_dependent) - { - sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb; - sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb; - sm->out2in_node_index = sm->ed_out2in_node_index; - sm->in2out_node_index = sm->ed_in2out_node_index; - sm->in2out_output_node_index = sm->ed_in2out_output_node_index; - sm->icmp_match_out2in_cb = icmp_match_out2in_ed; - sm->icmp_match_in2out_cb = icmp_match_in2out_ed; - - // try to move it into nat44_db_init, - // consider static mapping requirements - clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed", - sm->translation_buckets, 0); - clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, - format_ed_session_kvp); + sm->outside_vrf_id = c.outside_vrf; + sm->outside_fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi); - nat_affinity_enable (); - } - else - { - sm->worker_out2in_cb = nat44_ei_get_out2in_worker_index; - sm->worker_in2out_cb = nat44_ei_get_in2out_worker_index; + sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb; + sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb; - sm->out2in_node_index = sm->ei_out2in_node_index; - sm->in2out_node_index = sm->ei_in2out_node_index; - sm->in2out_output_node_index = sm->ei_in2out_output_node_index; - sm->icmp_match_out2in_cb = icmp_match_out2in_slow; - sm->icmp_match_in2out_cb = icmp_match_in2out_slow; + sm->in2out_node_index = sm->ed_in2out_node_index; + sm->out2in_node_index = sm->ed_out2in_node_index; - nat44_ei_plugin_enable (); - } + sm->in2out_output_node_index = sm->ed_in2out_output_node_index; - // c.static_mapping & c.connection_tracking require - // session database - if (!c.static_mapping_only - || (c.static_mapping_only && c.connection_tracking)) + if (sm->pat) { - snat_main_per_thread_data_t *tsm; - /* *INDENT-OFF* */ - vec_foreach (tsm, sm->per_thread_data) - { - nat44_db_init (tsm); - } - /* *INDENT-ON* */ + sm->icmp_match_in2out_cb = icmp_match_in2out_ed; + sm->icmp_match_out2in_cb = icmp_match_out2in_ed; } else { @@ -2775,19 +2787,14 @@ nat44_plugin_enable (nat44_config_t c) 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); + nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets, + sm->user_buckets); - 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); + nat_affinity_enable (); + + nat_reset_timeouts (&sm->timeouts); - // last: reset counters + // TODO: function for reset counters vlib_zero_simple_counter (&sm->total_users, 0); vlib_zero_simple_counter (&sm->total_sessions, 0); vlib_zero_simple_counter (&sm->user_limit_reached, 0); @@ -2798,6 +2805,43 @@ nat44_plugin_enable (nat44_config_t c) return 0; } +int +nat44_plugin_enable (nat44_config_t c) +{ + fail_if_enabled (); + + // c.static_mapping_only + c.connection_tracking + // - supported in NAT EI & NAT ED + // c.out2in_dpo, c.static_mapping_only + // - supported in NAT EI + + if (c.endpoint_dependent) + { + if (c.out2in_dpo || c.users || c.user_sessions) + { + nat_log_err ("unsupported combination of configuration"); + return 1; + } + return nat44_ed_plugin_enable (c); + } + + // separation: + // for now just copy variables + + nat44_ei_config_t ei_c = { + .inside_vrf = c.inside_vrf, + .outside_vrf = c.outside_vrf, + .users = c.users, + .sessions = c.sessions, + .user_sessions = c.user_sessions, + .out2in_dpo = c.out2in_dpo, + .static_mapping_only = c.static_mapping_only, + .connection_tracking = c.connection_tracking, + }; + + return nat44_ei_plugin_enable (ei_c); +} + void nat44_addresses_free (snat_address_t ** addresses) { @@ -2815,24 +2859,13 @@ nat44_addresses_free (snat_address_t ** addresses) *addresses = 0; } -int -nat44_plugin_disable () +static int +nat44_ed_plugin_disable () { snat_main_t *sm = &snat_main; snat_interface_t *i, *vec; int error = 0; - if (!sm->enabled) - { - nat_log_err ("nat44 is disabled"); - return 1; - } - - if (!sm->endpoint_dependent) - { - nat44_ei_plugin_disable (); - } - // first unregister all nodes from interfaces vec = vec_dup (sm->interfaces); /* *INDENT-OFF* */ @@ -2874,28 +2907,9 @@ nat44_plugin_disable () vec_free (sm->max_translations_per_fib); - if (sm->endpoint_dependent) - { - nat_affinity_disable (); - clib_bihash_free_16_8 (&sm->out2in_ed); - } - - clib_bihash_free_8_8 (&sm->static_mapping_by_local); - clib_bihash_free_8_8 (&sm->static_mapping_by_external); - - if (!sm->static_mapping_only || - (sm->static_mapping_only && sm->static_mapping_connection_tracking)) - { - snat_main_per_thread_data_t *tsm; - /* *INDENT-OFF* */ - vec_foreach (tsm, sm->per_thread_data) - { - nat44_db_free (tsm); - } - /* *INDENT-ON* */ - } + nat_affinity_disable (); - pool_free (sm->static_mappings); + nat44_ed_db_free (); nat44_addresses_free (&sm->addresses); nat44_addresses_free (&sm->twice_nat_addresses); @@ -2917,10 +2931,21 @@ nat44_plugin_disable () return 0; } +int +nat44_plugin_disable () +{ + snat_main_t *sm = &snat_main; + + fail_if_disabled (); + + if (sm->endpoint_dependent) + return nat44_ed_plugin_disable (); + return nat44_ei_plugin_disable (); +} + void -snat_free_outside_address_and_port (snat_address_t * addresses, - u32 thread_index, - ip4_address_t * addr, +snat_free_outside_address_and_port (snat_address_t *addresses, + u32 thread_index, ip4_address_t *addr, u16 port, nat_protocol_t protocol) { snat_address_t *a; @@ -3177,7 +3202,7 @@ nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add) } static u32 -nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index, +nat44_ed_get_worker_in2out_cb (ip4_header_t *ip, u32 rx_fib_index, u8 is_output) { snat_main_t *sm = &snat_main; @@ -3435,7 +3460,7 @@ done: return next_worker_index; } -static u32 +u32 nat_calc_bihash_buckets (u32 n_elts) { n_elts = n_elts / 2.5; @@ -3504,16 +3529,15 @@ nat44_update_session_limit (u32 session_limit, u32 vrf_id) return 0; } -void -nat44_db_init (snat_main_per_thread_data_t * tsm) +static void +nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations, + u32 translation_buckets, u32 user_buckets) { - 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_alloc (tsm->sessions, translations); + pool_alloc (tsm->lru_pool, translations); + 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); @@ -3534,87 +3558,122 @@ nat44_db_init (snat_main_per_thread_data_t * tsm) 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, 0); - clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed, - format_ed_session_kvp); - /* - clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed", - sm->translation_buckets, 0); - clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, - format_ed_session_kvp); */ - } - else - { - clib_bihash_init_8_8 (&tsm->in2out, "in2out", sm->translation_buckets, - 0); - clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp); - clib_bihash_init_8_8 (&tsm->out2in, "out2in", sm->translation_buckets, - 0); - clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp); - } + clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed", translation_buckets, 0); + clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed, format_ed_session_kvp); // TODO: ED nat is not using these // before removal large refactor required - pool_alloc (tsm->list_pool, sm->max_translations_per_thread); - clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets, 0); + pool_alloc (tsm->list_pool, translations); + clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, 0); 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) +static void +nat44_ed_db_init (u32 translations, u32 translation_buckets, u32 user_buckets) { snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + u32 static_mapping_buckets = 1024; + u32 static_mapping_memory_size = 64 << 20; - pool_free (tsm->sessions); - pool_free (tsm->lru_pool); + clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed", translation_buckets, 0); + clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, format_ed_session_kvp); - if (sm->endpoint_dependent) - { - clib_bihash_free_16_8 (&tsm->in2out_ed); - vec_free (tsm->per_vrf_sessions_vec); - } - else + 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); + + if (sm->pat) { - clib_bihash_free_8_8 (&tsm->in2out); - clib_bihash_free_8_8 (&tsm->out2in); + vec_foreach (tsm, sm->per_thread_data) + { + nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, + sm->translation_buckets, sm->user_buckets); + } } +} + +static void +nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm) +{ + pool_free (tsm->sessions); + pool_free (tsm->lru_pool); + + clib_bihash_free_16_8 (&tsm->in2out_ed); + vec_free (tsm->per_vrf_sessions_vec); // TODO: resolve static mappings (put only to !ED) - pool_free (tsm->users); pool_free (tsm->list_pool); + pool_free (tsm->users); clib_bihash_free_8_8 (&tsm->user_hash); } -void -nat44_sessions_clear () +static void +nat44_ed_db_free () { snat_main_t *sm = &snat_main; snat_main_per_thread_data_t *tsm; - if (sm->endpoint_dependent) + pool_free (sm->static_mappings); + clib_bihash_free_16_8 (&sm->out2in_ed); + clib_bihash_free_8_8 (&sm->static_mapping_by_local); + clib_bihash_free_8_8 (&sm->static_mapping_by_external); + + if (sm->pat) { - 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, 0); - clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, - format_ed_session_kvp); + vec_foreach (tsm, sm->per_thread_data) + { + nat44_ed_worker_db_free (tsm); + } } +} - /* *INDENT-OFF* */ - vec_foreach (tsm, sm->per_thread_data) +void +nat44_ed_sessions_clear () +{ + snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + + 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, 0); + clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, format_ed_session_kvp); + + if (sm->pat) { - nat44_db_free (tsm); - nat44_db_init (tsm); + vec_foreach (tsm, sm->per_thread_data) + { + + nat44_ed_worker_db_free (tsm); + nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, + sm->translation_buckets, sm->user_buckets); + } } - /* *INDENT-ON* */ + // TODO: function for reset counters vlib_zero_simple_counter (&sm->total_users, 0); vlib_zero_simple_counter (&sm->total_sessions, 0); + vlib_zero_simple_counter (&sm->user_limit_reached, 0); +} + +void +nat44_sessions_clear () +{ + snat_main_t *sm = &snat_main; + + if (sm->endpoint_dependent) + nat44_ed_sessions_clear (); + else + nat44_ei_sessions_clear (); } static void @@ -3744,18 +3803,11 @@ match: 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, - rp->is_add, rp->twice_nat, - rp->out2in_only, rp->tag, - rp->identity_nat, - rp->pool_addr, rp->exact); + 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, 1, + rp->twice_nat, rp->out2in_only, rp->tag, rp->identity_nat, + rp->pool_addr, rp->exact); if (rv) nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv); @@ -3838,44 +3890,6 @@ snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del, return 0; } -int -nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port, - nat_protocol_t proto, u32 vrf_id, int is_in) -{ - snat_main_per_thread_data_t *tsm; - clib_bihash_kv_8_8_t kv, value; - ip4_header_t ip; - u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); - snat_session_t *s; - clib_bihash_8_8_t *t; - - if (sm->endpoint_dependent) - return VNET_API_ERROR_UNSUPPORTED; - - ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; - if (sm->num_workers > 1) - tsm = - vec_elt_at_index (sm->per_thread_data, - sm->worker_in2out_cb (&ip, fib_index, 0)); - else - tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - - init_nat_k (&kv, *addr, port, fib_index, proto); - t = is_in ? &tsm->in2out : &tsm->out2in; - if (!clib_bihash_search_8_8 (t, &kv, &value)) - { - if (pool_is_free_index (tsm->sessions, value.value)) - return VNET_API_ERROR_UNSPECIFIED; - - s = pool_elt_at_index (tsm->sessions, value.value); - nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); - nat44_delete_session (sm, s, tsm - sm->per_thread_data); - return 0; - } - - return VNET_API_ERROR_NO_SUCH_ENTRY; -} - int nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port, ip4_address_t * eh_addr, u16 eh_port, u8 proto, diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index af40409d267..58883d491aa 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -427,7 +427,6 @@ typedef struct u32 flags; int addr_only; int twice_nat; - int is_add; int out2in_only; int identity_nat; int exact; @@ -729,6 +728,9 @@ typedef struct snat_main_s fib_source_t fib_src_hi; fib_source_t fib_src_low; + /* pat - dynamic mapping enabled or conneciton tracking */ + u8 pat; + /* nat44 plugin enabled */ u8 enabled; @@ -1297,20 +1299,6 @@ int snat_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside, int snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del, u8 twice_nat); -/** - * @brief Delete NAT44 session - * - * @param addr IPv4 address - * @param port L4 port number - * @param proto L4 protocol - * @param vrf_id VRF ID - * @param is_in 1 = inside network address and port pair, 0 = outside - * - * @return 0 on success, non-zero value otherwise - */ -int nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port, - nat_protocol_t proto, u32 vrf_id, int is_in); - /** * @brief Delete NAT44 endpoint-dependent session * @@ -1356,20 +1344,6 @@ int nat44_set_session_limit (u32 session_limit, u32 vrf_id); */ int nat44_update_session_limit (u32 session_limit, u32 vrf_id); -/** - * @brief Initialize NAT44 data - * - * @param tsm per thread data - */ -void nat44_db_init (snat_main_per_thread_data_t * tsm); - -/** - * @brief Free NAT44 data - * - * @param tsm per thread data - */ -void nat44_db_free (snat_main_per_thread_data_t * tsm); - /** * @brief Free all NAT44 sessions */ @@ -1510,6 +1484,18 @@ typedef struct u8 *format_user_kvp (u8 * s, va_list * args); +u32 get_thread_idx_by_port (u16 e_port); + +u8 *format_static_mapping_kvp (u8 *s, va_list *args); + +u8 *format_session_kvp (u8 *s, va_list *args); + +u8 *format_user_kvp (u8 *s, va_list *args); + +u32 nat_calc_bihash_buckets (u32 n_elts); + +void nat44_addresses_free (snat_address_t **addresses); + #endif /* __included_nat_h__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat44-ei/nat44_ei.c b/src/plugins/nat/nat44-ei/nat44_ei.c index f50ccb9ba1b..00aa8e1b65b 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.c +++ b/src/plugins/nat/nat44-ei/nat44_ei.c @@ -36,18 +36,156 @@ #include #include +nat44_ei_main_t nat44_ei_main; + +static void nat44_ei_db_free (); + +static void nat44_ei_db_init (u32 translations, u32 translation_buckets, + u32 user_buckets); + int -nat44_ei_plugin_enable () +nat44_ei_plugin_enable (nat44_ei_config_t c) { + nat44_ei_main_t *nm = &nat44_ei_main; + snat_main_t *sm = &snat_main; + + clib_memset (nm, 0, sizeof (*nm)); + + if (!c.users) + c.users = 1024; + + if (!c.sessions) + c.sessions = 10 * 1024; + + nm->rconfig = c; + + nm->translations = c.sessions; + nm->translation_buckets = nat_calc_bihash_buckets (c.sessions); + nm->user_buckets = nat_calc_bihash_buckets (c.users); + + // OBSOLETE + + sm->static_mapping_only = c.static_mapping_only; + sm->static_mapping_connection_tracking = c.connection_tracking; + sm->out2in_dpo = c.out2in_dpo; + sm->forwarding_enabled = 0; + sm->mss_clamping = 0; + sm->pat = (!c.static_mapping_only || + (c.static_mapping_only && c.connection_tracking)); + + sm->max_users_per_thread = c.users; + sm->max_translations_per_thread = c.sessions; + sm->translation_buckets = nat_calc_bihash_buckets (c.sessions); + sm->max_translations_per_user = + c.user_sessions ? c.user_sessions : sm->max_translations_per_thread; + + sm->inside_vrf_id = c.inside_vrf; + sm->inside_fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, c.inside_vrf, sm->fib_src_hi); + + sm->outside_vrf_id = c.outside_vrf; + sm->outside_fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi); + + sm->worker_in2out_cb = nat44_ei_get_in2out_worker_index; + sm->worker_out2in_cb = nat44_ei_get_out2in_worker_index; + + sm->in2out_node_index = sm->ei_in2out_node_index; + sm->out2in_node_index = sm->ei_out2in_node_index; + + sm->in2out_output_node_index = sm->ei_in2out_output_node_index; + + if (sm->pat) + { + sm->icmp_match_in2out_cb = icmp_match_in2out_slow; + sm->icmp_match_out2in_cb = icmp_match_out2in_slow; + } + else + { + sm->icmp_match_in2out_cb = icmp_match_in2out_fast; + sm->icmp_match_out2in_cb = icmp_match_out2in_fast; + } + + nat_reset_timeouts (&sm->timeouts); + nat44_ei_db_init (nm->translations, nm->translation_buckets, + nm->user_buckets); nat44_ei_set_alloc_default (); nat_ha_enable (); + + // TODO: function for reset counters + vlib_zero_simple_counter (&sm->total_users, 0); + vlib_zero_simple_counter (&sm->total_sessions, 0); + vlib_zero_simple_counter (&sm->user_limit_reached, 0); + + sm->enabled = 1; + return 0; } -void +int nat44_ei_plugin_disable () { + nat44_ei_main_t *nm = &nat44_ei_main; + snat_main_t *sm = &snat_main; + snat_interface_t *i, *vec; + int error = 0; + + // first unregister all nodes from interfaces + vec = vec_dup (sm->interfaces); + vec_foreach (i, vec) + { + if (nat_interface_is_inside (i)) + error = snat_interface_add_del (i->sw_if_index, 1, 1); + if (nat_interface_is_outside (i)) + error = snat_interface_add_del (i->sw_if_index, 0, 1); + + if (error) + { + nat_log_err ("error occurred while removing interface %u", + i->sw_if_index); + } + } + vec_free (vec); + sm->interfaces = 0; + + vec = vec_dup (sm->output_feature_interfaces); + vec_foreach (i, vec) + { + if (nat_interface_is_inside (i)) + error = snat_interface_add_del_output_feature (i->sw_if_index, 1, 1); + if (nat_interface_is_outside (i)) + error = snat_interface_add_del_output_feature (i->sw_if_index, 0, 1); + + if (error) + { + nat_log_err ("error occurred while removing interface %u", + i->sw_if_index); + } + } + vec_free (vec); + sm->output_feature_interfaces = 0; + nat_ha_disable (); + nat44_ei_db_free (); + + nat44_addresses_free (&sm->addresses); + nat44_addresses_free (&sm->twice_nat_addresses); + + vec_free (sm->to_resolve); + vec_free (sm->auto_add_sw_if_indices); + vec_free (sm->auto_add_sw_if_indices_twice_nat); + + sm->to_resolve = 0; + sm->auto_add_sw_if_indices = 0; + sm->auto_add_sw_if_indices_twice_nat = 0; + + sm->forwarding_enabled = 0; + + sm->enabled = 0; + clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig)); + clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig)); + + return error; } void @@ -525,6 +663,651 @@ nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length) sm->psid_length = psid_length; } +static void +nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port, + u16 e_port, nat_protocol_t proto, + u32 sw_if_index, u32 vrf_id, + int addr_only, int identity_nat, + u8 *tag) +{ + snat_main_t *sm = &snat_main; + snat_static_map_resolve_t *rp; + + vec_add2 (sm->to_resolve, rp, 1); + clib_memset (rp, 0, sizeof (*rp)); + + rp->l_addr.as_u32 = l_addr.as_u32; + rp->l_port = l_port; + rp->e_port = e_port; + rp->sw_if_index = sw_if_index; + rp->vrf_id = vrf_id; + rp->proto = proto; + rp->addr_only = addr_only; + rp->identity_nat = identity_nat; + rp->tag = vec_dup (tag); +} + +int +nat44_ei_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + nat_protocol_t proto, u32 vrf_id, int is_in) +{ + snat_main_per_thread_data_t *tsm; + clib_bihash_kv_8_8_t kv, value; + ip4_header_t ip; + u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); + snat_session_t *s; + clib_bihash_8_8_t *t; + + if (sm->endpoint_dependent) + return VNET_API_ERROR_UNSUPPORTED; + + ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; + if (sm->num_workers > 1) + tsm = vec_elt_at_index (sm->per_thread_data, + sm->worker_in2out_cb (&ip, fib_index, 0)); + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + + init_nat_k (&kv, *addr, port, fib_index, proto); + t = is_in ? &tsm->in2out : &tsm->out2in; + if (!clib_bihash_search_8_8 (t, &kv, &value)) + { + if (pool_is_free_index (tsm->sessions, value.value)) + return VNET_API_ERROR_UNSPECIFIED; + + s = pool_elt_at_index (tsm->sessions, value.value); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); + nat44_delete_session (sm, s, tsm - sm->per_thread_data); + return 0; + } + + return VNET_API_ERROR_NO_SUCH_ENTRY; +} + +int +nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, nat_protocol_t proto, + u32 sw_if_index, u32 vrf_id, u8 addr_only, + u8 identity_nat, u8 *tag, u8 is_add) +{ + snat_main_t *sm = &snat_main; + snat_static_mapping_t *m = 0; + clib_bihash_kv_8_8_t kv, value; + snat_address_t *a = 0; + u32 fib_index = ~0; + snat_interface_t *interface; + snat_main_per_thread_data_t *tsm; + snat_user_key_t u_key; + snat_user_t *u; + dlist_elt_t *head, *elt; + u32 elt_index, head_index; + u32 ses_index; + 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; + int i; + + if (sw_if_index != ~0) + { + ip4_address_t *first_int_addr; + + for (i = 0; i < vec_len (sm->to_resolve); i++) + { + rp = sm->to_resolve + i; + if (rp->sw_if_index != sw_if_index || + rp->l_addr.as_u32 != l_addr.as_u32 || rp->vrf_id != vrf_id || + rp->addr_only != addr_only) + continue; + + if (!addr_only) + { + if ((rp->l_port != l_port && rp->e_port != e_port) || + rp->proto != proto) + continue; + } + + rp_match = rp; + break; + } + + /* Might be already set... */ + first_int_addr = ip4_interface_first_address ( + sm->ip4_main, sw_if_index, 0 /* just want the address */); + + if (is_add) + { + if (rp_match) + return VNET_API_ERROR_VALUE_EXIST; + + nat44_ei_add_static_mapping_when_resolved ( + l_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only, + identity_nat, tag); + + /* DHCP resolution required? */ + if (!first_int_addr) + return 0; + + e_addr.as_u32 = first_int_addr->as_u32; + /* Identity mapping? */ + if (l_addr.as_u32 == 0) + l_addr.as_u32 = e_addr.as_u32; + } + else + { + if (!rp_match) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + vec_del1 (sm->to_resolve, i); + + if (!first_int_addr) + return 0; + + e_addr.as_u32 = first_int_addr->as_u32; + /* Identity mapping? */ + if (l_addr.as_u32 == 0) + l_addr.as_u32 = e_addr.as_u32; + } + } + + init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto); + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) + m = pool_elt_at_index (sm->static_mappings, value.value); + + if (is_add) + { + if (m) + { + // identity mapping for second vrf + if (is_identity_static_mapping (m)) + { + pool_foreach (local, m->locals) + { + if (local->vrf_id == vrf_id) + return VNET_API_ERROR_VALUE_EXIST; + } + 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, sm->fib_src_low); + init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index, + m->proto, m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); + return 0; + } + return VNET_API_ERROR_VALUE_EXIST; + } + + /* Convert VRF id to FIB index */ + if (vrf_id != ~0) + { + fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); + } + /* If not specified use inside VRF id from NAT44 plugin config */ + else + { + fib_index = sm->inside_fib_index; + vrf_id = sm->inside_vrf_id; + fib_table_lock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + } + + if (!identity_nat) + { + init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index, + addr_only ? 0 : proto); + if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, + &value)) + return VNET_API_ERROR_VALUE_EXIST; + } + + /* Find external address in allocated addresses and reserve port for + address and port pair mapping when dynamic translations enabled */ + if (!(addr_only || sm->static_mapping_only)) + { + for (i = 0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) + { + a = sm->addresses + i; + /* External port must be unused */ + switch (proto) + { +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + if (a->busy_##n##_port_refcounts[e_port]) \ + return VNET_API_ERROR_INVALID_VALUE; \ + ++a->busy_##n##_port_refcounts[e_port]; \ + if (e_port > 1024) \ + { \ + a->busy_##n##_ports++; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]++; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : nat_elog_info ("unknown protocol"); + return VNET_API_ERROR_INVALID_VALUE_2; + } + break; + } + } + /* External address must be allocated */ + if (!a && (l_addr.as_u32 != e_addr.as_u32)) + { + if (sw_if_index != ~0) + { + for (i = 0; i < vec_len (sm->to_resolve); i++) + { + rp = sm->to_resolve + i; + if (rp->addr_only) + continue; + if (rp->sw_if_index != sw_if_index && + rp->l_addr.as_u32 != l_addr.as_u32 && + rp->vrf_id != vrf_id && rp->l_port != l_port && + rp->e_port != e_port && rp->proto != proto) + continue; + + vec_del1 (sm->to_resolve, i); + break; + } + } + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + } + + pool_get (sm->static_mappings, m); + clib_memset (m, 0, sizeof (*m)); + m->tag = vec_dup (tag); + m->local_addr = l_addr; + m->external_addr = e_addr; + + if (addr_only) + m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY; + else + { + m->local_port = l_port; + m->external_port = e_port; + m->proto = proto; + } + + 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 (sm->num_workers > 1) + { + ip4_header_t ip = { + .src_address = m->local_addr, + }; + vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0)); + tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]); + } + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + + init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, + m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1); + + init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, + m - sm->static_mappings); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1); + + /* Delete dynamic sessions matching local address (+ local port) */ + // TODO: based on type of NAT EI/ED + if (!(sm->static_mapping_only)) + { + u_key.addr = m->local_addr; + u_key.fib_index = m->fib_index; + kv.key = u_key.as_u64; + if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) + { + user_index = value.value; + u = pool_elt_at_index (tsm->users, user_index); + if (u->nsessions) + { + 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 (snat_is_session_static (s)) + continue; + + if (!addr_only && s->in2out.port != m->local_port) + continue; + + nat_free_session_data (sm, s, tsm - sm->per_thread_data, + 0); + nat44_delete_session (sm, s, tsm - sm->per_thread_data); + + if (!addr_only) + break; + } + } + } + } + } + else + { + if (!m) + { + if (sw_if_index != ~0) + return 0; + else + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + if (identity_nat) + { + if (vrf_id == ~0) + vrf_id = sm->inside_vrf_id; + + pool_foreach (local, m->locals) + { + if (local->vrf_id == vrf_id) + find = local - m->locals; + } + 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)) + { + for (i = 0; i < vec_len (sm->addresses); i++) + { + if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) + { + a = sm->addresses + i; + switch (proto) + { +#define _(N, j, n, s) \ + case NAT_PROTOCOL_##N: \ + --a->busy_##n##_port_refcounts[e_port]; \ + if (e_port > 1024) \ + { \ + a->busy_##n##_ports--; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--; \ + } \ + break; + foreach_nat_protocol +#undef _ + default : return VNET_API_ERROR_INVALID_VALUE_2; + } + break; + } + } + } + + if (sm->num_workers > 1) + tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]); + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + + init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto); + clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &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 = fib_index; + kv.key = u_key.as_u64; + nat44_ei_static_mapping_del_sessions (sm, tsm, u_key, addr_only, + e_addr, e_port); + } + + fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + if (pool_elts (m->locals)) + return 0; + + init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto); + 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 */ + pool_put (sm->static_mappings, m); + } + + if (!addr_only || (l_addr.as_u32 == e_addr.as_u32)) + return 0; + + /* Add/delete external address to FIB */ + pool_foreach (interface, sm->interfaces) + { + if (nat_interface_is_inside (interface) || sm->out2in_dpo) + continue; + + snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add); + break; + } + pool_foreach (interface, sm->output_feature_interfaces) + { + if (nat_interface_is_inside (interface) || sm->out2in_dpo) + continue; + + snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add); + break; + } + return 0; +} + +int +nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port, + u32 match_fib_index, + nat_protocol_t match_protocol, + ip4_address_t *mapping_addr, u16 *mapping_port, + u32 *mapping_fib_index, u8 by_external, + u8 *is_addr_only, u8 *is_identity_nat) +{ + snat_main_t *sm = &snat_main; + clib_bihash_kv_8_8_t kv, value; + snat_static_mapping_t *m; + u16 port; + + if (by_external) + { + init_nat_k (&kv, match_addr, match_port, 0, match_protocol); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, + &value)) + { + /* Try address only mapping */ + init_nat_k (&kv, match_addr, 0, 0, 0); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, + &value)) + return 1; + } + m = pool_elt_at_index (sm->static_mappings, value.value); + + *mapping_fib_index = m->fib_index; + *mapping_addr = m->local_addr; + port = m->local_port; + } + else + { + init_nat_k (&kv, match_addr, match_port, match_fib_index, + match_protocol); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value)) + { + /* Try address only mapping */ + init_nat_k (&kv, match_addr, 0, match_fib_index, 0); + if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, + &value)) + return 1; + } + m = pool_elt_at_index (sm->static_mappings, value.value); + + *mapping_fib_index = sm->outside_fib_index; + *mapping_addr = m->external_addr; + port = m->external_port; + } + + /* Address only mapping doesn't change port */ + if (is_addr_only_static_mapping (m)) + *mapping_port = match_port; + else + *mapping_port = port; + + if (PREDICT_FALSE (is_addr_only != 0)) + *is_addr_only = is_addr_only_static_mapping (m); + + if (PREDICT_FALSE (is_identity_nat != 0)) + *is_identity_nat = is_identity_static_mapping (m); + + return 0; +} + +static void +nat44_ei_worker_db_free (snat_main_per_thread_data_t *tsm) +{ + pool_free (tsm->list_pool); + pool_free (tsm->lru_pool); + pool_free (tsm->sessions); + pool_free (tsm->users); + + clib_bihash_free_8_8 (&tsm->in2out); + clib_bihash_free_8_8 (&tsm->out2in); + clib_bihash_free_8_8 (&tsm->user_hash); +} + +static void +nat44_ei_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations, + u32 translation_buckets, u32 user_buckets) +{ + dlist_elt_t *head; + + pool_alloc (tsm->list_pool, translations); + pool_alloc (tsm->lru_pool, translations); + pool_alloc (tsm->sessions, translations); + + clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets, 0); + clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets, 0); + clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, 0); + + clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp); + + 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); +} + +static void +nat44_ei_db_free () +{ + snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + + pool_free (sm->static_mappings); + clib_bihash_free_8_8 (&sm->static_mapping_by_local); + clib_bihash_free_8_8 (&sm->static_mapping_by_external); + + if (sm->pat) + { + vec_foreach (tsm, sm->per_thread_data) + { + nat44_ei_worker_db_free (tsm); + } + } +} + +static void +nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets) +{ + snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + + u32 static_mapping_buckets = 1024; + u32 static_mapping_memory_size = 64 << 20; + + 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); + clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local, + format_static_mapping_kvp); + clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external, + format_static_mapping_kvp); + + if (sm->pat) + { + vec_foreach (tsm, sm->per_thread_data) + { + nat44_ei_worker_db_init (tsm, translations, translation_buckets, + user_buckets); + } + } +} + +void +nat44_ei_sessions_clear () +{ + nat44_ei_main_t *nm = &nat44_ei_main; + + snat_main_per_thread_data_t *tsm; + snat_main_t *sm = &snat_main; + + if (sm->pat) + { + vec_foreach (tsm, sm->per_thread_data) + { + nat44_ei_worker_db_free (tsm); + nat44_ei_worker_db_init (tsm, nm->translations, + nm->translation_buckets, nm->user_buckets); + } + } + + // TODO: function for reset counters + vlib_zero_simple_counter (&sm->total_users, 0); + vlib_zero_simple_counter (&sm->total_sessions, 0); + vlib_zero_simple_counter (&sm->user_limit_reached, 0); +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/nat/nat44-ei/nat44_ei.h b/src/plugins/nat/nat44-ei/nat44_ei.h index ac430bee5c3..510e73de59a 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.h +++ b/src/plugins/nat/nat44-ei/nat44_ei.h @@ -19,9 +19,38 @@ #ifndef __included_nat44_ei_h__ #define __included_nat44_ei_h__ -int nat44_ei_plugin_enable (); +typedef struct +{ + /* maximum number of users */ + u32 users; + /* maximum number of sessions */ + u32 sessions; + /* maximum number of ssessions per user */ + u32 user_sessions; -void nat44_ei_plugin_disable (); + /* plugin features */ + u8 static_mapping_only; + u8 connection_tracking; + u8 out2in_dpo; + + u32 inside_vrf; + u32 outside_vrf; + +} nat44_ei_config_t; + +typedef struct +{ + u32 translations; + u32 translation_buckets; + u32 user_buckets; + + nat44_ei_config_t rconfig; + +} nat44_ei_main_t; + +int nat44_ei_plugin_enable (nat44_ei_config_t c); + +int nat44_ei_plugin_disable (); /** * @brief Delete specific NAT44 EI user and his sessions @@ -71,6 +100,71 @@ void nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length); */ void nat44_ei_set_alloc_range (u16 start_port, u16 end_port); +/** + * @brief Add/delete NAT44-EI static mapping + * + * @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 proto L4 protocol + * @param sw_if_index use interface address as external IPv4 address + * @param vrf_id local VRF ID + * @param addr_only 1 = 1:1NAT, 0 = 1:1NAPT + * @param identity_nat identity NAT + * @param tag opaque string tag + * @param is_add 1 = add, 0 = delete + * + * @return 0 on success, non-zero value otherwise + + */ +int nat44_ei_add_del_static_mapping (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, nat_protocol_t proto, + u32 sw_if_index, u32 vrf_id, u8 addr_only, + u8 identity_nat, u8 *tag, u8 is_add); + +/** + * @brief Delete NAT44-EI session + * + * @param addr IPv4 address + * @param port L4 port number + * @param proto L4 protocol + * @param vrf_id VRF ID + * @param is_in 1 = inside network address and port pair, 0 = outside + * + * @return 0 on success, non-zero value otherwise + */ +int nat44_ei_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + nat_protocol_t proto, u32 vrf_id, int is_in); + +/** + * @brief Match NAT44-EI static mapping. + * + * @param key address and port to match + * @param addr external/local address of the matched mapping + * @param port port of the matched mapping + * @param fib_index fib index of the matched mapping + * @param by_external if 0 match by local address otherwise match by + * external address + * @param is_addr_only 1 if matched mapping is address only + * @param is_identity_nat 1 if indentity mapping + * + * @returns 0 if match found otherwise 1. + */ +int nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port, + u32 match_fib_index, + nat_protocol_t match_protocol, + ip4_address_t *mapping_addr, + u16 *mapping_port, u32 *mapping_fib_index, + u8 by_external, u8 *is_addr_only, + u8 *is_identity_nat); + +/** + * @brief Clear all active NAT44-EI sessions. + */ +void nat44_ei_sessions_clear (); + #endif /* __included_nat44_ei_h__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c index 1c341318957..892518fff97 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -130,10 +131,10 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t * node, ip4_address_t placeholder_addr; u16 placeholder_port; u32 placeholder_fib_index; - if (!snat_static_mapping_match - (sm, ip0->dst_address, udp0->dst_port, sm->outside_fib_index, - proto0, &placeholder_addr, &placeholder_port, - &placeholder_fib_index, 1, 0, 0, 0, 0, 0, 0)) + if (!nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port, + sm->outside_fib_index, proto0, + &placeholder_addr, &placeholder_port, + &placeholder_fib_index, 1, 0, 0)) return 0; } else @@ -270,9 +271,9 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0, } /* First try to match static mapping by local address and port */ - if (snat_static_mapping_match - (sm, i2o_addr, i2o_port, rx_fib_index0, nat_proto, &sm_addr, - &sm_port, &sm_fib_index, 0, 0, 0, 0, 0, &identity_nat, 0)) + if (nat44_ei_static_mapping_match (i2o_addr, i2o_port, rx_fib_index0, + nat_proto, &sm_addr, &sm_port, + &sm_fib_index, 0, 0, &identity_nat)) { /* Try to create dynamic translation */ if (sm->alloc_addr_and_port ( @@ -592,9 +593,9 @@ icmp_match_in2out_fast (snat_main_t * sm, vlib_node_runtime_t * node, u16 sm_port; u32 sm_fib_index; - if (snat_static_mapping_match - (sm, *addr, *port, *fib_index, *proto, &sm_addr, &sm_port, - &sm_fib_index, 0, &is_addr_only, 0, 0, 0, 0, 0)) + if (nat44_ei_static_mapping_match (*addr, *port, *fib_index, *proto, + &sm_addr, &sm_port, &sm_fib_index, 0, + &is_addr_only, 0)) { if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0, IP_PROTOCOL_ICMP, @@ -1831,9 +1832,9 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm, goto trace0; } - if (snat_static_mapping_match - (sm, ip0->src_address, udp0->src_port, rx_fib_index0, proto0, - &sm0_addr, &sm0_port, &sm0_fib_index, 0, 0, 0, 0, 0, 0, 0)) + if (nat44_ei_static_mapping_match ( + ip0->src_address, udp0->src_port, rx_fib_index0, proto0, + &sm0_addr, &sm0_port, &sm0_fib_index, 0, 0, 0)) { b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; next0 = SNAT_IN2OUT_NEXT_DROP; diff --git a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c index 8220f0dc9d8..b677e9bde89 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -354,10 +355,9 @@ icmp_match_out2in_slow (snat_main_t * sm, vlib_node_runtime_t * node, { /* Try to match static mapping by external address and port, destination address and port in packet */ - if (snat_static_mapping_match - (sm, *addr, *port, *fib_index, *proto, - &mapping_addr, &mapping_port, &mapping_fib_index, 1, &is_addr_only, - 0, 0, 0, &identity_nat, 0)) + if (nat44_ei_static_mapping_match ( + *addr, *port, *fib_index, *proto, &mapping_addr, &mapping_port, + &mapping_fib_index, 1, &is_addr_only, &identity_nat)) { if (!sm->forwarding_enabled) { @@ -481,9 +481,9 @@ icmp_match_out2in_fast (snat_main_t * sm, vlib_node_runtime_t * node, next0 = SNAT_OUT2IN_NEXT_DROP; goto out; } - if (snat_static_mapping_match - (sm, addr, port, rx_fib_index0, *proto, mapping_addr, mapping_port, - mapping_fib_index, 1, &is_addr_only, 0, 0, 0, 0, 0)) + if (nat44_ei_static_mapping_match (addr, port, rx_fib_index0, *proto, + mapping_addr, mapping_port, + mapping_fib_index, 1, &is_addr_only, 0)) { /* Don't NAT packet aimed at the intfc address */ if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32)) @@ -828,11 +828,10 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm, { /* Try to match static mapping by external address and port, destination address and port in packet */ - if (snat_static_mapping_match - (sm, ip0->dst_address, - vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, - proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1, 0, 0, 0, - 0, &identity_nat0, 0)) + if (nat44_ei_static_mapping_match ( + ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port, + rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1, + 0, &identity_nat0)) { /* * Send DHCP packets to the ipv4 stack, or we won't @@ -1003,17 +1002,15 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm, init_nat_k (&kv1, ip1->dst_address, vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1, proto1); - if (clib_bihash_search_8_8 (&sm->per_thread_data[thread_index].out2in, &kv1, &value1)) { /* Try to match static mapping by external address and port, destination address and port in packet */ - if (snat_static_mapping_match - (sm, ip1->dst_address, - vnet_buffer (b1)->ip.reass.l4_dst_port, proto1, - rx_fib_index1, &sm_addr1, &sm_port1, &sm_fib_index1, 1, 0, - 0, 0, 0, &identity_nat1, 0)) + if (nat44_ei_static_mapping_match ( + ip1->dst_address, vnet_buffer (b1)->ip.reass.l4_dst_port, + rx_fib_index1, proto1, &sm_addr1, &sm_port1, &sm_fib_index1, 1, + 0, &identity_nat1)) { /* * Send DHCP packets to the ipv4 stack, or we won't @@ -1227,11 +1224,10 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm, { /* Try to match static mapping by external address and port, destination address and port in packet */ - if (snat_static_mapping_match - (sm, ip0->dst_address, - vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, - proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1, 0, 0, 0, - 0, &identity_nat0, 0)) + if (nat44_ei_static_mapping_match ( + ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port, + rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1, + 0, &identity_nat0)) { /* * Send DHCP packets to the ipv4 stack, or we won't @@ -1454,9 +1450,9 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm, goto trace00; } - if (snat_static_mapping_match - (sm, ip0->dst_address, udp0->dst_port, rx_fib_index0, proto0, - &sm_addr0, &sm_port0, &sm_fib_index0, 1, 0, 0, 0, 0, 0, 0)) + if (nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port, + rx_fib_index0, proto0, &sm_addr0, + &sm_port0, &sm_fib_index0, 1, 0, 0)) { b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; diff --git a/src/plugins/nat/nat44_api.c b/src/plugins/nat/nat44_api.c index cfe2211acd3..c025db74f2e 100644 --- a/src/plugins/nat/nat44_api.c +++ b/src/plugins/nat/nat44_api.c @@ -828,13 +828,10 @@ static void tag = format (0, "%s", mp->tag); vec_terminate_c_string (tag); - rv = snat_add_static_mapping (local_addr, external_addr, local_port, - external_port, vrf_id, - mp->flags & NAT_API_IS_ADDR_ONLY, - external_sw_if_index, proto, - mp->is_add, twice_nat, - mp->flags & NAT_API_IS_OUT2IN_ONLY, tag, 0, - pool_addr, 0); + rv = snat_add_static_mapping ( + local_addr, external_addr, local_port, external_port, vrf_id, + mp->flags & NAT_API_IS_ADDR_ONLY, external_sw_if_index, proto, mp->is_add, + twice_nat, mp->flags & NAT_API_IS_OUT2IN_ONLY, tag, 0, pool_addr, 0); vec_free (tag); REPLY_MACRO (VL_API_NAT44_ADD_DEL_STATIC_MAPPING_REPLY); @@ -1622,7 +1619,7 @@ vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp) nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol, vrf_id, is_in); else - rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in); + rv = nat44_ei_del_session (sm, &addr, port, proto, vrf_id, is_in); REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY); } diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index 7415b5fe76f..adcf324850d 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -44,8 +44,6 @@ nat44_enable_command_fn (vlib_main_t * vm, nat44_config_t c = { 0 }; u8 mode_set = 0; - // TODO: check this also inside the function so it can be - // safely called from anyplace, also sanity checking required if (sm->enabled) return clib_error_return (0, "nat44 already enabled"); @@ -1148,11 +1146,10 @@ add_static_mapping_command_fn (vlib_main_t * vm, goto done; } - rv = snat_add_static_mapping (l_addr, e_addr, clib_host_to_net_u16 (l_port), - clib_host_to_net_u16 (e_port), - vrf_id, addr_only, sw_if_index, proto, is_add, - twice_nat, out2in_only, 0, 0, exact_addr, - exact); + rv = snat_add_static_mapping ( + l_addr, e_addr, clib_host_to_net_u16 (l_port), + clib_host_to_net_u16 (e_port), vrf_id, addr_only, sw_if_index, proto, + is_add, twice_nat, out2in_only, 0, 0, exact_addr, exact); switch (rv) { @@ -1230,11 +1227,9 @@ add_identity_mapping_command_fn (vlib_main_t * vm, } } - rv = - snat_add_static_mapping (addr, addr, clib_host_to_net_u16 (port), - clib_host_to_net_u16 (port), vrf_id, addr_only, - sw_if_index, proto, is_add, 0, 0, 0, 1, - pool_addr, 0); + rv = snat_add_static_mapping ( + addr, addr, clib_host_to_net_u16 (port), clib_host_to_net_u16 (port), + vrf_id, addr_only, sw_if_index, proto, is_add, 0, 0, 0, 1, pool_addr, 0); switch (rv) { @@ -1779,9 +1774,8 @@ nat44_del_session_command_fn (vlib_main_t * vm, clib_host_to_net_u16 (eh_port), nat_proto_to_ip_proto (proto), vrf_id, is_in); else - rv = - nat44_del_session (sm, &addr, clib_host_to_net_u16 (port), proto, - vrf_id, is_in); + rv = nat44_ei_del_session (sm, &addr, clib_host_to_net_u16 (port), proto, + vrf_id, is_in); switch (rv) { -- cgit 1.2.3-korg