nat: nat44 enable/disable dynamic config 63/29463/5
authorFilip Varga <fivarga@cisco.com>
Wed, 30 Sep 2020 20:24:47 +0000 (22:24 +0200)
committerOle Tr�an <otroan@employees.org>
Fri, 23 Oct 2020 12:09:07 +0000 (12:09 +0000)
This patch changes initialization and configuration of NAT
plugin. Instead of allocating data structures at vpp plugin
initialization phase allocation and configuration happens
after calling enable API or CLI call. This reduces base VPP
memory footprint and also enables dynamic reconfiguration
of the NAT plugin.

Type: improvement
Change-Id: I42c069ee19a0311d043ac1f3f230d87bc8d2680f
Signed-off-by: Filip Varga <fivarga@cisco.com>
src/plugins/gbp/test/test_gbp.py
src/plugins/nat/nat.api
src/plugins/nat/nat.c
src/plugins/nat/nat.h
src/plugins/nat/nat44_cli.c
src/plugins/nat/nat_affinity.c
src/plugins/nat/nat_affinity.h
src/plugins/nat/nat_api.c
src/plugins/nat/nat_ha.c
src/plugins/nat/nat_ha.h
src/plugins/nat/test/test_nat.py

index 5ff71f4..df3c3ad 100644 (file)
@@ -576,9 +576,13 @@ class TestGBP(VppTestCase):
     """ GBP Test Case """
 
     @property
-    def config_flags(self):
+    def nat_config_flags(self):
         return VppEnum.vl_api_nat_config_flags_t
 
+    @property
+    def nat44_config_flags(self):
+        return VppEnum.vl_api_nat44_config_flags_t
+
     @classmethod
     def setUpClass(cls):
         super(TestGBP, cls).setUpClass()
@@ -826,6 +830,8 @@ class TestGBP(VppTestCase):
                               "10.0.2.1", "11.0.0.4",
                               "2001:10:2::1", "3001::4")]
 
+        self.vapi.nat44_plugin_enable_disable(enable=1)
+
         #
         # Config related to each of the EPGs
         #
@@ -839,7 +845,7 @@ class TestGBP(VppTestCase):
                 epg.bvi.set_mac(self.router_mac)
 
                 # The BVIs are NAT inside interfaces
-                flags = self.config_flags.NAT_IS_INSIDE
+                flags = self.nat_config_flags.NAT_IS_INSIDE
                 self.vapi.nat44_interface_add_del_feature(
                     sw_if_index=epg.bvi.sw_if_index,
                     flags=flags, is_add=1)
@@ -902,7 +908,7 @@ class TestGBP(VppTestCase):
             for (ip, fip) in zip(ep.ips, ep.fips):
                 # Add static mappings for each EP from the 10/8 to 11/8 network
                 if ip_address(ip).version == 4:
-                    flags = self.config_flags.NAT_IS_ADDR_ONLY
+                    flags = self.nat_config_flags.NAT_IS_ADDR_ONLY
                     self.vapi.nat44_add_del_static_mapping(
                         is_add=1,
                         local_ip_address=ip,
@@ -1468,16 +1474,11 @@ class TestGBP(VppTestCase):
         #
         # cleanup
         #
+        self.vapi.nat44_plugin_enable_disable(enable=0)
+
         for ep in eps:
             # del static mappings for each EP from the 10/8 to 11/8 network
-            flags = self.config_flags.NAT_IS_ADDR_ONLY
-            self.vapi.nat44_add_del_static_mapping(
-                is_add=0,
-                local_ip_address=ep.ip4,
-                external_ip_address=ep.fip4,
-                external_sw_if_index=0xFFFFFFFF,
-                vrf_id=0,
-                flags=flags)
+            flags = self.nat_config_flags.NAT_IS_ADDR_ONLY
             self.vapi.nat66_add_del_static_mapping(
                 local_ip_address=ep.ip6,
                 external_ip_address=ep.fip6,
@@ -1486,22 +1487,14 @@ class TestGBP(VppTestCase):
         for epg in epgs:
             # IP config on the BVI interfaces
             if epg != epgs[0] and epg != epgs[3]:
-                flags = self.config_flags.NAT_IS_INSIDE
-                self.vapi.nat44_interface_add_del_feature(
-                    sw_if_index=epg.bvi.sw_if_index,
-                    flags=flags,
-                    is_add=0)
+                flags = self.nat_config_flags.NAT_IS_INSIDE
                 self.vapi.nat66_add_del_interface(
-                    is_add=0, flags=flags,
-                    sw_if_index=epg.bvi.sw_if_index)
+                    sw_if_index=epg.bvi.sw_if_index,
+                    flags=flags, is_add=0)
 
         for recirc in recircs:
-            self.vapi.nat44_interface_add_del_feature(
-                sw_if_index=recirc.recirc.sw_if_index,
-                is_add=0)
             self.vapi.nat66_add_del_interface(
-                is_add=0,
-                sw_if_index=recirc.recirc.sw_if_index)
+                sw_if_index=recirc.recirc.sw_if_index, is_add=0)
 
     def wait_for_ep_timeout(self, sw_if_index=None, ip=None, mac=None,
                             tep=None, n_tries=100, s_time=1):
index 09c4d4a..753cfdf 100644 (file)
@@ -30,6 +30,49 @@ import "plugins/nat/nat_types.api";
  * Common NAT plugin APIs
  */
 
+enum nat44_config_flags : u8
+{
+  NAT44_IS_ENDPOINT_INDEPENDENT = 0x00,
+  NAT44_IS_ENDPOINT_DEPENDENT = 0x01,
+  NAT44_IS_STATIC_MAPPING_ONLY = 0x02,
+  NAT44_IS_CONNECTION_TRACKING = 0x04,
+  NAT44_IS_OUT2IN_DPO = 0x08,
+};
+
+/** \brief Enable/disable NAT44 plugin
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param inside_vrf - inside vrf id
+    @param outside_vrf - outside vrf id
+    @param users - maximum number of users per thread
+                  (NAT44_IS_ENDPOINT_INDEPENDENT)
+    @param user_memory - overwrite hash allocation parameter
+                        (NAT44_IS_ENDPOINT_INDEPENDENT)
+    @param sessions - maximum number of sessions per thread
+    @param session_memory - overwrite hash allocation parameter
+    @param user_sessions - maximum number of sessions per user
+                          (NAT44_IS_ENDPOINT_INDEPENDENT)
+    @param enable - true if enable, false if disable
+    @param flags - flag NAT44_IS_ENDPOINT_INDEPENDENT,
+                        NAT44_IS_ENDPOINT_DEPENDENT,
+                        NAT44_IS_STATIC_MAPPING_ONLY,
+                        NAT44_IS_CONNECTION_TRACKING,
+                        NAT44_IS_OUT2IN_DPO
+*/
+autoreply define nat44_plugin_enable_disable {
+  u32 client_index;
+  u32 context;
+  u32 inside_vrf;
+  u32 outside_vrf;
+  u32 users;
+  u32 user_memory;
+  u32 sessions;
+  u32 session_memory;
+  u32 user_sessions;
+  bool enable;
+  vl_api_nat44_config_flags_t flags;
+};
+
 /** \brief Control ping from client to api server request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
index b519550..232c26a 100644 (file)
@@ -181,6 +181,70 @@ VLIB_PLUGIN_REGISTER () = {
 };
 /* *INDENT-ON* */
 
