+ sm->per_thread_data[0].snat_thread_index = 0;
+
+ /* callbacks to call when interface address changes. */
+ cbi.function = snat_ip4_add_del_interface_address_cb;
+ vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi);
+ cbi.function = nat_ip4_add_del_addr_only_sm_cb;
+ vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi);
+
+ /* callbacks to call when interface to table biding changes */
+ cbt.function = snat_update_outside_fib;
+ vec_add1 (sm->ip4_main->table_bind_callbacks, cbt);
+
+ sm->fib_src_low =
+ fib_source_allocate ("nat-low", FIB_SOURCE_PRIORITY_LOW,
+ FIB_SOURCE_BH_SIMPLE);
+ sm->fib_src_hi =
+ fib_source_allocate ("nat-hi", FIB_SOURCE_PRIORITY_HI,
+ FIB_SOURCE_BH_SIMPLE);
+
+ /* used only by out2in-dpo feature */
+ nat_dpo_module_init ();
+
+ nat_affinity_init (vm);
+ nat_ha_init (vm, sm->num_workers, num_threads);
+
+ test_key_calc_split ();
+ return nat44_api_hookup (vm);
+}
+
+VLIB_INIT_FUNCTION (nat_init);
+
+int
+nat44_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)
+ {
+ nat_log_err ("nat44 is enabled");
+ 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;
+ }
+ }
+
+ // reset to defaults:
+ sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
+ sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
+ //
+ 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;
+ sm->forwarding_enabled = 0;
+ sm->mss_clamping = 0;
+
+ if (!c.users)
+ c.users = 1024;
+
+ sm->max_users_per_thread = c.users;
+ sm->user_buckets = nat_calc_bihash_buckets (c.users);
+
+ if (!c.sessions)
+ c.sessions = 10 * 1024;
+
+ sm->max_translations_per_thread = c.sessions;
+ sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
+
+ vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
+ 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);
+
+
+ nat_affinity_enable ();
+
+ nat_ha_enable (nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb, nat_ha_sref_ed_cb);
+ }
+ else
+ {
+ sm->worker_out2in_cb = snat_get_worker_out2in_cb;
+ sm->worker_in2out_cb = snat_get_worker_in2out_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;
+
+ nat_ha_enable (nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
+ }
+
+ // c.static_mapping & c.connection_tracking require
+ // session database
+ if (!c.static_mapping_only
+ || (c.static_mapping_only && c.connection_tracking))
+ {
+ snat_main_per_thread_data_t *tsm;
+ /* *INDENT-OFF* */
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ nat44_db_init (tsm);
+ }
+ /* *INDENT-ON* */
+ }
+ else
+ {
+ sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
+ sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
+ }
+
+ clib_bihash_init_8_8 (&sm->static_mapping_by_local,
+ "static_mapping_by_local", static_mapping_buckets,
+ static_mapping_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
+ format_static_mapping_kvp);
+
+ clib_bihash_init_8_8 (&sm->static_mapping_by_external,
+ "static_mapping_by_external",
+ static_mapping_buckets, static_mapping_memory_size);
+ clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
+ format_static_mapping_kvp);
+
+ // last: 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;
+ sm->rconfig = c;
+
+ return 0;
+}
+
+void
+nat44_addresses_free (snat_address_t ** addresses)
+{
+ snat_address_t *ap;
+ /* *INDENT-OFF* */
+ vec_foreach (ap, *addresses)
+ {
+ #define _(N, i, n, s) \
+ vec_free (ap->busy_##n##_ports_per_thread);
+ foreach_nat_protocol
+ #undef _
+ }
+ /* *INDENT-ON* */
+ vec_free (*addresses);
+ *addresses = 0;
+}
+
+int
+nat44_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;
+ }
+
+ // first unregister all nodes from interfaces
+ vec = vec_dup (sm->interfaces);
+ /* *INDENT-OFF* */
+ vec_foreach (i, vec)