+static u32
+nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
+                              u32 rx_fib_index, u8 is_output);
+
+static u32
+nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
+                              u8 is_output);
+
+static u32
+snat_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip0,
+                          u32 rx_fib_index0, u8 is_output);
+
+static u32
+snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
+                          u8 is_output);
+
+static u32 nat_calc_bihash_buckets (u32 n_elts);
+
+static u32 nat_calc_bihash_memory (u32 n_buckets, uword kv_size);
+
+u8 *format_static_mapping_kvp (u8 * s, va_list * args);
+
+u8 *format_ed_session_kvp (u8 * s, va_list * args);
+
+void
+nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
+               ip4_address_t * out_addr, u16 out_port,
+               ip4_address_t * eh_addr, u16 eh_port,
+               ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
+               u32 fib_index, u16 flags, u32 thread_index);
+
+void
+nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
+               ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
+               u32 ti);
+
+void
+nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
+               ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
+               u32 total_pkts, u64 total_bytes, u32 thread_index);
+
+void
+nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
+                  ip4_address_t * out_addr, u16 out_port,
+                  ip4_address_t * eh_addr, u16 eh_port,
+                  ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
+                  u32 fib_index, u16 flags, u32 thread_index);
+
+void
+nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
+                  ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+                  u32 fib_index, u32 ti);
+
+void
+nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
+                  ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+                  u32 fib_index, u32 ti);
+
+void
+nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
+                  ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+                  u32 fib_index, u32 total_pkts, u64 total_bytes,
+                  u32 thread_index);
+
 void
 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
                       u8 is_ha)
@@ -613,14 +677,20 @@ snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
   vlib_thread_main_t *tm = vlib_get_thread_main ();
 
   if (twice_nat && !sm->endpoint_dependent)
-    return VNET_API_ERROR_FEATURE_DISABLED;
+    {
+      nat_log_err ("unsupported");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
 
   /* Check if address already exists */
   /* *INDENT-OFF* */
   vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
     {
       if (ap->addr.as_u32 == addr->as_u32)
-        return VNET_API_ERROR_VALUE_EXIST;
+        {
+          nat_log_err ("address exist");
+          return VNET_API_ERROR_VALUE_EXIST;
+        }
     }
   /* *INDENT-ON* */
 
@@ -636,14 +706,18 @@ snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
                                         nat_fib_src_low);
   else
     ap->fib_index = ~0;
-#define _(N, i, n, s) \
-  clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
-  ap->busy_##n##_ports = 0; \
-  ap->busy_##n##_ports_per_thread = 0;\
-  vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
-  foreach_nat_protocol
-#undef _
-    if (twice_nat)
+
+  /* *INDENT-OFF* */
+  #define _(N, i, n, s) \
+    clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
+    ap->busy_##n##_ports = 0; \
+    ap->busy_##n##_ports_per_thread = 0;\
+    vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
+    foreach_nat_protocol
+  #undef _
+  /* *INDENT-ON* */
+
+  if (twice_nat)
     return 0;
 
   /* Add external address to FIB */
@@ -1686,7 +1760,10 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
        }
     }
   if (!a)
-    return VNET_API_ERROR_NO_SUCH_ENTRY;
+    {
+      nat_log_err ("no such address");
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
 
   if (delete_sm)
     {
@@ -1713,7 +1790,7 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
       /* Check if address is used in some static mapping */
       if (is_snat_address_used_in_static_mapping (sm, addr))
        {
-         nat_elog_notice ("address used in static mapping");
+         nat_log_err ("address used in static mapping");
          return VNET_API_ERROR_UNSPECIFIED;
        }
     }
@@ -1894,14 +1971,26 @@ snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
   u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
                                                       sw_if_index);
 
+  if (!sm->enabled)
+    {
+      nat_log_err ("nat44 is disabled");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
+
   if (sm->out2in_dpo && !is_inside)
-    return VNET_API_ERROR_UNSUPPORTED;
+    {
+      nat_log_err ("error unsupported");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
 
   /* *INDENT-OFF* */
   pool_foreach (i, sm->output_feature_interfaces,
   ({
     if (i->sw_if_index == sw_if_index)
-      return VNET_API_ERROR_VALUE_EXIST;
+      {
+        nat_log_err ("error interface already configured");
+        return VNET_API_ERROR_VALUE_EXIST;
+      }
   }));
   /* *INDENT-ON* */
 
@@ -2082,7 +2171,10 @@ feature_set:
   /* *INDENT-ON* */
 
   if (is_del)
-    return VNET_API_ERROR_NO_SUCH_ENTRY;
+    {
+      nat_log_err ("error interface couldn't be found");
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
 
   pool_get (sm->interfaces, i);
   i->sw_if_index = sw_if_index;
@@ -2145,14 +2237,26 @@ snat_interface_add_del_output_feature (u32 sw_if_index,
   u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
                                                       sw_if_index);
 
+  if (!sm->enabled)
+    {
+      nat_log_err ("nat44 is disabled");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
+
   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
-    return VNET_API_ERROR_UNSUPPORTED;
+    {
+      nat_log_err ("error unsupported");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
 
   /* *INDENT-OFF* */
   pool_foreach (i, sm->interfaces,
   ({
     if (i->sw_if_index == sw_if_index)
-      return VNET_API_ERROR_VALUE_EXIST;
+      {
+        nat_log_err ("error interface already configured");
+        return VNET_API_ERROR_VALUE_EXIST;
+      }
   }));
   /* *INDENT-ON* */
 
@@ -2301,7 +2405,10 @@ fq:
   /* *INDENT-ON* */
 
   if (is_del)
-    return VNET_API_ERROR_NO_SUCH_ENTRY;
+    {
+      nat_log_err ("error interface couldn't be found");
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
 
   pool_get (sm->output_feature_interfaces, i);
   i->sw_if_index = sw_if_index;
@@ -2362,7 +2469,8 @@ snat_set_workers (uword * bitmap)
 }
 
 static void
-snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
+snat_update_outside_fib (ip4_main_t * im, uword opaque,
+                        u32 sw_if_index, u32 new_fib_index,
                         u32 old_fib_index)
 {
   snat_main_t *sm = &snat_main;
@@ -2371,11 +2479,11 @@ snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
   u8 is_add = 1;
   u8 match = 0;
 
-  if (new_fib_index == old_fib_index)
-    return;
-
-  if (!vec_len (sm->outside_fibs))
-    return;
+  if (!sm->enabled || (new_fib_index == old_fib_index)
+      || (!vec_len (sm->outside_fibs)))
+    {
+      return;
+    }
 
   /* *INDENT-OFF* */
   pool_foreach (i, sm->interfaces,
@@ -2432,12 +2540,9 @@ snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
 }
 
 static void
-snat_ip4_table_bind (ip4_main_t * im,
-                    uword opaque,
-                    u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
-{
-  snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
-}
+snat_update_outside_fib (ip4_main_t * im, uword opaque,
+                        u32 sw_if_index, u32 new_fib_index,
+                        u32 old_fib_index);
 
 static void
 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
@@ -2535,81 +2640,47 @@ nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add)
 
 VNET_IP_TABLE_ADD_DEL_FUNCTION (nat_ip_table_add_del);
 
-
-static clib_error_t *
-snat_init (vlib_main_t * vm)
+void
+nat44_set_node_indexes (snat_main_t * sm, vlib_main_t * vm)
 {
-  snat_main_t *sm = &snat_main;
-  clib_error_t *error = 0;
-  ip4_main_t *im = &ip4_main;
-  ip_lookup_main_t *lm = &im->lookup_main;
-  uword *p;
-  vlib_thread_registration_t *tr;
-  vlib_thread_main_t *tm = vlib_get_thread_main ();
-  uword *bitmap = 0;
-  u32 i;
-  ip4_add_del_interface_address_callback_t cb4;
   vlib_node_t *node;
 
-  sm->vnet_main = vnet_get_main ();
-  sm->ip4_main = im;
-  sm->ip4_lookup_main = lm;
-  sm->api_main = vlibapi_get_main ();
-  sm->first_worker_index = 0;
-  sm->num_workers = 0;
-  sm->workers = 0;
-  sm->port_per_thread = 0xffff - 1024;
-  sm->fq_in2out_index = ~0;
-  sm->fq_in2out_output_index = ~0;
-  sm->fq_out2in_index = ~0;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
+  sm->ei_out2in_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
+  sm->ei_in2out_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
+  sm->ei_in2out_output_node_index = node->index;
 
-  sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
-  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
-  sm->forwarding_enabled = 0;
-  sm->log_class = vlib_log_register_class ("nat", 0);
-  sm->log_level = SNAT_LOG_ERROR;
-  sm->mss_clamping = 0;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
+  sm->ed_out2in_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
+  sm->ed_in2out_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output");
+  sm->ed_in2out_output_node_index = node->index;
 
   node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
   sm->error_node_index = node->index;
-
   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
   sm->pre_in2out_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
   sm->pre_out2in_node_index = node->index;
-
   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
   sm->pre_in2out_node_index = node->index;
-
   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
   sm->pre_out2in_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
-  sm->in2out_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
-  sm->in2out_output_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
   sm->in2out_fast_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
   sm->in2out_slowpath_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
   sm->in2out_slowpath_output_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
-  sm->ed_in2out_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
   sm->ed_in2out_slowpath_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
-  sm->out2in_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
   sm->out2in_fast_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
-  sm->ed_out2in_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
   sm->ed_out2in_slowpath_node_index = node->index;
-
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
   sm->hairpinning_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
@@ -2622,63 +2693,55 @@ snat_init (vlib_main_t * vm)
   sm->ed_hairpin_dst_node_index = node->index;
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
   sm->ed_hairpin_src_node_index = node->index;
+}
 
-  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
-  if (p)
-    {
-      tr = (vlib_thread_registration_t *) p[0];
-      if (tr)
-       {
-         sm->num_workers = tr->count;
-         sm->first_worker_index = tr->first_index;
-       }
-    }
-
-  vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
-
-  /* Use all available workers by default */
-  if (sm->num_workers > 1)
-    {
-      for (i = 0; i < sm->num_workers; i++)
-       bitmap = clib_bitmap_set (bitmap, i, 1);
-      snat_set_workers (bitmap);
-      clib_bitmap_free (bitmap);
-    }
-  else
-    {
-      sm->per_thread_data[0].snat_thread_index = 0;
-    }
+#define nat_init_simple_counter(c, n, sn) \
+do                                        \
+  {                                       \
+    c.name = n;                           \
+    c.stat_segment_name = sn;             \
+    vlib_validate_simple_counter (&c, 0); \
+    vlib_zero_simple_counter (&c, 0);     \
+  } while (0);
 
-  error = snat_api_init (vm, sm);
-  if (error)
-    return error;
+static clib_error_t *
+nat_init (vlib_main_t * vm)
+{
+  snat_main_t *sm = &snat_main;
+  clib_error_t *error = 0;
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
+  vlib_thread_registration_t *tr;
+  ip4_add_del_interface_address_callback_t cbi = { 0 };
+  ip4_table_bind_callback_t cbt = { 0 };
+  u32 i, num_threads = 0;
+  uword *p, *bitmap = 0;
 
-  /* Set up the interface address add/del callback */
-  cb4.function = snat_ip4_add_del_interface_address_cb;
-  cb4.function_opaque = 0;
+  clib_memset (sm, 0, sizeof (*sm));
 
-  vec_add1 (im->add_del_interface_address_callbacks, cb4);
+  // required
+  sm->vnet_main = vnet_get_main ();
+  // convenience
+  sm->ip4_main = &ip4_main;
+  sm->api_main = vlibapi_get_main ();
+  sm->ip4_lookup_main = &ip4_main.lookup_main;
 
-  cb4.function = nat_ip4_add_del_addr_only_sm_cb;
-  cb4.function_opaque = 0;
+  // frame queue indices used for handoff
+  sm->fq_out2in_index = ~0;
+  sm->fq_in2out_index = ~0;
+  sm->fq_in2out_output_index = ~0;
 
-  vec_add1 (im->add_del_interface_address_callbacks, cb4);
+  sm->log_level = SNAT_LOG_ERROR;
 
-  nat_dpo_module_init ();
+  nat44_set_node_indexes (sm, vm);
+  sm->log_class = vlib_log_register_class ("nat", 0);
+  nat_ipfix_logging_init (vm);
 
-  /* 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);
-  sm->user_limit_reached.name = "user-limit-reached";
-  sm->user_limit_reached.stat_segment_name = "/nat44/user-limit-reached";
-  vlib_validate_simple_counter (&sm->user_limit_reached, 0);
-  vlib_zero_simple_counter (&sm->user_limit_reached, 0);
+  nat_init_simple_counter (sm->total_users, "total-users",
+                          "/nat44/total-users");
+  nat_init_simple_counter (sm->total_sessions, "total-sessions",
+                          "/nat44/total-sessions");
+  nat_init_simple_counter (sm->user_limit_reached, "user-limit-reached",
+                          "/nat44/user-limit-reached");
 
 #define _(x)                                            \
   sm->counters.fastpath.in2out.x.name = #x;             \
@@ -2710,26 +2773,345 @@ snat_init (vlib_main_t * vm)
   sm->counters.hairpinning.name = "hairpinning";
   sm->counters.hairpinning.stat_segment_name = "/nat44/hairpinning";
 
-  /* Init IPFIX logging */
-  nat_ipfix_logging_init (vm);
+  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
+  if (p)
+    {
+      tr = (vlib_thread_registration_t *) p[0];
+      if (tr)
+       {
+         sm->num_workers = tr->count;
+         sm->first_worker_index = tr->first_index;
+       }
+    }
+  num_threads = tm->n_vlib_mains - 1;
+  sm->port_per_thread = 0xffff - 1024;
+  vec_validate (sm->per_thread_data, num_threads);
 
-  ip4_table_bind_callback_t cbt4 = {
-    .function = snat_ip4_table_bind,
-  };
-  vec_add1 (ip4_main.table_bind_callbacks, cbt4);
+  /* Use all available workers by default */
+  if (sm->num_workers > 1)
+    {
 
-  nat_fib_src_hi = fib_source_allocate ("nat-hi",
-                                       FIB_SOURCE_PRIORITY_HI,
-                                       FIB_SOURCE_BH_SIMPLE);
-  nat_fib_src_low = fib_source_allocate ("nat-low",
-                                        FIB_SOURCE_PRIORITY_LOW,
-                                        FIB_SOURCE_BH_SIMPLE);
+      for (i = 0; i < sm->num_workers; i++)
+       bitmap = clib_bitmap_set (bitmap, i, 1);
+      snat_set_workers (bitmap);
+      clib_bitmap_free (bitmap);
+    }
+  else
+    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);
+
+  // TODO: is it possible to move it into snat_main ?
+  nat_fib_src_low =
+    fib_source_allocate ("nat-low", FIB_SOURCE_PRIORITY_LOW,
+                        FIB_SOURCE_BH_SIMPLE);
+  nat_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 ();
+  error = snat_api_init (vm, sm);
   return error;
 }
 
-VLIB_INIT_FUNCTION (snat_init);
+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;
+  //
+  sm->udp_timeout = SNAT_UDP_TIMEOUT;
+  sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
+  sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
+  sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
+
+  // 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.user_memory)
+    {
+      c.user_memory =
+       nat_calc_bihash_memory (c.users, sizeof (clib_bihash_8_8_t));
+    }
+  sm->user_memory_size = c.user_memory;
+
+  if (!c.sessions)
+    {
+      // default value based on legacy setting of load factor 10 * default
+      // translation buckets 1024
+      c.sessions = 10 * 1024;
+    }
+  sm->max_translations_per_thread = c.sessions;
+  sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
+
+  if (!c.session_memory)
+    {
+      c.session_memory =
+       nat_calc_bihash_memory
+       (sm->translation_buckets, sizeof (clib_bihash_16_8_t));
+    }
+  sm->translation_memory_size = c.session_memory;
+  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, nat_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, nat_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;
+
+      clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
+                            sm->translation_buckets,
+                            sm->translation_memory_size);
+      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;
+
+
+  nat_log_err ("nat44 enable");
+
+  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)
+    {
+      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);
+        }
+    }
+  /* *INDENT-ON* */
+  vec_free (vec);
+  sm->interfaces = 0;
+
+  vec = vec_dup (sm->output_feature_interfaces);
+  /* *INDENT-OFF* */
+  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);
+        }
+    }
+  /* *INDENT-ON* */
+  vec_free (vec);
+  sm->output_feature_interfaces = 0;
+
+  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* */
+    }
+
+  pool_free (sm->static_mappings);
+
+  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;
+
+  return 0;
+}
 
 void
 snat_free_outside_address_and_port (snat_address_t * addresses,
@@ -4017,7 +4399,8 @@ nat44_db_init (snat_main_per_thread_data_t * tsm)
       clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp);
     }
 
-  // TODO: resolve static mappings (put only to !ED)
+  // 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,
                        sm->user_memory_size);
@@ -4082,222 +4465,6 @@ nat44_sessions_clear ()
   /* *INDENT-ON* */
 }
 
-static clib_error_t *
-snat_config (vlib_main_t * vm, unformat_input_t * input)
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
-
-  u32 static_mapping_buckets = 1024;
-  uword static_mapping_memory_size = 64 << 20;
-
-  u32 max_users_per_thread = 0;
-  u32 user_memory_size = 0;
-  u32 max_translations_per_thread = 0;
-  u32 translation_memory_size = 0;
-
-  u32 max_translations_per_user = ~0;
-
-  u32 outside_vrf_id = 0;
-  u32 outside_ip6_vrf_id = 0;
-  u32 inside_vrf_id = 0;
-  u8 static_mapping_only = 0;
-  u8 static_mapping_connection_tracking = 0;
-
-  u32 udp_timeout = SNAT_UDP_TIMEOUT;
-  u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
-  u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
-  u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
-
-  sm->out2in_dpo = 0;
-  sm->endpoint_dependent = 0;
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat
-         (input, "max translations per thread %d",
-          &max_translations_per_thread))
-       ;
-      else if (unformat (input, "udp timeout %d", &udp_timeout))
-       ;
-      else if (unformat (input, "icmp timeout %d", &icmp_timeout))
-       ;
-      else if (unformat (input, "tcp transitory timeout %d",
-                        &tcp_transitory_timeout));
-      else if (unformat (input, "tcp established timeout %d",
-                        &tcp_established_timeout));
-      else if (unformat (input, "translation hash memory %d",
-                        &translation_memory_size));
-      else
-       if (unformat
-           (input, "max users per thread %d", &max_users_per_thread))
-       ;
-      else if (unformat (input, "user hash memory %d", &user_memory_size))
-       ;
-      else if (unformat (input, "max translations per user %d",
-                        &max_translations_per_user))
-       ;
-      else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
-       ;
-      else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
-       ;
-      else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
-       ;
-      else if (unformat (input, "static mapping only"))
-       {
-         static_mapping_only = 1;
-         if (unformat (input, "connection tracking"))
-           static_mapping_connection_tracking = 1;
-       }
-      else if (unformat (input, "out2in dpo"))
-       sm->out2in_dpo = 1;
-      else if (unformat (input, "endpoint-dependent"))
-       sm->endpoint_dependent = 1;
-      else
-       return clib_error_return (0, "unknown input '%U'",
-                                 format_unformat_error, input);
-    }
-
-  if (static_mapping_only && (sm->endpoint_dependent))
-    return clib_error_return (0,
-                             "static mapping only mode available only for simple nat");
-
-  if (sm->out2in_dpo && (sm->endpoint_dependent))
-    return clib_error_return (0,
-                             "out2in dpo mode available only for simple nat");
-  if (sm->endpoint_dependent && max_users_per_thread > 0)
-    {
-      return clib_error_return (0,
-                               "setting 'max users' in endpoint-dependent mode is not supported");
-    }
-
-  if (sm->endpoint_dependent && max_translations_per_user != ~0)
-    {
-      return clib_error_return (0,
-                               "setting 'max translations per user' in endpoint-dependent mode is not supported");
-    }
-
-  /* optionally configurable timeouts for testing purposes */
-  sm->udp_timeout = udp_timeout;
-  sm->tcp_transitory_timeout = tcp_transitory_timeout;
-  sm->tcp_established_timeout = tcp_established_timeout;
-  sm->icmp_timeout = icmp_timeout;
-
-  if (0 == max_users_per_thread)
-    {
-      max_users_per_thread = 1024;
-    }
-  sm->max_users_per_thread = max_users_per_thread;
-  sm->user_buckets = nat_calc_bihash_buckets (sm->max_users_per_thread);
-
-  if (0 == max_translations_per_thread)
-    {
-      // default value based on legacy setting of load factor 10 * default
-      // translation buckets 1024
-      max_translations_per_thread = 10 * 1024;
-    }
-  sm->translation_memory_size_set = translation_memory_size != 0;
-
-  sm->max_translations_per_thread = max_translations_per_thread;
-  sm->translation_buckets =
-    nat_calc_bihash_buckets (sm->max_translations_per_thread);
-  if (0 == translation_memory_size)
-    {
-      translation_memory_size =
-       nat_calc_bihash_memory (sm->translation_buckets,
-                               sizeof (clib_bihash_16_8_t));
-    }
-  sm->translation_memory_size = translation_memory_size;
-  if (0 == user_memory_size)
-    {
-      user_memory_size =
-       nat_calc_bihash_memory (sm->max_users_per_thread,
-                               sizeof (clib_bihash_8_8_t));
-    }
-  sm->user_memory_size = user_memory_size;
-  vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
-
-  sm->max_translations_per_user = max_translations_per_user == ~0 ?
-    sm->max_translations_per_thread : max_translations_per_user;
-
-  sm->outside_vrf_id = outside_vrf_id;
-  sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
-                                                            outside_vrf_id,
-                                                            nat_fib_src_hi);
-  sm->inside_vrf_id = inside_vrf_id;
-  sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
-                                                           inside_vrf_id,
-                                                           nat_fib_src_hi);
-  sm->static_mapping_only = static_mapping_only;
-  sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
-
-  if (sm->endpoint_dependent)
-    {
-      sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
-      sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
-
-      sm->in2out_node_index = nat44_ed_in2out_node.index;
-      sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
-      sm->out2in_node_index = nat44_ed_out2in_node.index;
-
-      sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
-      sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
-      nat_affinity_init (vm);
-      nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
-                  nat_ha_sref_ed_cb);
-      clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
-                            clib_max (1, sm->num_workers) *
-                            sm->translation_buckets,
-                            clib_max (1, sm->num_workers) *
-                            sm->translation_memory_size);
-      clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
-                                         format_ed_session_kvp);
-    }
-  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;
-
-      sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
-      sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
-      nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
-    }
-  if (!static_mapping_only ||
-      (static_mapping_only && static_mapping_connection_tracking))
-    {
-          /* *INDENT-OFF* */
-          vec_foreach (tsm, sm->per_thread_data)
-            {
-              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);
-
-  return 0;
-}
-
-VLIB_CONFIG_FUNCTION (snat_config, "nat");
-
 static void
 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
                                 uword opaque,
@@ -4313,6 +4480,9 @@ nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
   int i, rv;
   ip4_address_t l_addr;
 
+  if (!sm->enabled)
+    return;
+
   for (i = 0; i < vec_len (sm->to_resolve); i++)
     {
       rp = sm->to_resolve + i;
@@ -4379,6 +4549,9 @@ snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
   u8 twice_nat = 0;
   snat_address_t *addresses = sm->addresses;
 
+  if (!sm->enabled)
+    return;
+
   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
     {
       if (sw_if_index == sm->auto_add_sw_if_indices[i])
index 123bea5..2d16507 100644 (file)
 /* NAT buffer flags */
 #define SNAT_FLAG_HAIRPINNING (1 << 0)
 
+/* NAT44 API Configuration flags */
+#define foreach_nat44_config_flag  \
+  _(0x00, IS_ENDPOINT_INDEPENDENT) \
+  _(0x01, IS_ENDPOINT_DEPENDENT)   \
+  _(0x02, IS_STATIC_MAPPING_ONLY)  \
+  _(0x04, IS_CONNECTION_TRACKING)  \
+  _(0x08, IS_OUT2IN_DPO)
+
+typedef enum nat44_config_flags_t_
+{
+#define _(n,f) NAT44_API_##f = n,
+  foreach_nat44_config_flag
+#undef _
+} nat44_config_flags_t;
+
+typedef struct
+{
+  /* nat44 plugin features */
+  u8 static_mapping_only;
+  u8 connection_tracking;
+  u8 endpoint_dependent;
+  u8 out2in_dpo;
+
+  u32 inside_vrf;
+  u32 outside_vrf;
+
+  /* maximum number of users */
+  u32 users;
+  u32 user_memory;
+
+  /* maximum number of sessions */
+  u32 sessions;
+  u32 session_memory;
+
+  /* maximum number of ssessions per user */
+  u32 user_sessions;
+} nat44_config_t;
+
 typedef enum
 {
   NAT_NEXT_DROP,
@@ -551,16 +589,24 @@ typedef struct snat_main_s
   u32 pre_out2in_node_index;
   u32 pre_in2out_node_index;
 
+  u32 out2in_node_index;
   u32 in2out_node_index;
   u32 in2out_output_node_index;
+
   u32 in2out_fast_node_index;
   u32 in2out_slowpath_node_index;
   u32 in2out_slowpath_output_node_index;
-  u32 ed_in2out_node_index;
-  u32 ed_in2out_slowpath_node_index;
-  u32 out2in_node_index;
   u32 out2in_fast_node_index;
+
+  u32 ei_out2in_node_index;
+  u32 ei_in2out_node_index;
+  u32 ei_in2out_output_node_index;
+
   u32 ed_out2in_node_index;
+  u32 ed_in2out_node_index;
+  u32 ed_in2out_output_node_index;
+
+  u32 ed_in2out_slowpath_node_index;
   u32 ed_out2in_slowpath_node_index;
 
   u32 hairpinning_node_index;
@@ -574,10 +620,12 @@ typedef struct snat_main_s
   u8 forwarding_enabled;
 
   /* Config parameters */
+  u8 endpoint_dependent;
+
+  u8 out2in_dpo;
+  /* static mapping config */
   u8 static_mapping_only;
   u8 static_mapping_connection_tracking;
-  u8 out2in_dpo;
-  u8 endpoint_dependent;
 
   /* Is translation memory size calculated or user defined */
   u8 translation_memory_size_set;
@@ -597,7 +645,6 @@ typedef struct snat_main_s
   u32 inside_fib_index;
 
   /* values of various timeouts */
-  // proto timeouts
   u32 udp_timeout;
   u32 tcp_transitory_timeout;
   u32 tcp_established_timeout;
@@ -606,7 +653,7 @@ typedef struct snat_main_s
   /* TCP MSS clamping */
   u16 mss_clamping;
 
-  /* counters/gauges */
+  /* counters */
   vlib_simple_counter_main_t total_users;
   vlib_simple_counter_main_t total_sessions;
   vlib_simple_counter_main_t user_limit_reached;
@@ -673,10 +720,14 @@ typedef struct snat_main_s
   u8 log_level;
 
   /* convenience */
-  vnet_main_t *vnet_main;
+  api_main_t *api_main;
   ip4_main_t *ip4_main;
   ip_lookup_main_t *ip4_lookup_main;
-  api_main_t *api_main;
+
+  /* nat44 plugin enabled */
+  u8 enabled;
+
+  vnet_main_t *vnet_main;
 } snat_main_t;
 
 typedef struct
@@ -1087,6 +1138,23 @@ int nat44_o2i_ed_is_idle_session_cb (clib_bihash_kv_16_8_t * kv, void *arg);
 int nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg);
 int nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg);
 
+
+/**
+ * @brief Enable NAT44 plugin
+ *
+ * @param c         nat44_config_t
+ *
+ * @return 0 on success, non-zero value otherwise
+ */
+int nat44_plugin_enable (nat44_config_t c);
+
+/**
+ * @brief Disable NAT44 plugin
+ *
+ * @return 0 on success, non-zero value otherwise
+ */
+int nat44_plugin_disable ();
+
 /**
  * @brief Add external address to NAT44 pool
  *
index 680a1e2..a84c820 100644 (file)
 #define SUPPORTED_ONLY_IN_ED_MODE_STR \
   "This command is supported only in endpoint dependent mode"
 
+static clib_error_t *
+nat44_enable_command_fn (vlib_main_t * vm,
+                        unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  snat_main_t *sm = &snat_main;
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+
+  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");
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    {
+      if (nat44_plugin_enable (c) != 0)
+       return clib_error_return (0, "nat44 enable failed");
+      return 0;
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (!mode_set && unformat (line_input, "static-mapping-only"))
+       {
+         mode_set = 1;
+         c.static_mapping_only = 1;
+         if (unformat (line_input, "connection-tracking"))
+           {
+             c.connection_tracking = 1;
+           }
+       }
+      else if (!mode_set && unformat (line_input, "out2in-dpo"))
+       {
+         mode_set = 1;
+         c.out2in_dpo = 1;
+       }
+      else if (!mode_set && unformat (line_input, "endpoint-dependent"))
+       {
+         mode_set = 1;
+         c.endpoint_dependent = 1;
+       }
+      else if (unformat (input, "inside-vrf %u", &c.inside_vrf));
+      else if (unformat (input, "outside-vrf %u", &c.outside_vrf));
+      else if (unformat (input, "users %u", &c.users));
+      else if (unformat (input, "user-memory %u", &c.user_memory));
+      else if (unformat (input, "sessions %u", &c.sessions));
+      else if (unformat (input, "session-memory %u", &c.session_memory));
+      else if (unformat (input, "user-sessions %u", &c.user_sessions));
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (!(c.sessions && c.session_memory))
+    {
+      error =
+       clib_error_return (0,
+                          "either number of sessions or size of the memory is required");
+      goto done;
+    }
+
+  if (nat44_plugin_enable (c) != 0)
+    error = clib_error_return (0, "nat44 enable failed");
+done:
+  unformat_free (line_input);
+  return error;
+}
+
+static clib_error_t *
+nat44_disable_command_fn (vlib_main_t * vm,
+                         unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  snat_main_t *sm = &snat_main;
+  clib_error_t *error = 0;
+
+  if (sm->enabled)
+    return clib_error_return (0, "nat44 already disabled");
+
+  if (nat44_plugin_disable () != 0)
+    error = clib_error_return (0, "nat44 disable failed");
+
+  return error;
+}
+
 static clib_error_t *
 set_workers_command_fn (vlib_main_t * vm,
                        unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -1889,6 +1980,48 @@ VLIB_CLI_COMMAND (nat44_debug_fib_registration_command, static) = {
   .function = nat44_debug_fib_registration_command_fn,
 };
 
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 enable}
+ * Enable nat44 plugin
+ * To enable nat44, use:
+ *  vpp# nat44 enable sessions <n>
+ * To enable nat44 static mapping only, use:
+ *  vpp# nat44 enable sessions <n> static-mapping
+ * To enable nat44 static mapping with connection tracking, use:
+ *  vpp# nat44 enable sessions <n> static-mapping connection-tracking
+ * To enable nat44 out2in dpo, use:
+ *  vpp# nat44 enable sessions <n> out2in-dpo
+ * To enable nat44 endpoint-dependent, use:
+ *  vpp# nat44 enable sessions <n> endpoint-dependent
+ * To overwrite user hash configuration, use:
+ *  vpp# nat44 enable sessions <n> user-memory <n>
+ * To overwrite session hash configuration, use:
+ *  vpp# nat44 enable session-memory <n>
+ * To set inside-vrf outside-vrf, use:
+ *  vpp# nat44 enable sessions <n> inside-vrf <id> outside-vrf <id>
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_enable_command, static) = {
+  .path = "nat44 enable",
+  .short_help = "nat44 enable sessions <max-number> [users <max-number>] [static-mappig-only [connection-tracking]|out2in-dpo|endpoint-dependent] [inside-vrf <vrf-id>] [outside-vrf <vrf-id>] [user-memory <number>] [session-memory <number>] [user-sessions <max-number>]",
+  .function = nat44_enable_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 disable}
+ * Disable nat44 plugin
+ * To disable nat44, use:
+ *  vpp# nat44 disable
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_disable_command, static) = {
+  .path = "nat44 disable",
+  .short_help = "nat44 disable",
+  .function = nat44_disable_command_fn,
+};
+
 /*?
  * @cliexpar
  * @cliexstart{set snat workers}
index 2c22ae0..e7a7354 100644 (file)
@@ -43,24 +43,37 @@ format_affinity_kvp (u8 * s, va_list * args)
   return s;
 }
 
-clib_error_t *
-nat_affinity_init (vlib_main_t * vm)
+void
+nat_affinity_enable ()
 {
   nat_affinity_main_t *nam = &nat_affinity_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
-  clib_error_t *error = 0;
 
   if (tm->n_vlib_mains > 1)
     clib_spinlock_init (&nam->affinity_lock);
-
   clib_bihash_init_16_8 (&nam->affinity_hash, "nat-affinity",
                         AFFINITY_HASH_BUCKETS, AFFINITY_HASH_MEMORY);
   clib_bihash_set_kvp_format_fn_16_8 (&nam->affinity_hash,
                                      format_affinity_kvp);
+}
 
-  nam->vlib_main = vm;
+void
+nat_affinity_disable ()
+{
+  nat_affinity_main_t *nam = &nat_affinity_main;
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
 
-  return error;
+  if (tm->n_vlib_mains > 1)
+    clib_spinlock_free (&nam->affinity_lock);
+  clib_bihash_free_16_8 (&nam->affinity_hash);
+}
+
+clib_error_t *
+nat_affinity_init (vlib_main_t * vm)
+{
+  nat_affinity_main_t *nam = &nat_affinity_main;
+  nam->vlib_main = vm;
+  return 0;
 }
 
 static_always_inline void
index 358e682..d6bda6a 100644 (file)
@@ -78,6 +78,16 @@ u32 nat_affinity_get_per_service_list_head_index (void);
  */
 void nat_affinity_flush_service (u32 affinity_per_service_list_head_index);
 
+/**
+ * @brief NAT affinity enable
+ */
+void nat_affinity_enable ();
+
+/**
+ * @brief NAT affinity disable
+ */
+void nat_affinity_disable ();
+
 /**
  * @brief Initialize NAT client-IP based affinity.
  *
index 11d4ded..39f1af7 100644 (file)
@@ -333,6 +333,89 @@ vl_api_nat_set_log_level_t_print (vl_api_nat_set_log_level_t *
   FINISH;
 }
 
+static void
+  vl_api_nat44_plugin_enable_disable_t_handler
+  (vl_api_nat44_plugin_enable_disable_t * mp)
+{
+  snat_main_t *sm = &snat_main;
+  nat44_config_t c = { 0 };
+  vl_api_nat44_plugin_enable_disable_reply_t *rmp;
+  int rv = 0;
+
+  if (mp->enable)
+    {
+      c.endpoint_dependent = mp->flags & NAT44_API_IS_ENDPOINT_DEPENDENT;
+      c.static_mapping_only = mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY;
+      c.connection_tracking = mp->flags & NAT44_API_IS_CONNECTION_TRACKING;
+      c.out2in_dpo = mp->flags & NAT44_API_IS_OUT2IN_DPO;
+
+      c.inside_vrf = ntohl (mp->inside_vrf);
+      c.outside_vrf = ntohl (mp->outside_vrf);
+
+      c.users = ntohl (mp->users);
+      c.user_memory = ntohl (mp->user_memory);
+
+      c.sessions = ntohl (mp->sessions);
+      c.session_memory = ntohl (mp->session_memory);
+
+      c.user_sessions = ntohl (mp->user_sessions);
+
+      rv = nat44_plugin_enable (c);
+    }
+  else
+    rv = nat44_plugin_disable ();
+
+  REPLY_MACRO (VL_API_NAT44_PLUGIN_ENABLE_DISABLE_REPLY);
+}
+
+static void *vl_api_nat44_plugin_enable_disable_t_print
+  (vl_api_nat44_plugin_enable_disable_t * mp, void *handle)
+{
+  u8 *s;
+  u32 val;
+
+  s = format (0, "SCRIPT: nat44_plugin_enable_disable ");
+  if (mp->enable)
+    {
+      s = format (s, "enable ");
+      if (mp->flags & NAT44_API_IS_ENDPOINT_DEPENDENT)
+       s = format (s, "endpoint-dependent ");
+      else
+       s = format (s, "endpoint-indepenednet ");
+      if (mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY)
+       s = format (s, "static_mapping_only ");
+      if (mp->flags & NAT44_API_IS_CONNECTION_TRACKING)
+       s = format (s, "connection_tracking ");
+      if (mp->flags & NAT44_API_IS_OUT2IN_DPO)
+       s = format (s, "out2in_dpo ");
+      val = ntohl (mp->inside_vrf);
+      if (val)
+       s = format (s, "inside_vrf %u ", val);
+      val = ntohl (mp->outside_vrf);
+      if (val)
+       s = format (s, "outside_vrf %u ", val);
+      val = ntohl (mp->users);
+      if (val)
+       s = format (s, "users %u ", val);
+      val = ntohl (mp->user_memory);
+      if (val)
+       s = format (s, "user_memory %u ", val);
+      val = ntohl (mp->sessions);
+      if (val)
+       s = format (s, "sessions %u ", val);
+      val = ntohl (mp->session_memory);
+      if (val)
+       s = format (s, "session_memory %u ", val);
+      val = ntohl (mp->user_sessions);
+      if (val)
+       s = format (s, "user_sessions %u ", val);
+    }
+  else
+    s = format (s, "disable ");
+
+  FINISH;
+}
+
 static void
 vl_api_nat_ipfix_enable_disable_t_handler (vl_api_nat_ipfix_enable_disable_t *
                                           mp)
@@ -2228,6 +2311,7 @@ _(NAT_SHOW_CONFIG, nat_show_config)                                     \
 _(NAT_SHOW_CONFIG_2, nat_show_config_2)                                 \
 _(NAT_SET_WORKERS, nat_set_workers)                                     \
 _(NAT_WORKER_DUMP, nat_worker_dump)                                     \
+_(NAT44_PLUGIN_ENABLE_DISABLE, nat44_plugin_enable_disable)             \
 _(NAT44_DEL_USER, nat44_del_user)                                       \
 _(NAT44_SET_SESSION_LIMIT, nat44_set_session_limit)                     \
 _(NAT_SET_LOG_LEVEL, nat_set_log_level)                                 \
index ddfa3e4..93f762f 100644 (file)
@@ -310,35 +310,27 @@ nat_ha_resend_scan (f64 now, u32 thread_index)
 }
 
 void
-nat_ha_init (vlib_main_t * vm, nat_ha_sadd_cb_t sadd_cb,
-            nat_ha_sdel_cb_t sdel_cb, nat_ha_sref_cb_t sref_cb)
+nat_ha_enable (nat_ha_sadd_cb_t sadd_cb,
+              nat_ha_sdel_cb_t sdel_cb, nat_ha_sref_cb_t sref_cb)
 {
   nat_ha_main_t *ha = &nat_ha_main;
-  vlib_thread_main_t *tm = vlib_get_thread_main ();
-  vlib_thread_registration_t *tr;
-  uword *p;
-
-  ha->src_ip_address.as_u32 = 0;
-  ha->src_port = 0;
-  ha->dst_ip_address.as_u32 = 0;
-  ha->dst_port = 0;
-  ha->in_resync = 0;
-  ha->resync_ack_count = 0;
-  ha->resync_ack_missed = 0;
-  ha->vlib_main = vm;
+
   ha->sadd_cb = sadd_cb;
   ha->sdel_cb = sdel_cb;
   ha->sref_cb = sref_cb;
-  ha->num_workers = 0;
-  vec_validate (ha->per_thread_data, tm->n_vlib_mains - 1);
+}
+
+void
+nat_ha_init (vlib_main_t * vm, u32 num_workers, u32 num_threads)
+{
+  nat_ha_main_t *ha = &nat_ha_main;
+  clib_memset (ha, 0, sizeof (*ha));
+
+  ha->vlib_main = vm;
   ha->fq_index = ~0;
-  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
-  if (p)
-    {
-      tr = (vlib_thread_registration_t *) p[0];
-      if (tr)
-       ha->num_workers = tr->count;
-    }
+
+  ha->num_workers = num_workers;
+  vec_validate (ha->per_thread_data, num_threads);
 
 #define _(N, s, v) ha->counters[v].name = s;          \
   ha->counters[v].stat_segment_name = "/nat44/ha/" s; \
index ec62789..92fc337 100644 (file)
@@ -38,11 +38,16 @@ typedef void (*nat_ha_sref_cb_t) (ip4_address_t * out_addr, u16 out_port,
                                  u8 proto, u32 fib_index, u32 total_pkts,
                                  u64 total_bytes, u32 thread_index);
 
+/**
+ * @brief Enable NAT HA, set callbacks
+ */
+void nat_ha_enable (nat_ha_sadd_cb_t sadd_cb, nat_ha_sdel_cb_t sdel_cb,
+                   nat_ha_sref_cb_t sref_cb);
+
 /**
  * @brief Initialize NAT HA
  */
-void nat_ha_init (vlib_main_t * vm, nat_ha_sadd_cb_t sadd_cb,
-                 nat_ha_sdel_cb_t sdel_cb, nat_ha_sref_cb_t sref_cb);
+void nat_ha_init (vlib_main_t * vm, u32 num_workers, u32 num_threads);
 
 /**
  * @brief Set HA listener (local settings)
index a64f6c0..3b19b71 100644 (file)
@@ -75,104 +75,14 @@ class MethodHolder(VppTestCase):
     def config_flags(self):
         return VppEnum.vl_api_nat_config_flags_t
 
+    @property
+    def nat44_config_flags(self):
+        return VppEnum.vl_api_nat44_config_flags_t
+
     @property
     def SYSLOG_SEVERITY(self):
         return VppEnum.vl_api_syslog_severity_t
 
-    def clear_nat44(self):
-        """
-        Clear NAT44 configuration.
-        """
-        if hasattr(self, 'pg7') and hasattr(self, 'pg8'):
-            if self.pg7.has_ip4_config:
-                self.pg7.unconfig_ip4()
-
-        self.vapi.nat44_forwarding_enable_disable(enable=0)
-
-        interfaces = self.vapi.nat44_interface_addr_dump()
-        for intf in interfaces:
-            self.vapi.nat44_add_del_interface_addr(
-                is_add=0,
-                sw_if_index=intf.sw_if_index,
-                flags=intf.flags)
-
-        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                           src_port=self.ipfix_src_port,
-                                           enable=0)
-        self.ipfix_src_port = 4739
-        self.ipfix_domain_id = 1
-
-        self.vapi.syslog_set_filter(
-            self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_EMERG)
-
-        self.vapi.nat_ha_set_listener(ip_address='0.0.0.0', port=0,
-                                      path_mtu=512)
-        self.vapi.nat_ha_set_failover(ip_address='0.0.0.0', port=0,
-                                      session_refresh_interval=10)
-
-        interfaces = self.vapi.nat44_interface_dump()
-        for intf in interfaces:
-            if intf.flags & self.config_flags.NAT_IS_INSIDE and \
-                    intf.flags & self.config_flags.NAT_IS_OUTSIDE:
-                self.vapi.nat44_interface_add_del_feature(
-                    sw_if_index=intf.sw_if_index)
-            self.vapi.nat44_interface_add_del_feature(
-                sw_if_index=intf.sw_if_index,
-                flags=intf.flags)
-
-        interfaces = self.vapi.nat44_interface_output_feature_dump()
-        for intf in interfaces:
-            self.vapi.nat44_interface_add_del_output_feature(
-                is_add=0,
-                flags=intf.flags,
-                sw_if_index=intf.sw_if_index)
-        static_mappings = self.vapi.nat44_static_mapping_dump()
-        for sm in static_mappings:
-            self.vapi.nat44_add_del_static_mapping(
-                is_add=0,
-                local_ip_address=sm.local_ip_address,
-                external_ip_address=sm.external_ip_address,
-                external_sw_if_index=sm.external_sw_if_index,
-                local_port=sm.local_port,
-                external_port=sm.external_port,
-                vrf_id=sm.vrf_id,
-                protocol=sm.protocol,
-                flags=sm.flags, tag=sm.tag)
-
-        lb_static_mappings = self.vapi.nat44_lb_static_mapping_dump()
-        for lb_sm in lb_static_mappings:
-            self.vapi.nat44_add_del_lb_static_mapping(
-                is_add=0,
-                flags=lb_sm.flags,
-                external_addr=lb_sm.external_addr,
-                external_port=lb_sm.external_port,
-                protocol=lb_sm.protocol,
-                local_num=0, locals=[],
-                tag=lb_sm.tag)
-
-        identity_mappings = self.vapi.nat44_identity_mapping_dump()
-        for id_m in identity_mappings:
-            self.vapi.nat44_add_del_identity_mapping(
-                ip_address=id_m.ip_address,
-                sw_if_index=id_m.sw_if_index,
-                port=id_m.port,
-                flags=id_m.flags,
-                vrf_id=id_m.vrf_id,
-                protocol=id_m.protocol)
-
-        addresses = self.vapi.nat44_address_dump()
-        for addr in addresses:
-            self.vapi.nat44_add_del_address_range(
-                first_ip_address=addr.ip_address,
-                last_ip_address=addr.ip_address,
-                vrf_id=0xFFFFFFFF, flags=addr.flags)
-
-        self.verify_no_nat44_user()
-        self.vapi.nat_set_timeouts(udp=300, tcp_established=7440,
-                                   tcp_transitory=240, icmp=60)
-        self.vapi.nat_set_addr_and_port_alloc_alg()
-        self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
-
     def nat44_add_static_mapping(self, local_ip, external_ip='0.0.0.0',
                                  local_port=0, external_port=0, vrf_id=0,
                                  is_add=1, external_sw_if_index=0xFFFFFFFF,
@@ -1256,19 +1166,17 @@ class TestNATMisc(MethodHolder):
     max_translations = 10240
     max_users = 10240
 
-    @classmethod
-    def setUpConstants(cls):
-        super(TestNATMisc, cls).setUpConstants()
-        cls.vpp_cmdline.extend([
-            "nat", "{",
-            "max translations per thread %d" % cls.max_translations,
-            "max users per thread %d" % cls.max_users,
-            "}"
-        ])
+    def setUp(self):
+        super(TestNATMisc, self).setUp()
+        self.vapi.nat44_plugin_enable_disable(
+            sessions=self.max_translations,
+            users=self.max_users, enable=1)
 
-    @classmethod
-    def tearDownClass(cls):
-        super(TestNATMisc, cls).tearDownClass()
+    def tearDown(self):
+        super(TestNATMisc, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.cli("clear logging")
 
     def test_show_config(self):
         """ NAT config translation memory """
@@ -1299,16 +1207,6 @@ class TestNAT44(MethodHolder):
     max_translations = 10240
     max_users = 10240
 
-    @classmethod
-    def setUpConstants(cls):
-        super(TestNAT44, cls).setUpConstants()
-        cls.vpp_cmdline.extend([
-            "nat", "{",
-            "max translations per thread %d" % cls.max_translations,
-            "max users per thread %d" % cls.max_users,
-            "}"
-        ])
-
     @classmethod
     def setUpClass(cls):
         super(TestNAT44, cls).setUpClass()
@@ -1373,10 +1271,28 @@ class TestNAT44(MethodHolder):
         cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
         cls.pg9.resolve_arp()
 
+    def setUp(self):
+        super(TestNAT44, self).setUp()
+        self.vapi.nat44_plugin_enable_disable(
+            sessions=self.max_translations,
+            users=self.max_users, enable=1)
+
     @classmethod
     def tearDownClass(cls):
         super(TestNAT44, cls).tearDownClass()
 
+    def tearDown(self):
+        super(TestNAT44, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
+                                               src_port=self.ipfix_src_port,
+                                               enable=0)
+            self.ipfix_src_port = 4739
+            self.ipfix_domain_id = 1
+
+            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.cli("clear logging")
+
     def test_clear_sessions(self):
         """ NAT44 session clearing test """
 
@@ -4094,11 +4010,6 @@ class TestNAT44(MethodHolder):
             self.assertEqual(tcp.sport, self.tcp_external_port)
             self.assertEqual(tcp.dport, self.tcp_port_in)
 
-    def tearDown(self):
-        super(TestNAT44, self).tearDown()
-        self.clear_nat44()
-        self.vapi.cli("clear logging")
-
     def show_commands_at_teardown(self):
         self.logger.info(self.vapi.cli("show nat44 addresses"))
         self.logger.info(self.vapi.cli("show nat44 interfaces"))
@@ -4115,11 +4026,6 @@ class TestNAT44(MethodHolder):
 class TestNAT44EndpointDependent2(MethodHolder):
     """ Endpoint-Dependent mapping and filtering test cases """
 
-    @classmethod
-    def setUpConstants(cls):
-        super(TestNAT44EndpointDependent2, cls).setUpConstants()
-        cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
-
     @classmethod
     def tearDownClass(cls):
         super(TestNAT44EndpointDependent2, cls).tearDownClass()
@@ -4151,9 +4057,14 @@ class TestNAT44EndpointDependent2(MethodHolder):
 
     def setUp(self):
         super(TestNAT44EndpointDependent2, self).setUp()
+        flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
+        self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
 
-        nat_config = self.vapi.nat_show_config()
-        self.assertEqual(1, nat_config.endpoint_dependent)
+    def tearDown(self):
+        super(TestNAT44EndpointDependent2, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.cli("clear logging")
 
     def nat_add_inside_interface(self, i):
         self.vapi.nat44_interface_add_del_feature(
@@ -4248,11 +4159,6 @@ class TestNAT44EndpointDependent2(MethodHolder):
 class TestNAT44EndpointDependent(MethodHolder):
     """ Endpoint-Dependent mapping and filtering test cases """
 
-    @classmethod
-    def setUpConstants(cls):
-        super(TestNAT44EndpointDependent, cls).setUpConstants()
-        cls.vpp_cmdline.extend(["nat", "{", "endpoint-dependent", "}"])
-
     @classmethod
     def setUpClass(cls):
         super(TestNAT44EndpointDependent, cls).setUpClass()
@@ -4352,14 +4258,23 @@ class TestNAT44EndpointDependent(MethodHolder):
         cls.pg8.config_ip4()
         cls.pg8.resolve_arp()
 
+    @classmethod
+    def tearDownClass(cls):
+        super(TestNAT44EndpointDependent, cls).tearDownClass()
+
     def setUp(self):
         super(TestNAT44EndpointDependent, self).setUp()
+        flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
+        self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
         self.vapi.nat_set_timeouts(
-            udp=300, tcp_established=7440, tcp_transitory=240, icmp=60)
+            udp=300, tcp_established=7440,
+            tcp_transitory=240, icmp=60)
 
-    @classmethod
-    def tearDownClass(cls):
-        super(TestNAT44EndpointDependent, cls).tearDownClass()
+    def tearDown(self):
+        super(TestNAT44EndpointDependent, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.cli("clear logging")
 
     def test_frag_in_order(self):
         """ NAT44 translate fragments arriving in order """
@@ -7120,12 +7035,6 @@ class TestNAT44EndpointDependent(MethodHolder):
                 external_sw_if_index=0xFFFFFFFF,
                 flags=flags)
 
-    def tearDown(self):
-        super(TestNAT44EndpointDependent, self).tearDown()
-        if not self.vpp_dead:
-            self.clear_nat44()
-            self.vapi.cli("clear logging")
-
     def show_commands_at_teardown(self):
         self.logger.info(self.vapi.cli("show errors"))
         self.logger.info(self.vapi.cli("show nat44 addresses"))
@@ -7143,15 +7052,6 @@ class TestNAT44EndpointDependent3(MethodHolder):
 
     max_translations = 50
 
-    @classmethod
-    def setUpConstants(cls):
-        super(TestNAT44EndpointDependent3, cls).setUpConstants()
-        cls.vpp_cmdline.extend([
-            "nat", "{", "endpoint-dependent",
-            "max translations per thread %d" % cls.max_translations,
-            "}"
-        ])
-
     @classmethod
     def setUpClass(cls):
         super(TestNAT44EndpointDependent3, cls).setUpClass()
@@ -7168,8 +7068,13 @@ class TestNAT44EndpointDependent3(MethodHolder):
 
     def setUp(self):
         super(TestNAT44EndpointDependent3, self).setUp()
+        flags = self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT
+        self.vapi.nat44_plugin_enable_disable(
+            sessions=self.max_translations,
+            flags=flags, enable=1)
         self.vapi.nat_set_timeouts(
             udp=1, tcp_established=7440, tcp_transitory=30, icmp=1)
+
         self.nat44_add_address(self.nat_addr)
         flags = self.config_flags.NAT_IS_INSIDE
         self.vapi.nat44_interface_add_del_feature(
@@ -7181,6 +7086,12 @@ class TestNAT44EndpointDependent3(MethodHolder):
     def tearDownClass(cls):
         super(TestNAT44EndpointDependent3, cls).tearDownClass()
 
+    def tearDown(self):
+        super(TestNAT44EndpointDependent3, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.cli("clear logging")
+
     def init_tcp_session(self, in_if, out_if, sport, ext_dport):
         # SYN packet in->out
         p = (Ether(src=in_if.remote_mac, dst=in_if.local_mac) /
@@ -7245,11 +7156,6 @@ class TestNAT44EndpointDependent3(MethodHolder):
 class TestNAT44Out2InDPO(MethodHolder):
     """ NAT44 Test Cases using out2in DPO """
 
-    @classmethod
-    def setUpConstants(cls):
-        super(TestNAT44Out2InDPO, cls).setUpConstants()
-        cls.vpp_cmdline.extend(["nat", "{", "out2in dpo", "}"])
-
     @classmethod
     def setUpClass(cls):
         super(TestNAT44Out2InDPO, cls).setUpClass()
@@ -7284,6 +7190,17 @@ class TestNAT44Out2InDPO(MethodHolder):
     def tearDownClass(cls):
         super(TestNAT44Out2InDPO, cls).tearDownClass()
 
+    def setUp(self):
+        super(TestNAT44Out2InDPO, self).setUp()
+        flags = self.nat44_config_flags.NAT44_API_IS_OUT2IN_DPO
+        self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
+
+    def tearDown(self):
+        super(TestNAT44Out2InDPO, self).tearDown()
+        if not self.vpp_dead:
+            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.cli("clear logging")
+
     def configure_xlat(self):
         self.dst_ip6_pfx = '1:2:3::'
         self.dst_ip6_pfx_n = socket.inet_pton(socket.AF_INET6,