nat: nat44-ei configuration improvements 16/33916/9
authorFilip Varga <fivarga@cisco.com>
Thu, 30 Sep 2021 11:35:59 +0000 (13:35 +0200)
committerOle Tr�an <otroan@employees.org>
Wed, 20 Oct 2021 10:47:27 +0000 (10:47 +0000)
nat44-ed core configuration improvements & fixes [0-5] adjusted
for nat44-ei plugin.

Improvements:
 * repeating code converted to functions
 * simplified functions used for pool address, static mapping
and interface configuration.

Clean up:
 * remove obsolete code and logic persisted after plugin
separation from old SNAT plugin.

Fixes:
 * [0] return correct API behavior changed in [5]

Type: improvement

[0] https://gerrit.fd.io/r/c/vpp/+/33622
[1] https://gerrit.fd.io/r/c/vpp/+/33431
[2] https://gerrit.fd.io/r/c/vpp/+/33337
[3] https://gerrit.fd.io/r/c/vpp/+/33249
[4] https://gerrit.fd.io/r/c/vpp/+/32796
[5] https://gerrit.fd.io/r/c/vpp/+/32951

Signed-off-by: Filip Varga <fivarga@cisco.com>
Change-Id: Ie197faa576cb49acb3d218f14e00cb7d13ad9342

src/plugins/nat/nat44-ei/nat44_ei.api
src/plugins/nat/nat44-ei/nat44_ei.c
src/plugins/nat/nat44-ei/nat44_ei.h
src/plugins/nat/nat44-ei/nat44_ei_api.c
src/plugins/nat/nat44-ei/nat44_ei_cli.c
src/plugins/nat/nat44-ei/nat44_ei_handoff.c
test/test_nat44_ei.py

index 9ea1a3a..e535906 100644 (file)
@@ -550,6 +550,45 @@ define nat44_ei_interface_output_feature_details {
   vl_api_interface_index_t sw_if_index;
 };
 
+/** \brief add/del NAT output interface (postrouting
+           in2out translation)
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param is_add - true if add, false if delete
+    @param sw_if_index - software index of the interface
+*/
+autoendian autoreply define nat44_ei_add_del_output_interface {
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_interface_index_t sw_if_index;
+};
+
+service {
+  rpc nat44_ei_output_interface_get returns nat44_ei_output_interface_get_reply
+    stream nat44_ei_output_interface_details;
+};
+
+define nat44_ei_output_interface_get
+{
+  u32 client_index;
+  u32 context;
+  u32 cursor;
+};
+
+define nat44_ei_output_interface_get_reply
+{
+  u32 context;
+  i32 retval;
+  u32 cursor;
+};
+
+define nat44_ei_output_interface_details
+{
+  u32 context;
+  vl_api_interface_index_t sw_if_index;
+};
+
 /** \brief Add/delete NAT44 static mapping
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
index 3691af3..694bc6b 100644 (file)
@@ -304,6 +304,76 @@ nat_validate_interface_counters (nat44_ei_main_t *nm, u32 sw_if_index)
   nat_validate_simple_counter (nm->counters.hairpinning, sw_if_index);
 }
 
+static void
+nat44_ei_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i;
+
+  pool_foreach (i, nm->interfaces)
+    {
+      if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo)
+       {
+         nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add);
+       }
+    }
+  pool_foreach (i, nm->output_feature_interfaces)
+    {
+      if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo)
+       {
+         nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add);
+       }
+    }
+}
+
+static_always_inline void
+nat44_ei_add_del_addr_to_fib_foreach_addr (u32 sw_if_index, u8 is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *ap;
+
+  vec_foreach (ap, nm->addresses)
+    {
+      nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add);
+    }
+}
+
+static_always_inline void
+nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (u32 sw_if_index, u8 is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m;
+
+  pool_foreach (m, nm->static_mappings)
+    {
+      if (is_sm_addr_only (m->flags) &&
+         !(m->local_addr.as_u32 == m->external_addr.as_u32))
+       {
+         nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
+                                       is_add);
+       }
+    }
+}
+
+static int
+nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m;
+  pool_foreach (m, nm->static_mappings)
+    {
+      if (is_sm_addr_only (m->flags) || is_sm_identity_nat (m->flags))
+       {
+         continue;
+       }
+      if (m->external_addr.as_u32 == addr.as_u32)
+       {
+         return 1;
+       }
+    }
+  return 0;
+}
+
 clib_error_t *
 nat44_ei_init (vlib_main_t *vm)
 {
@@ -372,14 +442,15 @@ nat44_ei_init (vlib_main_t *vm)
   /* Use all available workers by default */
   if (nm->num_workers > 1)
     {
-
       for (i = 0; i < nm->num_workers; i++)
        bitmap = clib_bitmap_set (bitmap, i, 1);
       nat44_ei_set_workers (bitmap);
       clib_bitmap_free (bitmap);
     }
   else
-    nm->per_thread_data[0].snat_thread_index = 0;
+    {
+      nm->per_thread_data[0].snat_thread_index = 0;
+    }
 
   /* callbacks to call when interface address changes. */
   cbi.function = nat44_ei_ip4_add_del_interface_address_cb;
@@ -472,6 +543,25 @@ nat44_ei_plugin_enable (nat44_ei_config_t c)
   vlib_zero_simple_counter (&nm->total_sessions, 0);
   vlib_zero_simple_counter (&nm->user_limit_reached, 0);
 
+  if (nm->num_workers > 1)
+    {
+      if (nm->fq_in2out_index == ~0)
+       {
+         nm->fq_in2out_index = vlib_frame_queue_main_init (
+           nm->in2out_node_index, nm->frame_queue_nelts);
+       }
+      if (nm->fq_out2in_index == ~0)
+       {
+         nm->fq_out2in_index = vlib_frame_queue_main_init (
+           nm->out2in_node_index, nm->frame_queue_nelts);
+       }
+      if (nm->fq_in2out_output_index == ~0)
+       {
+         nm->fq_in2out_output_index = vlib_frame_queue_main_init (
+           nm->in2out_output_node_index, nm->frame_queue_nelts);
+       }
+    }
+
   nat_ha_enable ();
   nm->enabled = 1;
 
@@ -492,17 +582,44 @@ nat44_ei_addresses_free (nat44_ei_address_t **addresses)
   *addresses = 0;
 }
 
-int
-nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
+static_always_inline nat44_ei_outside_fib_t *
+nat44_ei_get_outside_fib (nat44_ei_outside_fib_t *outside_fibs, u32 fib_index)
+{
+  nat44_ei_outside_fib_t *f;
+  vec_foreach (f, outside_fibs)
+    {
+      if (f->fib_index == fib_index)
+       {
+         return f;
+       }
+    }
+  return 0;
+}
+
+static_always_inline nat44_ei_interface_t *
+nat44_ei_get_interface (nat44_ei_interface_t *interfaces, u32 sw_if_index)
+{
+  nat44_ei_interface_t *i;
+  pool_foreach (i, interfaces)
+    {
+      if (i->sw_if_index == sw_if_index)
+       {
+         return i;
+       }
+    }
+  return 0;
+}
+
+static_always_inline int
+nat44_ei_add_interface (u32 sw_if_index, u8 is_inside)
 {
   const char *feature_name, *del_feature_name;
   nat44_ei_main_t *nm = &nat44_ei_main;
-  nat44_ei_interface_t *i;
-  nat44_ei_address_t *ap;
-  nat44_ei_static_mapping_t *m;
+
   nat44_ei_outside_fib_t *outside_fib;
-  u32 fib_index =
-    fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+  nat44_ei_interface_t *i;
+  u32 fib_index;
+  int rv;
 
   fail_if_disabled ();
 
@@ -512,410 +629,481 @@ nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
       return VNET_API_ERROR_UNSUPPORTED;
     }
 
-  pool_foreach (i, nm->output_feature_interfaces)
+  if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index))
     {
-      if (i->sw_if_index == sw_if_index)
-       {
-         nat44_ei_log_err ("error interface already configured");
-         return VNET_API_ERROR_VALUE_EXIST;
-       }
+      nat44_ei_log_err ("error interface already configured");
+      return VNET_API_ERROR_VALUE_EXIST;
     }
 
-  if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking))
-    feature_name = is_inside ? "nat44-ei-in2out-fast" : "nat44-ei-out2in-fast";
-  else
+  i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
+  if (i)
     {
+      if ((nat44_ei_interface_is_inside (i) && is_inside) ||
+         (nat44_ei_interface_is_outside (i) && !is_inside))
+       {
+         return 0;
+       }
       if (nm->num_workers > 1)
-       feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
-                                  "nat44-ei-out2in-worker-handoff";
+       {
+         del_feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" :
+                                         "nat44-ei-out2in-worker-handoff";
+         feature_name = "nat44-ei-handoff-classify";
+       }
       else
-       feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
-    }
-
-  if (nm->fq_in2out_index == ~0 && nm->num_workers > 1)
-    nm->fq_in2out_index = vlib_frame_queue_main_init (nm->in2out_node_index,
-                                                     nm->frame_queue_nelts);
+       {
+         del_feature_name =
+           !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
 
-  if (nm->fq_out2in_index == ~0 && nm->num_workers > 1)
-    nm->fq_out2in_index = vlib_frame_queue_main_init (nm->out2in_node_index,
-                                                     nm->frame_queue_nelts);
+         feature_name = "nat44-ei-classify";
+       }
 
-  if (!is_inside)
-    {
-      vec_foreach (outside_fib, nm->outside_fibs)
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+      if (rv)
        {
-         if (outside_fib->fib_index == fib_index)
-           {
-             if (is_del)
-               {
-                 outside_fib->refcount--;
-                 if (!outside_fib->refcount)
-                   vec_del1 (nm->outside_fibs,
-                             outside_fib - nm->outside_fibs);
-               }
-             else
-               outside_fib->refcount++;
-             goto feature_set;
-           }
+         return rv;
        }
-      if (!is_del)
+      rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
+                                       sw_if_index, 0, 0, 0);
+      if (rv)
        {
-         vec_add2 (nm->outside_fibs, outside_fib, 1);
-         outside_fib->refcount = 1;
-         outside_fib->fib_index = fib_index;
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                       sw_if_index, 1, 0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      if (!is_inside)
+       {
+         rv = vnet_feature_enable_disable (
+           "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
+         if (rv)
+           {
+             return rv;
+           }
        }
     }
-
-feature_set:
-  pool_foreach (i, nm->interfaces)
+  else
     {
-      if (i->sw_if_index == sw_if_index)
+      if (nm->num_workers > 1)
        {
-         if (is_del)
-           {
-             if (nat44_ei_interface_is_inside (i) &&
-                 nat44_ei_interface_is_outside (i))
-               {
-                 if (is_inside)
-                   i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
-                 else
-                   i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
-
-                 if (nm->num_workers > 1)
-                   {
-                     del_feature_name = "nat44-ei-handoff-classify";
-                     clib_warning (
-                       "del_feature_name = nat44-ei-handoff-classify");
-                     feature_name = !is_inside ?
-                                      "nat44-ei-in2out-worker-handoff" :
-                                      "nat44-ei-out2in-worker-handoff";
-                   }
-                 else
-                   {
-                     del_feature_name = "nat44-ei-classify";
-                     clib_warning ("del_feature_name = nat44-ei-classify");
-                     feature_name =
-                       !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
-                   }
+         feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
+                                    "nat44-ei-out2in-worker-handoff";
+       }
+      else
+       {
+         feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+       }
+      nat_validate_interface_counters (nm, sw_if_index);
 
-                 int rv =
-                   ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
-                 if (rv)
-                   return rv;
-                 rv = vnet_feature_enable_disable (
-                   "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0);
-                 if (rv)
-                   return rv;
-                 rv = vnet_feature_enable_disable (
-                   "ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
-                 if (rv)
-                   return rv;
-                 if (!is_inside)
-                   {
-                     rv = vnet_feature_enable_disable ("ip4-local",
-                                                       "nat44-ei-hairpinning",
-                                                       sw_if_index, 1, 0, 0);
-                     if (rv)
-                       return rv;
-                   }
-               }
-             else
-               {
-                 int rv =
-                   ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
-                 if (rv)
-                   return rv;
-                 rv = vnet_feature_enable_disable (
-                   "ip4-unicast", feature_name, sw_if_index, 0, 0, 0);
-                 if (rv)
-                   return rv;
-                 pool_put (nm->interfaces, i);
-                 if (is_inside)
-                   {
-                     rv = vnet_feature_enable_disable ("ip4-local",
-                                                       "nat44-ei-hairpinning",
-                                                       sw_if_index, 0, 0, 0);
-                     if (rv)
-                       return rv;
-                   }
-               }
-           }
-         else
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                       sw_if_index, 1, 0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      if (is_inside && !nm->out2in_dpo)
+       {
+         rv = vnet_feature_enable_disable (
+           "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0);
+         if (rv)
            {
-             if ((nat44_ei_interface_is_inside (i) && is_inside) ||
-                 (nat44_ei_interface_is_outside (i) && !is_inside))
-               return 0;
-
-             if (nm->num_workers > 1)
-               {
-                 del_feature_name = !is_inside ?
-                                      "nat44-ei-in2out-worker-handoff" :
-                                      "nat44-ei-out2in-worker-handoff";
-                 feature_name = "nat44-ei-handoff-classify";
-                 clib_warning ("feature_name = nat44-ei-handoff-classify");
-               }
-             else
-               {
-                 del_feature_name =
-                   !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
-                 feature_name = "nat44-ei-classify";
-                 clib_warning ("feature_name = nat44-ei-classify");
-               }
-
-             int rv =
-               ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
-             if (rv)
-               return rv;
-             rv = vnet_feature_enable_disable (
-               "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0);
-             if (rv)
-               return rv;
-             rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
-                                               sw_if_index, 1, 0, 0);
-             if (rv)
-               return rv;
-             if (!is_inside)
-               {
-                 rv = vnet_feature_enable_disable (
-                   "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
-                 if (rv)
-                   return rv;
-               }
-             goto set_flags;
+             return rv;
            }
-
-         goto fib;
        }
-    }
 
-  if (is_del)
-    {
-      nat44_ei_log_err ("error interface couldn't be found");
-      return VNET_API_ERROR_NO_SUCH_ENTRY;
+      pool_get (nm->interfaces, i);
+      i->sw_if_index = sw_if_index;
+      i->flags = 0;
     }
 
-  pool_get (nm->interfaces, i);
-  i->sw_if_index = sw_if_index;
-  i->flags = 0;
-  nat_validate_interface_counters (nm, sw_if_index);
-
-  int rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
-                                       sw_if_index, 1, 0, 0);
-  if (rv)
-    return rv;
-
-  rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
-  if (rv)
-    return rv;
+  fib_index =
+    fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
 
-  if (is_inside && !nm->out2in_dpo)
+  if (!is_inside)
     {
-      rv = vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning",
-                                       sw_if_index, 1, 0, 0);
-      if (rv)
-       return rv;
-    }
+      i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
 
-set_flags:
-  if (is_inside)
-    {
-      i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
-      return 0;
+      outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+      if (outside_fib)
+       {
+         outside_fib->refcount++;
+       }
+      else
+       {
+         vec_add2 (nm->outside_fibs, outside_fib, 1);
+         outside_fib->fib_index = fib_index;
+         outside_fib->refcount = 1;
+       }
+
+      nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1);
+      nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1);
     }
   else
-    i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
-
-  /* Add/delete external addresses to FIB */
-fib:
-  vec_foreach (ap, nm->addresses)
-    nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, !is_del);
-
-  pool_foreach (m, nm->static_mappings)
     {
-      if (!(nat44_ei_is_addr_only_static_mapping (m)) ||
-         (m->local_addr.as_u32 == m->external_addr.as_u32))
-       continue;
-
-      nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
-                                   !is_del);
+      i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
     }
 
   return 0;
 }
 
-int
-nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside,
-                                          int is_del)
+static_always_inline int
+nat44_ei_del_interface (u32 sw_if_index, u8 is_inside)
 {
+  const char *feature_name, *del_feature_name;
   nat44_ei_main_t *nm = &nat44_ei_main;
-  nat44_ei_interface_t *i;
-  nat44_ei_address_t *ap;
-  nat44_ei_static_mapping_t *m;
+
   nat44_ei_outside_fib_t *outside_fib;
-  u32 fib_index =
-    fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+  nat44_ei_interface_t *i;
+  u32 fib_index;
+  int rv;
 
   fail_if_disabled ();
 
-  if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking))
+  if (nm->out2in_dpo && !is_inside)
     {
       nat44_ei_log_err ("error unsupported");
       return VNET_API_ERROR_UNSUPPORTED;
     }
 
-  pool_foreach (i, nm->interfaces)
+  i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
+  if (i == 0)
     {
-      if (i->sw_if_index == sw_if_index)
-       {
-         nat44_ei_log_err ("error interface already configured");
-         return VNET_API_ERROR_VALUE_EXIST;
-       }
+      nat44_ei_log_err ("error interface couldn't be found");
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
     }
 
-  if (!is_inside)
+  if (nat44_ei_interface_is_inside (i) && nat44_ei_interface_is_outside (i))
     {
-      vec_foreach (outside_fib, nm->outside_fibs)
+      if (nm->num_workers > 1)
        {
-         if (outside_fib->fib_index == fib_index)
-           {
-             if (is_del)
-               {
-                 outside_fib->refcount--;
-                 if (!outside_fib->refcount)
-                   vec_del1 (nm->outside_fibs,
-                             outside_fib - nm->outside_fibs);
-               }
-             else
-               outside_fib->refcount++;
-             goto feature_set;
-           }
+         del_feature_name = "nat44-ei-handoff-classify";
+         feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" :
+                                     "nat44-ei-out2in-worker-handoff";
        }
-      if (!is_del)
+      else
        {
-         vec_add2 (nm->outside_fibs, outside_fib, 1);
-         outside_fib->refcount = 1;
-         outside_fib->fib_index = fib_index;
+         del_feature_name = "nat44-ei-classify";
+         feature_name = !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
        }
-    }
 
-feature_set:
-  if (is_inside)
-    {
-      int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
-      if (rv)
-       return rv;
-      rv =
-       ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
       if (rv)
-       return rv;
-      rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-hairpin-dst",
-                                       sw_if_index, !is_del, 0, 0);
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
+                                       sw_if_index, 0, 0, 0);
       if (rv)
-       return rv;
-      rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-hairpin-src",
-                                       sw_if_index, !is_del, 0, 0);
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                       sw_if_index, 1, 0, 0);
       if (rv)
-       return rv;
-      goto fq;
+       {
+         return rv;
+       }
+      if (is_inside)
+       {
+         i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+       }
+      else
+       {
+         rv = vnet_feature_enable_disable (
+           "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0);
+         if (rv)
+           {
+             return rv;
+           }
+         i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+       }
+    }
+  else
+    {
+      if (nm->num_workers > 1)
+       {
+         feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
+                                    "nat44-ei-out2in-worker-handoff";
+       }
+      else
+       {
+         feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+       }
+
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                       sw_if_index, 0, 0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      if (is_inside)
+       {
+         rv = vnet_feature_enable_disable (
+           "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
+         if (rv)
+           {
+             return rv;
+           }
+       }
+
+      // remove interface
+      pool_put (nm->interfaces, i);
+    }
+
+  if (!is_inside)
+    {
+      fib_index =
+       fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+      outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+      if (outside_fib)
+       {
+         outside_fib->refcount--;
+         if (!outside_fib->refcount)
+           {
+             vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
+           }
+       }
+
+      nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 0);
+      nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0);
+    }
+
+  return 0;
+}
+
+int
+nat44_ei_add_del_interface (u32 sw_if_index, u8 is_inside, int is_del)
+{
+  if (is_del)
+    {
+      return nat44_ei_del_interface (sw_if_index, is_inside);
+    }
+  else
+    {
+      return nat44_ei_add_interface (sw_if_index, is_inside);
+    }
+}
+
+static_always_inline int
+nat44_ei_add_output_interface (u32 sw_if_index)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  nat44_ei_outside_fib_t *outside_fib;
+  nat44_ei_interface_t *i;
+  u32 fib_index;
+  int rv;
+
+  fail_if_disabled ();
+
+  if (nat44_ei_get_interface (nm->interfaces, sw_if_index))
+    {
+      nat44_ei_log_err ("error interface already configured");
+      return VNET_API_ERROR_VALUE_EXIST;
+    }
+
+  if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index))
+    {
+      nat44_ei_log_err ("error interface already configured");
+      return VNET_API_ERROR_VALUE_EXIST;
     }
 
   if (nm->num_workers > 1)
     {
-      int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
       if (rv)
-       return rv;
-      rv =
-       ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
+       {
+         return rv;
+       }
+      rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
       if (rv)
-       return rv;
-      rv = vnet_feature_enable_disable ("ip4-unicast",
-                                       "nat44-ei-out2in-worker-handoff",
-                                       sw_if_index, !is_del, 0, 0);
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable (
+       "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 1, 0, 0);
       if (rv)
-       return rv;
+       {
+         return rv;
+       }
       rv = vnet_feature_enable_disable (
-       "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index,
-       !is_del, 0, 0);
+       "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 1,
+       0, 0);
       if (rv)
-       return rv;
+       {
+         return rv;
+       }
     }
   else
     {
-      int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
       if (rv)
-       return rv;
-      rv =
-       ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
+       {
+         return rv;
+       }
+      rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
       if (rv)
-       return rv;
+       {
+         return rv;
+       }
       rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
-                                       sw_if_index, !is_del, 0, 0);
+                                       sw_if_index, 1, 0, 0);
       if (rv)
-       return rv;
+       {
+         return rv;
+       }
       rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
-                                       sw_if_index, !is_del, 0, 0);
+                                       sw_if_index, 1, 0, 0);
       if (rv)
-       return rv;
+       {
+         return rv;
+       }
     }
 
-fq:
-  if (nm->fq_in2out_output_index == ~0 && nm->num_workers > 1)
-    nm->fq_in2out_output_index =
-      vlib_frame_queue_main_init (nm->in2out_output_node_index, 0);
+  nat_validate_interface_counters (nm, sw_if_index);
 
-  if (nm->fq_out2in_index == ~0 && nm->num_workers > 1)
-    nm->fq_out2in_index =
-      vlib_frame_queue_main_init (nm->out2in_node_index, 0);
+  pool_get (nm->output_feature_interfaces, i);
+  i->sw_if_index = sw_if_index;
+  i->flags = 0;
+  i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+  i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
 
-  pool_foreach (i, nm->output_feature_interfaces)
+  fib_index =
+    fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+  outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+  if (outside_fib)
     {
-      if (i->sw_if_index == sw_if_index)
-       {
-         if (is_del)
-           pool_put (nm->output_feature_interfaces, i);
-         else
-           return VNET_API_ERROR_VALUE_EXIST;
-
-         goto fib;
-       }
+      outside_fib->refcount++;
+    }
+  else
+    {
+      vec_add2 (nm->outside_fibs, outside_fib, 1);
+      outside_fib->fib_index = fib_index;
+      outside_fib->refcount = 1;
     }
 
-  if (is_del)
+  nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1);
+  nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1);
+
+  return 0;
+}
+
+static_always_inline int
+nat44_ei_del_output_interface (u32 sw_if_index)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  nat44_ei_outside_fib_t *outside_fib;
+  nat44_ei_interface_t *i;
+  u32 fib_index;
+  int rv;
+
+  fail_if_disabled ();
+
+  i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index);
+  if (!i)
     {
       nat44_ei_log_err ("error interface couldn't be found");
       return VNET_API_ERROR_NO_SUCH_ENTRY;
     }
 
-  pool_get (nm->output_feature_interfaces, i);
-  i->sw_if_index = sw_if_index;
-  i->flags = 0;
-  nat_validate_interface_counters (nm, sw_if_index);
-  if (is_inside)
-    i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+  if (nm->num_workers > 1)
+    {
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable (
+       "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 0, 0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable (
+       "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 0,
+       0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+    }
   else
-    i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
-
-  /* Add/delete external addresses to FIB */
-fib:
-  if (is_inside)
-    return 0;
+    {
+      rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
+                                       sw_if_index, 0, 0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+      rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
+                                       sw_if_index, 0, 0, 0);
+      if (rv)
+       {
+         return rv;
+       }
+    }
 
-  vec_foreach (ap, nm->addresses)
-    nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, !is_del);
+  pool_put (nm->output_feature_interfaces, i);
 
-  pool_foreach (m, nm->static_mappings)
+  fib_index =
+    fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+  outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+  if (outside_fib)
     {
-      if (!((nat44_ei_is_addr_only_static_mapping (m))) ||
-         (m->local_addr.as_u32 == m->external_addr.as_u32))
-       continue;
-
-      nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
-                                   !is_del);
+      outside_fib->refcount--;
+      if (!outside_fib->refcount)
+       {
+         vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
+       }
     }
 
+  nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1);
+  nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1);
+
   return 0;
 }
 
+int
+nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del)
+{
+  if (is_del)
+    {
+      return nat44_ei_del_output_interface (sw_if_index);
+    }
+  else
+    {
+      return nat44_ei_add_output_interface (sw_if_index);
+    }
+}
+
 int
 nat44_ei_plugin_disable ()
 {
@@ -928,9 +1116,13 @@ nat44_ei_plugin_disable ()
   pool_foreach (i, pool)
     {
       if (nat44_ei_interface_is_inside (i))
-       error = nat44_ei_interface_add_del (i->sw_if_index, 1, 1);
+       {
+         error = nat44_ei_del_interface (i->sw_if_index, 1);
+       }
       if (nat44_ei_interface_is_outside (i))
-       error = nat44_ei_interface_add_del (i->sw_if_index, 0, 1);
+       {
+         error = nat44_ei_del_interface (i->sw_if_index, 0);
+       }
 
       if (error)
        {
@@ -944,13 +1136,7 @@ nat44_ei_plugin_disable ()
   pool = pool_dup (nm->output_feature_interfaces);
   pool_foreach (i, pool)
     {
-      if (nat44_ei_interface_is_inside (i))
-       error =
-         nat44_ei_interface_add_del_output_feature (i->sw_if_index, 1, 1);
-      if (nat44_ei_interface_is_outside (i))
-       error =
-         nat44_ei_interface_add_del_output_feature (i->sw_if_index, 0, 1);
-
+      error = nat44_ei_del_output_interface (i->sw_if_index);
       if (error)
        {
          nat44_ei_log_err ("error occurred while removing interface %u",
@@ -1727,30 +1913,6 @@ nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length)
   nm->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)
-{
-  nat44_ei_main_t *nm = &nat44_ei_main;
-  nat44_ei_static_map_resolve_t *rp;
-
-  vec_add2 (nm->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);
-}
-
 void
 nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
                         u32 thread_index)
@@ -1789,10 +1951,13 @@ nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
 {
   nat44_ei_main_per_thread_data_t *tnm;
   clib_bihash_kv_8_8_t kv, value;
-  u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+  u32 fib_index;
   nat44_ei_session_t *s;
   clib_bihash_8_8_t *t;
 
+  fail_if_disabled ();
+
+  fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
   init_nat_k (&kv, *addr, port, fib_index, proto);
   t = is_in ? &nm->in2out : &nm->out2in;
   if (!clib_bihash_search_8_8 (t, &kv, &value))
@@ -1842,412 +2007,563 @@ nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index,
   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
 
   if (is_add)
-    fib_table_entry_update_one_path (
-      fib_index, &prefix, nm->fib_src_low,
-      (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL |
-       FIB_ENTRY_FLAG_EXCLUSIVE),
-      DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
+    {
+      fib_table_entry_update_one_path (fib_index, &prefix, nm->fib_src_low,
+                                      (FIB_ENTRY_FLAG_CONNECTED |
+                                       FIB_ENTRY_FLAG_LOCAL |
+                                       FIB_ENTRY_FLAG_EXCLUSIVE),
+                                      DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1,
+                                      NULL, FIB_ROUTE_PATH_FLAG_NONE);
+    }
   else
-    fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
+    {
+      fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
+    }
 }
 
 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)
+nat44_ei_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
 {
+  u32 ti = nat44_ei_get_thread_idx_by_port (port);
   nat44_ei_main_t *nm = &nat44_ei_main;
-  nat44_ei_static_mapping_t *m = 0;
-  clib_bihash_kv_8_8_t kv, value;
   nat44_ei_address_t *a = 0;
-  u32 fib_index = ~0;
-  nat44_ei_interface_t *interface;
-  nat44_ei_main_per_thread_data_t *tnm;
-  nat44_ei_user_key_t u_key;
-  nat44_ei_user_t *u;
-  dlist_elt_t *head, *elt;
-  u32 elt_index, head_index;
-  u32 ses_index;
-  u64 user_index;
-  nat44_ei_session_t *s;
-  nat44_ei_static_map_resolve_t *rp, *rp_match = 0;
-  nat44_ei_lb_addr_port_t *local;
-  u32 find = ~0;
   int i;
 
-  if (sw_if_index != ~0)
+  for (i = 0; i < vec_len (nm->addresses); i++)
     {
-      ip4_address_t *first_int_addr;
+      a = nm->addresses + i;
 
-      for (i = 0; i < vec_len (nm->to_resolve); i++)
-       {
-         rp = nm->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 (
-       nm->ip4_main, sw_if_index, 0 /* just want the address */);
+      if (a->addr.as_u32 != addr.as_u32)
+       continue;
 
-      if (is_add)
+      switch (proto)
        {
-         if (rp_match)
-           return VNET_API_ERROR_VALUE_EXIST;
+#define _(N, j, n, s)                                                         \
+  case NAT_PROTOCOL_##N:                                                      \
+    if (a->busy_##n##_port_refcounts[port])                                   \
+      goto done;                                                              \
+    ++a->busy_##n##_port_refcounts[port];                                     \
+    if (port > 1024)                                                          \
+      {                                                                       \
+       a->busy_##n##_ports++;                                                \
+       a->busy_##n##_ports_per_thread[ti]++;                                 \
+      }                                                                       \
+    break;
+         foreach_nat_protocol
+#undef _
+           default : nat_elog_info (nm, "unknown protocol");
+         goto done;
+       }
 
-         nat44_ei_add_static_mapping_when_resolved (
-           l_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only,
-           identity_nat, tag);
+      return 0;
+    }
 
-         /* DHCP resolution required? */
-         if (!first_int_addr)
-           return 0;
+done:
+  return 1;
+}
 
-         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;
+int
+nat44_ei_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
+{
+  u32 ti = nat44_ei_get_thread_idx_by_port (port);
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a = 0;
+  int i;
 
-         vec_del1 (nm->to_resolve, i);
+  for (i = 0; i < vec_len (nm->addresses); i++)
+    {
+      a = nm->addresses + i;
 
-         if (!first_int_addr)
-           return 0;
+      if (a->addr.as_u32 != addr.as_u32)
+       continue;
 
-         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;
+      switch (proto)
+       {
+#define _(N, j, n, s)                                                         \
+  case NAT_PROTOCOL_##N:                                                      \
+    --a->busy_##n##_port_refcounts[port];                                     \
+    if (port > 1024)                                                          \
+      {                                                                       \
+       a->busy_##n##_ports--;                                                \
+       a->busy_##n##_ports_per_thread[ti]--;                                 \
+      }                                                                       \
+    break;
+         foreach_nat_protocol
+#undef _
+           default : nat_elog_info (nm, "unknown protocol");
+         goto done;
        }
+
+      return 0;
     }
 
-  init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto);
-  if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
-    m = pool_elt_at_index (nm->static_mappings, value.value);
+done:
+  return 1;
+}
 
-  if (is_add)
-    {
-      if (m)
-       {
-         // identity mapping for second vrf
-         if (nat44_ei_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, nm->fib_src_low);
-             init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
-                          m->proto, 0, m - nm->static_mappings);
-             clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
-             return 0;
-           }
-         return VNET_API_ERROR_VALUE_EXIST;
-       }
+void
+nat44_ei_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
+                            nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
+                            u32 flags, ip4_address_t pool_addr, u8 *tag)
+{
+  nat44_ei_static_map_resolve_t *rp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
-      /* Convert VRF id to FIB index */
-      if (vrf_id != ~0)
-       {
-         fib_index = fib_table_find_or_create_and_lock (
-           FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
-       }
-      /* If not specified use inside VRF id from NAT44 plugin config */
-      else
-       {
-         fib_index = nm->inside_fib_index;
-         vrf_id = nm->inside_vrf_id;
-         fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
-       }
+  vec_add2 (nm->to_resolve, rp, 1);
+  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->flags = flags;
+  rp->pool_addr = pool_addr;
+  rp->tag = vec_dup (tag);
+}
 
-      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 (&nm->static_mapping_by_local, &kv,
-                                      &value))
-           return VNET_API_ERROR_VALUE_EXIST;
-       }
+int
+nat44_ei_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
+                            nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
+                            u32 flags, int *out)
+{
+  nat44_ei_static_map_resolve_t *rp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  int i;
+
+  for (i = 0; i < vec_len (nm->to_resolve); i++)
+    {
+      rp = nm->to_resolve + i;
 
-      /* Find external address in allocated addresses and reserve port for
-        address and port pair mapping when dynamic translations enabled */
-      if (!(addr_only || nm->static_mapping_only))
+      if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id)
        {
-         for (i = 0; i < vec_len (nm->addresses); i++)
+         if (is_sm_identity_nat (rp->flags) && is_sm_identity_nat (flags))
            {
-             if (nm->addresses[i].addr.as_u32 == e_addr.as_u32)
+             if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
                {
-                 a = nm->addresses + i;
-                 /* External port must be unused */
-                 switch (proto)
+                 if (rp->e_port != e_port || rp->proto != 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[nat44_ei_get_thread_idx_by_port (      \
-         e_port)]++;                                                         \
-      }                                                                       \
-    break;
-                     foreach_nat_protocol
-#undef _
-                       default : nat_elog_info (nm, "unknown protocol");
-                     return VNET_API_ERROR_INVALID_VALUE_2;
+                     continue;
                    }
-                 break;
                }
            }
-         /* External address must be allocated */
-         if (!a && (l_addr.as_u32 != e_addr.as_u32))
+         else if (rp->l_addr.as_u32 == l_addr.as_u32)
            {
-             if (sw_if_index != ~0)
+             if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
                {
-                 for (i = 0; i < vec_len (nm->to_resolve); i++)
+                 if (rp->l_port != l_port || rp->e_port != e_port ||
+                     rp->proto != proto)
                    {
-                     rp = nm->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 (nm->to_resolve, i);
-                     break;
+                     continue;
                    }
                }
-             return VNET_API_ERROR_NO_SUCH_ENTRY;
            }
+         else
+           {
+             continue;
+           }
+         if (out)
+           {
+             *out = i;
+           }
+         return 0;
        }
+    }
+  return 1;
+}
 
-      pool_get (nm->static_mappings, m);
-      clib_memset (m, 0, sizeof (*m));
-      m->tag = vec_dup (tag);
-      m->local_addr = l_addr;
-      m->external_addr = e_addr;
+int
+nat44_ei_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
+                            nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
+                            u32 flags)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  int i;
+  if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+                                   sw_if_index, flags, &i))
+    {
+      vec_del1 (nm->to_resolve, i);
+      return 0;
+    }
+  return 1;
+}
 
-      if (addr_only)
-       m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY;
-      else
+void
+delete_matching_dynamic_sessions (const nat44_ei_static_mapping_t *m,
+                                 u32 worker_index)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_session_t *s;
+  nat44_ei_user_key_t u_key;
+  nat44_ei_user_t *u;
+  nat44_ei_main_per_thread_data_t *tnm;
+  dlist_elt_t *head, *elt;
+  u32 elt_index, head_index;
+  u32 ses_index;
+  u64 user_index;
+
+  if (nm->static_mapping_only)
+    return;
+
+  tnm = vec_elt_at_index (nm->per_thread_data, worker_index);
+
+  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 (&tnm->user_hash, &kv, &value))
+    {
+      user_index = value.value;
+      u = pool_elt_at_index (tnm->users, user_index);
+      if (u->nsessions)
        {
-         m->local_port = l_port;
-         m->external_port = e_port;
-         m->proto = proto;
+         head_index = u->sessions_per_user_list_head_index;
+         head = pool_elt_at_index (tnm->list_pool, head_index);
+         elt_index = head->next;
+         elt = pool_elt_at_index (tnm->list_pool, elt_index);
+         ses_index = elt->value;
+         while (ses_index != ~0)
+           {
+             s = pool_elt_at_index (tnm->sessions, ses_index);
+             elt = pool_elt_at_index (tnm->list_pool, elt->next);
+             ses_index = elt->value;
+
+             if (nat44_ei_is_session_static (s))
+               continue;
+
+             if (!is_sm_addr_only (m->flags) &&
+                 s->in2out.port != m->local_port)
+               continue;
+
+             nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data,
+                                            0);
+             nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
+
+             if (!is_sm_addr_only (m->flags))
+               break;
+           }
        }
+    }
+}
 
-      if (identity_nat)
+int
+nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
+                            u16 l_port, u16 e_port, nat_protocol_t proto,
+                            u32 vrf_id, u32 sw_if_index, u32 flags,
+                            ip4_address_t pool_addr, u8 *tag)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_lb_addr_port_t *local;
+  nat44_ei_static_mapping_t *m;
+  u32 fib_index = ~0;
+  u32 worker_index;
+
+  fail_if_disabled ();
+
+  if (is_sm_addr_only (flags))
+    {
+      e_port = l_port = proto = 0;
+    }
+
+  if (sw_if_index != ~0)
+    {
+      // this mapping is interface bound
+      ip4_address_t *first_int_addr;
+
+      // check if this record isn't registered for resolve
+      if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+                                       sw_if_index, flags, 0))
        {
-         m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT;
-         pool_get (m->locals, local);
-         local->vrf_id = vrf_id;
-         local->fib_index = fib_index;
+         return VNET_API_ERROR_VALUE_EXIST;
        }
-      else
+      // register record for resolve
+      nat44_ei_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+                                  sw_if_index, flags, pool_addr, tag);
+
+      first_int_addr =
+       ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
+      if (!first_int_addr)
        {
-         m->vrf_id = vrf_id;
-         m->fib_index = fib_index;
+         // dhcp resolution required
+         return 0;
        }
 
-      if (nm->num_workers > 1)
+      e_addr.as_u32 = first_int_addr->as_u32;
+    }
+
+  if (is_sm_identity_nat (flags))
+    {
+      l_port = e_port;
+      l_addr.as_u32 = e_addr.as_u32;
+    }
+
+  // fib index 0
+  init_nat_k (&kv, e_addr, e_port, 0, proto);
+
+  if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
+    {
+      m = pool_elt_at_index (nm->static_mappings, value.value);
+      if (!is_sm_identity_nat (m->flags))
        {
-         ip4_header_t ip = {
-           .src_address = m->local_addr,
-         };
-         vec_add1 (m->workers,
-                   nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0));
-         tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
+         return VNET_API_ERROR_VALUE_EXIST;
        }
-      else
-       tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
 
-      init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
-                  m - nm->static_mappings);
+      // case:
+      // adding local identity nat record for different vrf table
+      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, nm->fib_src_low);
+
+      init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
+                  m->proto, 0, m - nm->static_mappings);
       clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
 
-      init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
-                  m - nm->static_mappings);
-      clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1);
+      return 0;
+    }
 
-      /* Delete dynamic sessions matching local address (+ local port) */
-      // TODO: based on type of NAT EI/ED
-      if (!(nm->static_mapping_only))
+  if (vrf_id != ~0)
+    {
+      fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
+                                                    nm->fib_src_low);
+    }
+  else
+    {
+      // fallback to default vrf
+      vrf_id = nm->inside_vrf_id;
+      fib_index = nm->inside_fib_index;
+      fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
+    }
+
+  if (!is_sm_identity_nat (flags))
+    {
+      init_nat_k (&kv, l_addr, l_port, fib_index, proto);
+      if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
        {
-         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 (&tnm->user_hash, &kv, &value))
+         return VNET_API_ERROR_VALUE_EXIST;
+       }
+    }
+
+  if (!(is_sm_addr_only (flags) || nm->static_mapping_only))
+    {
+      if (nat44_ei_reserve_port (e_addr, e_port, proto))
+       {
+         // remove resolve record
+         if ((sw_if_index != ~0) && !is_sm_identity_nat (flags))
            {
-             user_index = value.value;
-             u = pool_elt_at_index (tnm->users, user_index);
-             if (u->nsessions)
-               {
-                 head_index = u->sessions_per_user_list_head_index;
-                 head = pool_elt_at_index (tnm->list_pool, head_index);
-                 elt_index = head->next;
-                 elt = pool_elt_at_index (tnm->list_pool, elt_index);
-                 ses_index = elt->value;
-                 while (ses_index != ~0)
-                   {
-                     s = pool_elt_at_index (tnm->sessions, ses_index);
-                     elt = pool_elt_at_index (tnm->list_pool, elt->next);
-                     ses_index = elt->value;
+             nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto,
+                                          vrf_id, sw_if_index, flags);
+           }
+         return VNET_API_ERROR_NO_SUCH_ENTRY;
+       }
+    }
+
+  pool_get (nm->static_mappings, m);
+  clib_memset (m, 0, sizeof (*m));
+
+  m->flags = flags;
+  m->local_addr = l_addr;
+  m->external_addr = e_addr;
+
+  m->tag = vec_dup (tag);
+
+  if (!is_sm_addr_only (flags))
+    {
+      m->local_port = l_port;
+      m->external_port = e_port;
+      m->proto = proto;
+    }
+
+  if (is_sm_identity_nat (flags))
+    {
+      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;
+    }
+
+  init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
+              m - nm->static_mappings);
+  clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
+
+  init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
+              m - nm->static_mappings);
+  clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1);
+
+  if (nm->num_workers > 1)
+    {
+      // store worker index for this record
+      ip4_header_t ip = {
+       .src_address = m->local_addr,
+      };
+      worker_index = nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0);
+      vec_add1 (m->workers, worker_index);
+    }
+  else
+    {
+      worker_index = nm->num_workers;
+    }
+  delete_matching_dynamic_sessions (m, worker_index);
+
+  if (is_sm_addr_only (flags))
+    {
+      nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 1);
+    }
+
+  return 0;
+}
+
+int
+nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
+                            u16 l_port, u16 e_port, nat_protocol_t proto,
+                            u32 vrf_id, u32 sw_if_index, u32 flags)
+{
+  nat44_ei_main_per_thread_data_t *tnm;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_lb_addr_port_t *local;
+  nat44_ei_static_mapping_t *m;
+  u32 fib_index = ~0;
+  nat44_ei_user_key_t u_key;
+
+  fail_if_disabled ();
+
+  if (is_sm_addr_only (flags))
+    {
+      e_port = l_port = proto = 0;
+    }
+
+  if (sw_if_index != ~0)
+    {
+      // this mapping is interface bound
+      ip4_address_t *first_int_addr;
+
+      // delete record registered for resolve
+      if (nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+                                      sw_if_index, flags))
+       {
+         return VNET_API_ERROR_NO_SUCH_ENTRY;
+       }
 
-                     if (nat44_ei_is_session_static (s))
-                       continue;
+      first_int_addr =
+       ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
+      if (!first_int_addr)
+       {
+         // dhcp resolution required
+         return 0;
+       }
 
-                     if (!addr_only && s->in2out.port != m->local_port)
-                       continue;
+      e_addr.as_u32 = first_int_addr->as_u32;
+    }
 
-                     nat44_ei_free_session_data_v2 (
-                       nm, s, tnm - nm->per_thread_data, 0);
-                     nat44_ei_delete_session (nm, s,
-                                              tnm - nm->per_thread_data);
+  if (is_sm_identity_nat (flags))
+    {
+      l_port = e_port;
+      l_addr.as_u32 = e_addr.as_u32;
+    }
 
-                     if (!addr_only)
-                       break;
-                   }
-               }
-           }
+  // fib index 0
+  init_nat_k (&kv, e_addr, e_port, 0, proto);
+
+  if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
+    {
+      if (sw_if_index != ~0)
+       {
+         return 0;
        }
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
     }
-  else
+
+  m = pool_elt_at_index (nm->static_mappings, value.value);
+
+  if (is_sm_identity_nat (flags))
     {
-      if (!m)
+      u8 found = 0;
+
+      if (vrf_id == ~0)
        {
-         if (sw_if_index != ~0)
-           return 0;
-         else
-           return VNET_API_ERROR_NO_SUCH_ENTRY;
+         vrf_id = nm->inside_vrf_id;
        }
 
-      if (identity_nat)
+      pool_foreach (local, m->locals)
        {
-         if (vrf_id == ~0)
-           vrf_id = nm->inside_vrf_id;
-
-         pool_foreach (local, m->locals)
+         if (local->vrf_id == vrf_id)
            {
-             if (local->vrf_id == vrf_id)
-               find = local - m->locals;
+             local = pool_elt_at_index (m->locals, local - m->locals);
+             fib_index = local->fib_index;
+             pool_put (m->locals, local);
+             found = 1;
            }
-         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;
+      if (!found)
+       {
+         return VNET_API_ERROR_NO_SUCH_ENTRY;
+       }
+    }
+  else
+    {
+      fib_index = m->fib_index;
+    }
 
-      /* Free external address port */
-      if (!(addr_only || nm->static_mapping_only))
+  if (!(is_sm_addr_only (flags) || nm->static_mapping_only))
+    {
+      if (nat44_ei_free_port (e_addr, e_port, proto))
        {
-         for (i = 0; i < vec_len (nm->addresses); i++)
-           {
-             if (nm->addresses[i].addr.as_u32 == e_addr.as_u32)
-               {
-                 a = nm->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[nat44_ei_get_thread_idx_by_port (      \
-         e_port)]--;                                                         \
-      }                                                                       \
-    break;
-                     foreach_nat_protocol
-#undef _
-                       default : return VNET_API_ERROR_INVALID_VALUE_2;
-                   }
-                 break;
-               }
-           }
+         return VNET_API_ERROR_INVALID_VALUE;
        }
+    }
 
+  init_nat_k (&kv, l_addr, l_port, fib_index, proto);
+  clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0);
+
+  if (!nm->static_mapping_only || nm->static_mapping_connection_tracking)
+    {
+      // delete sessions for static mapping
       if (nm->num_workers > 1)
        tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
       else
        tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
 
-      init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto);
-      clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0);
-
-      /* Delete session(s) for static mapping if exist */
-      if (!(nm->static_mapping_only) ||
-         (nm->static_mapping_only && nm->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 (nm, tnm, u_key, addr_only,
-                                               e_addr, e_port);
-       }
+      u_key.addr = m->local_addr;
+      u_key.fib_index = fib_index;
+      kv.key = u_key.as_u64;
+      nat44_ei_static_mapping_del_sessions (
+       nm, tnm, u_key, is_sm_addr_only (flags), e_addr, e_port);
+    }
 
-      fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
-      if (pool_elts (m->locals))
-       return 0;
+  fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
 
-      init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
+  if (!pool_elts (m->locals))
+    {
+      // this is last record remove all required stuff
+      // fib_index 0
+      init_nat_k (&kv, e_addr, e_port, 0, proto);
       clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 0);
 
       vec_free (m->tag);
       vec_free (m->workers);
-      /* Delete static mapping from pool */
       pool_put (nm->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, nm->interfaces)
-    {
-      if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
-       continue;
-
-      nat44_ei_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index,
-                                   is_add);
-      break;
+      if (is_sm_addr_only (flags) && !is_sm_identity_nat (flags))
+       {
+         nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 0);
+       }
     }
-  pool_foreach (interface, nm->output_feature_interfaces)
-    {
-      if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
-       continue;
 
-      nat44_ei_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index,
-                                   is_add);
-      break;
-    }
   return 0;
 }
 
@@ -2302,16 +2618,16 @@ nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
     }
 
   /* Address only mapping doesn't change port */
-  if (nat44_ei_is_addr_only_static_mapping (m))
+  if (is_sm_addr_only (m->flags))
     *mapping_port = match_port;
   else
     *mapping_port = port;
 
   if (PREDICT_FALSE (is_addr_only != 0))
-    *is_addr_only = nat44_ei_is_addr_only_static_mapping (m);
+    *is_addr_only = is_sm_addr_only (m->flags);
 
   if (PREDICT_FALSE (is_identity_nat != 0))
-    *is_identity_nat = nat44_ei_is_identity_static_mapping (m);
+    *is_identity_nat = is_sm_identity_nat (m->flags);
 
   return 0;
 }
@@ -2574,11 +2890,13 @@ nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque, u32 sw_if_index,
 }
 
 int
-nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id)
+nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id)
 {
-  nat44_ei_address_t *ap;
-  nat44_ei_interface_t *i;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
+  nat44_ei_address_t *ap;
+
+  fail_if_disabled ();
 
   /* Check if address already exists */
   vec_foreach (ap, nm->addresses)
@@ -2592,12 +2910,14 @@ nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id)
 
   vec_add2 (nm->addresses, ap, 1);
 
+  ap->fib_index = ~0;
   ap->addr = *addr;
+
   if (vrf_id != ~0)
-    ap->fib_index = fib_table_find_or_create_and_lock (
-      FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
-  else
-    ap->fib_index = ~0;
+    {
+      ap->fib_index = fib_table_find_or_create_and_lock (
+       FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
+    }
 
 #define _(N, i, n, s)                                                         \
   clib_memset (ap->busy_##n##_port_refcounts, 0,                              \
@@ -2609,120 +2929,30 @@ nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id)
   foreach_nat_protocol
 #undef _
 
-    /* Add external address to FIB */
-    pool_foreach (i, nm->interfaces)
-  {
-    if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo)
-      continue;
-
-    nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
-    break;
-  }
-  pool_foreach (i, nm->output_feature_interfaces)
-    {
-      if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo)
-       continue;
-
-      nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
-      break;
-    }
+    nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1);
 
   return 0;
 }
 
 int
-nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index,
-                               int is_del)
-{
-  ip4_main_t *ip4_main = nm->ip4_main;
-  ip4_address_t *first_int_addr;
-  nat44_ei_static_map_resolve_t *rp;
-  u32 *indices_to_delete = 0;
-  int i, j;
-  u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
-
-  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
-                                               0 /* just want the address */);
-
-  for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
-    {
-      if (auto_add_sw_if_indices[i] == sw_if_index)
-       {
-         if (is_del)
-           {
-             /* if have address remove it */
-             if (first_int_addr)
-               (void) nat44_ei_del_address (nm, first_int_addr[0], 1);
-             else
-               {
-                 for (j = 0; j < vec_len (nm->to_resolve); j++)
-                   {
-                     rp = nm->to_resolve + j;
-                     if (rp->sw_if_index == sw_if_index)
-                       vec_add1 (indices_to_delete, j);
-                   }
-                 if (vec_len (indices_to_delete))
-                   {
-                     for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
-                       vec_del1 (nm->to_resolve, j);
-                     vec_free (indices_to_delete);
-                   }
-               }
-             vec_del1 (nm->auto_add_sw_if_indices, i);
-           }
-         else
-           return VNET_API_ERROR_VALUE_EXIST;
-
-         return 0;
-       }
-    }
-
-  if (is_del)
-    return VNET_API_ERROR_NO_SUCH_ENTRY;
-
-  /* add to the auto-address list */
-  vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
-
-  /* If the address is already bound - or static - add it now */
-  if (first_int_addr)
-    (void) nat44_ei_add_address (nm, first_int_addr, ~0);
-
-  return 0;
-}
-
-static int
-nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr)
+nat44_ei_del_address (ip4_address_t addr, u8 delete_sm)
 {
   nat44_ei_main_t *nm = &nat44_ei_main;
-  nat44_ei_static_mapping_t *m;
-  pool_foreach (m, nm->static_mappings)
-    {
-      if (nat44_ei_is_addr_only_static_mapping (m) ||
-         nat44_ei_is_identity_static_mapping (m))
-       continue;
-      if (m->external_addr.as_u32 == addr.as_u32)
-       return 1;
-    }
-  return 0;
-}
-
-int
-nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
-{
   nat44_ei_address_t *a = 0;
   nat44_ei_session_t *ses;
   u32 *ses_to_be_removed = 0, *ses_index;
   nat44_ei_main_per_thread_data_t *tnm;
-  nat44_ei_interface_t *interface;
   nat44_ei_static_mapping_t *m;
-  int i;
+  int j;
+
+  fail_if_disabled ();
 
   /* Find SNAT address */
-  for (i = 0; i < vec_len (nm->addresses); i++)
+  for (j = 0; j < vec_len (nm->addresses); j++)
     {
-      if (nm->addresses[i].addr.as_u32 == addr.as_u32)
+      if (nm->addresses[j].addr.as_u32 == addr.as_u32)
        {
-         a = nm->addresses + i;
+         a = nm->addresses + j;
          break;
        }
     }
@@ -2737,11 +2967,9 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
       pool_foreach (m, nm->static_mappings)
        {
          if (m->external_addr.as_u32 == addr.as_u32)
-           (void) nat44_ei_add_del_static_mapping (
-             m->local_addr, m->external_addr, m->local_port, m->external_port,
-             m->proto, ~0 /* sw_if_index */, m->vrf_id,
-             nat44_ei_is_addr_only_static_mapping (m),
-             nat44_ei_is_identity_static_mapping (m), m->tag, 0);
+           nat44_ei_del_static_mapping (m->local_addr, m->external_addr,
+                                        m->local_port, m->external_port,
+                                        m->proto, m->vrf_id, ~0, m->flags);
        }
     }
   else
@@ -2755,7 +2983,9 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
     }
 
   if (a->fib_index != ~0)
-    fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
+    {
+      fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
+    }
 
   /* Delete sessions using address */
   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
@@ -2783,25 +3013,107 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
 #define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread);
   foreach_nat_protocol
 #undef _
-    vec_del1 (nm->addresses, i);
 
-  /* Delete external address from FIB */
-  pool_foreach (interface, nm->interfaces)
+    vec_del1 (nm->addresses, j);
+
+  nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0);
+
+  return 0;
+}
+
+int
+nat44_ei_add_interface_address (u32 sw_if_index)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  ip4_main_t *ip4_main = nm->ip4_main;
+  ip4_address_t *first_int_addr;
+  u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
+  int i;
+
+  for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
     {
-      if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
-       continue;
-      nat44_ei_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
-      break;
+      if (auto_add_sw_if_indices[i] == sw_if_index)
+       {
+         return VNET_API_ERROR_VALUE_EXIST;
+       }
+    }
+
+  /* add to the auto-address list */
+  vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
+
+  // if the address is already bound - or static - add it now
+  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
+  if (first_int_addr)
+    {
+      (void) nat44_ei_add_address (first_int_addr, ~0);
     }
 
-  pool_foreach (interface, nm->output_feature_interfaces)
+  return 0;
+}
+
+int
+nat44_ei_del_interface_address (u32 sw_if_index)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  ip4_main_t *ip4_main = nm->ip4_main;
+  ip4_address_t *first_int_addr;
+  nat44_ei_static_map_resolve_t *rp;
+  u32 *indices_to_delete = 0;
+  int i, j;
+  u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
+
+  fail_if_disabled ();
+
+  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
+
+  for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
     {
-      if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
-       continue;
-      nat44_ei_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
-      break;
+      if (auto_add_sw_if_indices[i] == sw_if_index)
+       {
+         first_int_addr =
+           ip4_interface_first_address (ip4_main, sw_if_index, 0);
+         if (first_int_addr)
+           {
+             (void) nat44_ei_del_address (first_int_addr[0], 1);
+           }
+         else
+           {
+             for (j = 0; j < vec_len (nm->to_resolve); j++)
+               {
+                 rp = nm->to_resolve + j;
+                 if (rp->sw_if_index == sw_if_index)
+                   {
+                     vec_add1 (indices_to_delete, j);
+                   }
+               }
+             if (vec_len (indices_to_delete))
+               {
+                 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
+                   {
+                     vec_del1 (nm->to_resolve, j);
+                   }
+                 vec_free (indices_to_delete);
+               }
+           }
+
+         vec_del1 (nm->auto_add_sw_if_indices, i);
+         return 0;
+       }
     }
+  return VNET_API_ERROR_NO_SUCH_ENTRY;
+}
 
+static_always_inline int
+is_sw_if_index_reg_for_auto_resolve (u32 *sw_if_indices, u32 sw_if_index)
+{
+  u32 *i;
+  vec_foreach (i, sw_if_indices)
+    {
+      if (*i == sw_if_index)
+       {
+         return 1;
+       }
+    }
   return 0;
 }
 
@@ -2814,61 +3126,59 @@ nat44_ei_ip4_add_del_interface_address_cb (ip4_main_t *im, uword opaque,
 {
   nat44_ei_main_t *nm = &nat44_ei_main;
   nat44_ei_static_map_resolve_t *rp;
-  ip4_address_t l_addr;
-  int i, j;
-  int rv;
   nat44_ei_address_t *addresses = nm->addresses;
+  int rv, i;
 
   if (!nm->enabled)
-    return;
-
-  for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
     {
-      if (sw_if_index == nm->auto_add_sw_if_indices[i])
-       goto match;
+      return;
     }
 
-  return;
+  if (!is_sw_if_index_reg_for_auto_resolve (nm->auto_add_sw_if_indices,
+                                           sw_if_index))
+    {
+      return;
+    }
 
-match:
   if (!is_delete)
     {
       /* Don't trip over lease renewal, static config */
-      for (j = 0; j < vec_len (addresses); j++)
-       if (addresses[j].addr.as_u32 == address->as_u32)
-         return;
+      for (i = 0; i < vec_len (addresses); i++)
+       {
+         if (addresses[i].addr.as_u32 == address->as_u32)
+           {
+             return;
+           }
+       }
+
+      (void) nat44_ei_add_address (address, ~0);
 
-      (void) nat44_ei_add_address (nm, address, ~0);
       /* Scan static map resolution vector */
-      for (j = 0; j < vec_len (nm->to_resolve); j++)
+      for (i = 0; i < vec_len (nm->to_resolve); i++)
        {
-         rp = nm->to_resolve + j;
-         if (rp->addr_only)
-           continue;
+         rp = nm->to_resolve + i;
+         if (is_sm_addr_only (rp->flags))
+           {
+             continue;
+           }
          /* On this interface? */
          if (rp->sw_if_index == sw_if_index)
            {
-             /* Indetity mapping? */
-             if (rp->l_addr.as_u32 == 0)
-               l_addr.as_u32 = address[0].as_u32;
-             else
-               l_addr.as_u32 = rp->l_addr.as_u32;
-             /* Add the static mapping */
-             rv = nat44_ei_add_del_static_mapping (
-               l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
-               ~0 /* sw_if_index */, rp->vrf_id, rp->addr_only,
-               rp->identity_nat, rp->tag, 1);
+             rv = nat44_ei_add_static_mapping (
+               rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
+               rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag);
              if (rv)
-               nat_elog_notice_X1 (
-                 nm, "nat44_ei_add_del_static_mapping returned %d", "i4", rv);
+               {
+                 nat_elog_notice_X1 (nm, "add_static_mapping returned %d",
+                                     "i4", rv);
+               }
            }
        }
-      return;
     }
   else
     {
-      (void) nat44_ei_del_address (nm, address[0], 1);
-      return;
+      // remove all static mapping records
+      (void) nat44_ei_del_address (address[0], 1);
     }
 }
 
@@ -2891,57 +3201,63 @@ nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque,
   nat44_ei_static_map_resolve_t *rp;
   nat44_ei_static_mapping_t *m;
   clib_bihash_kv_8_8_t kv, value;
-  int i, rv;
-  ip4_address_t l_addr;
+  int i, rv = 0, match = 0;
 
   if (!nm->enabled)
-    return;
+    {
+      return;
+    }
 
   for (i = 0; i < vec_len (nm->to_resolve); i++)
     {
       rp = nm->to_resolve + i;
-      if (rp->addr_only == 0)
-       continue;
-      if (rp->sw_if_index == sw_if_index)
-       goto match;
+
+      if (is_sm_addr_only (rp->flags) && rp->sw_if_index == sw_if_index)
+       {
+         match = 1;
+         break;
+       }
     }
 
-  return;
+  if (!match)
+    {
+      return;
+    }
 
-match:
-  init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port,
-             nm->outside_fib_index, rp->addr_only ? 0 : rp->proto);
+  init_nat_k (&kv, *address, is_sm_addr_only (rp->flags) ? 0 : rp->e_port,
+             nm->outside_fib_index,
+             is_sm_addr_only (rp->flags) ? 0 : rp->proto);
   if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
     m = 0;
   else
     m = pool_elt_at_index (nm->static_mappings, value.value);
 
-  if (!is_delete)
+  if (is_delete)
     {
-      /* Don't trip over lease renewal, static config */
-      if (m)
+      if (!m)
        return;
+      rv = nat44_ei_del_static_mapping (rp->l_addr, address[0], rp->l_port,
+                                       rp->e_port, rp->proto, rp->vrf_id, ~0,
+                                       rp->flags);
+      if (rv)
+       {
+         nat_elog_notice_X1 (nm, "nat44_ei_del_static_mapping returned %d",
+                             "i4", rv);
+       }
     }
   else
     {
-      if (!m)
+      if (m)
        return;
+      rv = nat44_ei_add_static_mapping (rp->l_addr, address[0], rp->l_port,
+                                       rp->e_port, rp->proto, rp->vrf_id, ~0,
+                                       rp->flags, rp->pool_addr, rp->tag);
+      if (rv)
+       {
+         nat_elog_notice_X1 (nm, "nat44_ei_add_static_mapping returned %d",
+                             "i4", rv);
+       }
     }
-
-  /* Indetity mapping? */
-  if (rp->l_addr.as_u32 == 0)
-    l_addr.as_u32 = address[0].as_u32;
-  else
-    l_addr.as_u32 = rp->l_addr.as_u32;
-  /* Add the static mapping */
-
-  rv = nat44_ei_add_del_static_mapping (
-    l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
-    ~0 /* sw_if_index */, rp->vrf_id, rp->addr_only, rp->identity_nat, rp->tag,
-    !is_delete);
-  if (rv)
-    nat_elog_notice_X1 (nm, "nat44_ei_add_del_static_mapping returned %d",
-                       "i4", rv);
 }
 
 static_always_inline uword
index 2e95b14..0134c78 100644 (file)
@@ -63,8 +63,8 @@ typedef enum
 #define NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO  (1 << 1)
 
 /* Static mapping flags */
-#define NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY   (1 << 0)
-#define NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT (1 << 1)
+#define NAT44_EI_SM_FLAG_ADDR_ONLY    (1 << 0)
+#define NAT44_EI_SM_FLAG_IDENTITY_NAT (1 << 1)
 
 typedef struct
 {
@@ -139,13 +139,9 @@ typedef struct
   u32 vrf_id;
   u32 flags;
   nat_protocol_t proto;
-  u8 addr_only;
-  u8 identity_nat;
-  u8 exact;
   u8 *tag;
 } nat44_ei_static_map_resolve_t;
 
-// TODO: cleanup/redo (there is no lb in EI nat)
 typedef struct
 {
   /* backend IP address */
@@ -340,6 +336,8 @@ typedef struct nat44_ei_main_s
   /* Interface pool */
   nat44_ei_interface_t *interfaces;
   nat44_ei_interface_t *output_feature_interfaces;
+  // broken api backward compatibility
+  nat44_ei_interface_t *output_feature_dummy_interfaces;
 
   /* Is translation memory size calculated or user defined */
   u8 translation_memory_size_set;
@@ -484,9 +482,16 @@ typedef struct nat44_ei_main_s
 extern nat44_ei_main_t nat44_ei_main;
 
 int nat44_ei_plugin_enable (nat44_ei_config_t c);
-
 int nat44_ei_plugin_disable ();
 
+int nat44_ei_add_del_interface (u32 sw_if_index, u8 is_inside, int is_del);
+int nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del);
+
+int nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id);
+int nat44_ei_del_address (ip4_address_t addr, u8 delete_sm);
+int nat44_ei_add_interface_address (u32 sw_if_index);
+int nat44_ei_del_interface_address (u32 sw_if_index);
+
 /**
  * @brief Delete specific NAT44 EI user and his sessions
  *
@@ -533,29 +538,14 @@ 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_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
+                                u16 l_port, u16 e_port, nat_protocol_t proto,
+                                u32 vrf_id, u32 sw_if_index, u32 flags,
+                                ip4_address_t pool_addr, u8 *tag);
 
- */
-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);
+int nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
+                                u16 l_port, u16 e_port, nat_protocol_t proto,
+                                u32 vrf_id, u32 sw_if_index, u32 flags);
 
 /**
  * @brief Delete NAT44-EI session
@@ -620,9 +610,6 @@ int nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
                                           ip4_address_t addr, u16 port,
                                           nat_protocol_t protocol);
 
-int nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr,
-                         u8 delete_sm);
-
 void nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
                                 u32 thread_index, u8 is_ha);
 
@@ -630,20 +617,9 @@ int nat44_ei_set_workers (uword *bitmap);
 
 void nat44_ei_add_del_address_dpo (ip4_address_t addr, u8 is_add);
 
-int nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr,
-                         u32 vrf_id);
-
 void nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
                              u32 thread_index);
 
-int nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del);
-
-int nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside,
-                                              int is_del);
-
-int nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index,
-                                   int is_del);
-
 /* Call back functions for clib_bihash_add_or_overwrite_stale */
 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);
@@ -665,20 +641,41 @@ u32 nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0,
 
 int nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts);
 
-#define nat44_ei_is_session_static(sp)                                        \
-  (sp->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING)
-#define nat44_ei_is_unk_proto_session(sp)                                     \
-  (sp->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO)
+always_inline bool
+nat44_ei_is_session_static (nat44_ei_session_t *s)
+{
+  return (s->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING);
+}
+
+always_inline bool
+nat44_ei_is_unk_proto_session (nat44_ei_session_t *s)
+{
+  return (s->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO);
+}
 
-#define nat44_ei_interface_is_inside(ip)                                      \
-  (ip->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE)
-#define nat44_ei_interface_is_outside(ip)                                     \
-  (ip->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE)
+always_inline bool
+nat44_ei_interface_is_inside (nat44_ei_interface_t *i)
+{
+  return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE);
+}
 
-#define nat44_ei_is_addr_only_static_mapping(mp)                              \
-  (mp->flags & NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY)
-#define nat44_ei_is_identity_static_mapping(mp)                               \
-  (mp->flags & NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT)
+always_inline bool
+nat44_ei_interface_is_outside (nat44_ei_interface_t *i)
+{
+  return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE);
+}
+
+always_inline bool
+is_sm_addr_only (u32 f)
+{
+  return (f & NAT44_EI_SM_FLAG_ADDR_ONLY);
+}
+
+always_inline bool
+is_sm_identity_nat (u32 f)
+{
+  return (f & NAT44_EI_SM_FLAG_IDENTITY_NAT);
+}
 
 /* logging */
 #define nat44_ei_log_err(...)                                                 \
index 427140f..c6d17c9 100644 (file)
@@ -469,9 +469,9 @@ vl_api_nat44_ei_add_del_address_range_t_handler (
   for (i = 0; i < count; i++)
     {
       if (is_add)
-       rv = nat44_ei_add_address (nm, &this_addr, vrf_id);
+       rv = nat44_ei_add_address (&this_addr, vrf_id);
       else
-       rv = nat44_ei_del_address (nm, this_addr, 0);
+       rv = nat44_ei_del_address (this_addr, 0);
 
       if (rv)
        goto send_reply;
@@ -540,7 +540,7 @@ vl_api_nat44_ei_interface_add_del_feature_t_handler (
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  rv = nat44_ei_interface_add_del (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE,
+  rv = nat44_ei_add_del_interface (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE,
                                   is_del);
 
   BAD_SW_IF_INDEX_LABEL;
@@ -588,19 +588,68 @@ vl_api_nat44_ei_interface_dump_t_handler (vl_api_nat44_ei_interface_dump_t *mp)
     }
 }
 
+static_always_inline int
+add_del_dummy_output_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i;
+  int rv = 1;
+
+  pool_foreach (i, nm->output_feature_dummy_interfaces)
+    {
+      if (i->sw_if_index == sw_if_index)
+       {
+         if (!is_add)
+           {
+             pool_put (nm->output_feature_dummy_interfaces, i);
+             rv = 0;
+           }
+         goto done;
+       }
+    }
+
+  if (is_add)
+    {
+      pool_get (nm->output_feature_dummy_interfaces, i);
+      i->sw_if_index = sw_if_index;
+
+      if (is_inside)
+       {
+         i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+       }
+      else
+       {
+         i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+       }
+
+      rv = 0;
+    }
+
+done:
+  return rv;
+}
+
 static void
 vl_api_nat44_ei_interface_add_del_output_feature_t_handler (
   vl_api_nat44_ei_interface_add_del_output_feature_t *mp)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
   vl_api_nat44_ei_interface_add_del_output_feature_reply_t *rmp;
-  u32 sw_if_index = ntohl (mp->sw_if_index);
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 sw_if_index;
   int rv = 0;
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  rv = nat44_ei_interface_add_del_output_feature (
-    sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, !mp->is_add);
+  sw_if_index = ntohl (mp->sw_if_index);
+
+  // register all interfaces in the dummy structure
+  rv = add_del_dummy_output_interface (
+    sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, mp->is_add);
+
+  if (!(mp->flags & NAT44_EI_IF_INSIDE))
+    {
+      rv = nat44_ei_add_del_output_interface (sw_if_index, !mp->is_add);
+    }
 
   BAD_SW_IF_INDEX_LABEL;
   REPLY_MACRO (VL_API_NAT44_EI_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY);
@@ -622,7 +671,9 @@ send_nat44_ei_interface_output_feature_details (nat44_ei_interface_t *i,
   rmp->context = context;
 
   if (nat44_ei_interface_is_inside (i))
-    rmp->flags |= NAT44_EI_IF_INSIDE;
+    {
+      rmp->flags |= NAT44_EI_IF_INSIDE;
+    }
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
@@ -639,49 +690,131 @@ vl_api_nat44_ei_interface_output_feature_dump_t_handler (
   if (!reg)
     return;
 
-  pool_foreach (i, nm->output_feature_interfaces)
+  pool_foreach (i, nm->output_feature_dummy_interfaces)
     {
       send_nat44_ei_interface_output_feature_details (i, reg, mp->context);
     }
 }
 
+static void
+vl_api_nat44_ei_add_del_output_interface_t_handler (
+  vl_api_nat44_ei_add_del_output_interface_t *mp)
+{
+  vl_api_nat44_ei_add_del_output_interface_reply_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 sw_if_index;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  sw_if_index = ntohl (mp->sw_if_index);
+
+  rv = nat44_ei_add_del_output_interface (sw_if_index, !mp->is_add);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_OUTPUT_INTERFACE_REPLY);
+}
+
+#define vl_endianfun
+#include <nat/nat44-ei/nat44_ei.api.h>
+#undef vl_endianfun
+static void
+send_nat44_ei_output_interface_details (u32 index, vl_api_registration_t *rp,
+                                       u32 context)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_output_interface_details_t *rmp;
+  nat44_ei_interface_t *i =
+    pool_elt_at_index (nm->output_feature_interfaces, index);
+
+  /* Make sure every field is initiated (or don't skip the clib_memset()) */
+  REPLY_MACRO_DETAILS4 (
+    VL_API_NAT44_EI_OUTPUT_INTERFACE_DETAILS, rp, context, ({
+      rmp->sw_if_index = i->sw_if_index;
+
+      /* Endian hack until apigen registers _details
+       * endian functions */
+      vl_api_nat44_ei_output_interface_details_t_endian (rmp);
+      rmp->_vl_msg_id = htons (rmp->_vl_msg_id);
+      rmp->context = htonl (rmp->context);
+    }));
+}
+
+static void
+vl_api_nat44_ei_output_interface_get_t_handler (
+  vl_api_nat44_ei_output_interface_get_t *mp)
+{
+  vl_api_nat44_ei_output_interface_get_reply_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  i32 rv = 0;
+
+  if (pool_elts (nm->output_feature_interfaces) == 0)
+    {
+      REPLY_MACRO (VL_API_NAT44_EI_OUTPUT_INTERFACE_GET_REPLY);
+      return;
+    }
+
+  REPLY_AND_DETAILS_MACRO (
+    VL_API_NAT44_EI_OUTPUT_INTERFACE_GET_REPLY, nm->output_feature_interfaces,
+    ({ send_nat44_ei_output_interface_details (cursor, rp, mp->context); }));
+}
+
 static void
 vl_api_nat44_ei_add_del_static_mapping_t_handler (
   vl_api_nat44_ei_add_del_static_mapping_t *mp)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
   vl_api_nat44_ei_add_del_static_mapping_reply_t *rmp;
-  ip4_address_t local_addr, external_addr;
-  u16 local_port = 0, external_port = 0;
-  u32 vrf_id, external_sw_if_index;
+
+  nat44_ei_main_t *nm = &nat44_ei_main;
   int rv = 0;
-  nat_protocol_t proto;
+
+  ip4_address_t l_addr, e_addr, pool_addr = { 0 };
+  u32 sw_if_index, flags = 0, vrf_id;
+  u16 l_port = 0, e_port = 0;
+  nat_protocol_t proto = 0;
   u8 *tag = 0;
 
-  memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
-  memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
+  memcpy (&l_addr.as_u8, mp->local_ip_address, 4);
 
-  if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING))
+  if (mp->flags & NAT44_EI_ADDR_ONLY_MAPPING)
     {
-      local_port = mp->local_port;
-      external_port = mp->external_port;
+      flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+    }
+  else
+    {
+      l_port = mp->local_port;
+      e_port = mp->external_port;
+      proto = ip_proto_to_nat_proto (mp->protocol);
     }
 
-  vrf_id = clib_net_to_host_u32 (mp->vrf_id);
-  external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
-  proto = ip_proto_to_nat_proto (mp->protocol);
-
-  mp->tag[sizeof (mp->tag) - 1] = 0;
-  tag = format (0, "%s", mp->tag);
-  vec_terminate_c_string (tag);
-
-  rv = nat44_ei_add_del_static_mapping (
-    local_addr, external_addr, local_port, external_port, proto,
-    external_sw_if_index, vrf_id, mp->flags & NAT44_EI_ADDR_ONLY_MAPPING, 0,
-    tag, mp->is_add);
+  sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
+  if (sw_if_index != ~0)
+    {
+      e_addr.as_u32 = 0;
+    }
+  else
+    {
+      memcpy (&e_addr.as_u8, mp->external_ip_address, 4);
+    }
 
-  vec_free (tag);
+  vrf_id = clib_net_to_host_u32 (mp->vrf_id);
 
+  if (mp->is_add)
+    {
+      mp->tag[sizeof (mp->tag) - 1] = 0;
+      tag = format (0, "%s", mp->tag);
+      vec_terminate_c_string (tag);
+
+      rv = nat44_ei_add_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+                                       vrf_id, sw_if_index, flags, pool_addr,
+                                       tag);
+      vec_free (tag);
+    }
+  else
+    {
+      rv = nat44_ei_del_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+                                       vrf_id, sw_if_index, flags);
+    }
   REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_STATIC_MAPPING_REPLY);
 }
 
@@ -704,7 +837,7 @@ send_nat44_ei_static_mapping_details (nat44_ei_static_mapping_t *m,
   rmp->vrf_id = htonl (m->vrf_id);
   rmp->context = context;
 
-  if (nat44_ei_is_addr_only_static_mapping (m))
+  if (is_sm_addr_only (m->flags))
     {
       rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
     }
@@ -738,7 +871,7 @@ send_nat44_ei_static_map_resolve_details (nat44_ei_static_map_resolve_t *m,
   rmp->vrf_id = htonl (m->vrf_id);
   rmp->context = context;
 
-  if (m->addr_only)
+  if (is_sm_addr_only (m->flags))
     {
       rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
     }
@@ -770,14 +903,14 @@ vl_api_nat44_ei_static_mapping_dump_t_handler (
 
   pool_foreach (m, nm->static_mappings)
     {
-      if (!nat44_ei_is_identity_static_mapping (m))
+      if (!is_sm_identity_nat (m->flags))
        send_nat44_ei_static_mapping_details (m, reg, mp->context);
     }
 
   for (j = 0; j < vec_len (nm->to_resolve); j++)
     {
       rp = nm->to_resolve + j;
-      if (!rp->identity_nat)
+      if (!is_sm_identity_nat (rp->flags))
        send_nat44_ei_static_map_resolve_details (rp, reg, mp->context);
     }
 }
@@ -786,35 +919,56 @@ static void
 vl_api_nat44_ei_add_del_identity_mapping_t_handler (
   vl_api_nat44_ei_add_del_identity_mapping_t *mp)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
   vl_api_nat44_ei_add_del_identity_mapping_reply_t *rmp;
-  ip4_address_t addr;
-  u16 port = 0;
-  u32 vrf_id, sw_if_index;
+
+  nat44_ei_main_t *nm = &nat44_ei_main;
   int rv = 0;
-  nat_protocol_t proto = NAT_PROTOCOL_OTHER;
+
+  ip4_address_t addr, pool_addr = { 0 };
+  u32 sw_if_index, flags, vrf_id;
+  nat_protocol_t proto = 0;
+  u16 port = 0;
   u8 *tag = 0;
 
-  if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING))
+  flags = NAT44_EI_SM_FLAG_IDENTITY_NAT;
+
+  if (mp->flags & NAT44_EI_ADDR_ONLY_MAPPING)
+    {
+      flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+    }
+  else
     {
       port = mp->port;
       proto = ip_proto_to_nat_proto (mp->protocol);
     }
-  vrf_id = clib_net_to_host_u32 (mp->vrf_id);
+
   sw_if_index = clib_net_to_host_u32 (mp->sw_if_index);
   if (sw_if_index != ~0)
-    addr.as_u32 = 0;
+    {
+      addr.as_u32 = 0;
+    }
   else
-    memcpy (&addr.as_u8, mp->ip_address, 4);
-  mp->tag[sizeof (mp->tag) - 1] = 0;
-  tag = format (0, "%s", mp->tag);
-  vec_terminate_c_string (tag);
+    {
+      memcpy (&addr.as_u8, mp->ip_address, 4);
+    }
 
-  rv = nat44_ei_add_del_static_mapping (
-    addr, addr, port, port, proto, sw_if_index, vrf_id,
-    mp->flags & NAT44_EI_ADDR_ONLY_MAPPING, 1, tag, mp->is_add);
+  vrf_id = clib_net_to_host_u32 (mp->vrf_id);
 
-  vec_free (tag);
+  if (mp->is_add)
+    {
+      mp->tag[sizeof (mp->tag) - 1] = 0;
+      tag = format (0, "%s", mp->tag);
+      vec_terminate_c_string (tag);
+
+      rv = nat44_ei_add_static_mapping (addr, addr, port, port, proto, vrf_id,
+                                       sw_if_index, flags, pool_addr, tag);
+      vec_free (tag);
+    }
+  else
+    {
+      rv = nat44_ei_del_static_mapping (addr, addr, port, port, proto, vrf_id,
+                                       sw_if_index, flags);
+    }
 
   REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_IDENTITY_MAPPING_REPLY);
 }
@@ -833,7 +987,7 @@ send_nat44_ei_identity_mapping_details (nat44_ei_static_mapping_t *m,
   rmp->_vl_msg_id =
     ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base);
 
-  if (nat44_ei_is_addr_only_static_mapping (m))
+  if (is_sm_addr_only (m->flags))
     rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
 
   clib_memcpy (rmp->ip_address, &(m->local_addr), 4);
@@ -860,7 +1014,7 @@ send_nat44_ei_identity_map_resolve_details (nat44_ei_static_map_resolve_t *m,
   rmp->_vl_msg_id =
     ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base);
 
-  if (m->addr_only)
+  if (is_sm_addr_only (m->flags))
     rmp->flags = (vl_api_nat44_ei_config_flags_t) NAT44_EI_ADDR_ONLY_MAPPING;
 
   rmp->port = m->l_port;
@@ -890,7 +1044,7 @@ vl_api_nat44_ei_identity_mapping_dump_t_handler (
 
   pool_foreach (m, nm->static_mappings)
     {
-      if (nat44_ei_is_identity_static_mapping (m))
+      if (is_sm_identity_nat (m->flags))
        {
          pool_foreach_index (j, m->locals)
            {
@@ -902,7 +1056,7 @@ vl_api_nat44_ei_identity_mapping_dump_t_handler (
   for (j = 0; j < vec_len (nm->to_resolve); j++)
     {
       rp = nm->to_resolve + j;
-      if (rp->identity_nat)
+      if (is_sm_identity_nat (rp->flags))
        send_nat44_ei_identity_map_resolve_details (rp, reg, mp->context);
     }
 }
@@ -915,13 +1069,17 @@ vl_api_nat44_ei_add_del_interface_addr_t_handler (
   vl_api_nat44_ei_add_del_interface_addr_reply_t *rmp;
   u32 sw_if_index = ntohl (mp->sw_if_index);
   int rv = 0;
-  u8 is_del;
-
-  is_del = !mp->is_add;
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del);
+  if (mp->is_add)
+    {
+      rv = nat44_ei_add_interface_address (sw_if_index);
+    }
+  else
+    {
+      rv = nat44_ei_del_interface_address (sw_if_index);
+    }
 
   BAD_SW_IF_INDEX_LABEL;
   REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_INTERFACE_ADDR_REPLY);
index 0780e5d..f3e7198 100644 (file)
@@ -112,9 +112,9 @@ format_nat44_ei_static_mapping (u8 *s, va_list *args)
   nat44_ei_static_mapping_t *m = va_arg (*args, nat44_ei_static_mapping_t *);
   nat44_ei_lb_addr_port_t *local;
 
-  if (nat44_ei_is_identity_static_mapping (m))
+  if (is_sm_identity_nat (m->flags))
     {
-      if (nat44_ei_is_addr_only_static_mapping (m))
+      if (is_sm_addr_only (m->flags))
        s = format (s, "identity mapping %U", format_ip4_address,
                    &m->local_addr);
       else
@@ -130,7 +130,7 @@ format_nat44_ei_static_mapping (u8 *s, va_list *args)
       return s;
     }
 
-  if (nat44_ei_is_addr_only_static_mapping (m))
+  if (is_sm_addr_only (m->flags))
     {
       s = format (s, "local %U external %U vrf %d", format_ip4_address,
                  &m->local_addr, format_ip4_address, &m->external_addr,
@@ -154,7 +154,7 @@ format_nat44_ei_static_map_to_resolve (u8 *s, va_list *args)
     va_arg (*args, nat44_ei_static_map_resolve_t *);
   vnet_main_t *vnm = vnet_get_main ();
 
-  if (m->addr_only)
+  if (is_sm_addr_only (m->flags))
     s =
       format (s, "local %U external %U vrf %d", format_ip4_address, &m->l_addr,
              format_vnet_sw_if_index_name, vnm, m->sw_if_index, m->vrf_id);
@@ -790,9 +790,9 @@ add_address_command_fn (vlib_main_t *vm, unformat_input_t *input,
   for (i = 0; i < count; i++)
     {
       if (is_add)
-       rv = nat44_ei_add_address (nm, &this_addr, vrf_id);
+       rv = nat44_ei_add_address (&this_addr, vrf_id);
       else
-       rv = nat44_ei_del_address (nm, this_addr, 0);
+       rv = nat44_ei_del_address (this_addr, 0);
 
       switch (rv)
        {
@@ -894,8 +894,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
          sw_if_index = inside_sw_if_indices[i];
          if (is_output_feature)
            {
-             if (nat44_ei_interface_add_del_output_feature (sw_if_index, 1,
-                                                            is_del))
+             if (nat44_ei_add_del_output_interface (sw_if_index, is_del))
                {
                  error = clib_error_return (
                    0, "%s %U failed", is_del ? "del" : "add",
@@ -905,7 +904,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
            }
          else
            {
-             if (nat44_ei_interface_add_del (sw_if_index, 1, is_del))
+             if (nat44_ei_add_del_interface (sw_if_index, 1, is_del))
                {
                  error = clib_error_return (
                    0, "%s %U failed", is_del ? "del" : "add",
@@ -923,8 +922,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
          sw_if_index = outside_sw_if_indices[i];
          if (is_output_feature)
            {
-             if (nat44_ei_interface_add_del_output_feature (sw_if_index, 0,
-                                                            is_del))
+             if (nat44_ei_add_del_output_interface (sw_if_index, is_del))
                {
                  error = clib_error_return (
                    0, "%s %U failed", is_del ? "del" : "add",
@@ -934,7 +932,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
            }
          else
            {
-             if (nat44_ei_interface_add_del (sw_if_index, 0, is_del))
+             if (nat44_ei_add_del_interface (sw_if_index, 0, is_del))
                {
                  error = clib_error_return (
                    0, "%s %U failed", is_del ? "del" : "add",
@@ -990,14 +988,16 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
                               vlib_cli_command_t *cmd)
 {
   unformat_input_t _line_input, *line_input = &_line_input;
-  clib_error_t *error = 0;
-  ip4_address_t l_addr, e_addr;
-  u32 l_port = 0, e_port = 0, vrf_id = ~0;
-  int is_add = 1, addr_only = 1, rv;
-  u32 sw_if_index = ~0;
   vnet_main_t *vnm = vnet_get_main ();
+  clib_error_t *error = 0;
+  int rv;
+
   nat_protocol_t proto = NAT_PROTOCOL_OTHER;
-  u8 proto_set = 0;
+  ip4_address_t l_addr, e_addr, pool_addr = { 0 };
+  u32 l_port = 0, e_port = 0, vrf_id = ~0;
+  u8 l_port_set = 0, e_port_set = 0;
+  u32 sw_if_index = ~0, flags = 0;
+  int is_add = 1;
 
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT);
@@ -1006,29 +1006,37 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
     {
       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
                    &l_port))
-       addr_only = 0;
+       {
+         l_port_set = 1;
+       }
       else if (unformat (line_input, "local %U", unformat_ip4_address,
                         &l_addr))
        ;
       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
                         &e_addr, &e_port))
-       addr_only = 0;
+       {
+         e_port_set = 1;
+       }
       else if (unformat (line_input, "external %U", unformat_ip4_address,
                         &e_addr))
        ;
       else if (unformat (line_input, "external %U %u",
                         unformat_vnet_sw_interface, vnm, &sw_if_index,
                         &e_port))
-       addr_only = 0;
+       {
+         e_port_set = 1;
+       }
       else if (unformat (line_input, "external %U", unformat_vnet_sw_interface,
                         vnm, &sw_if_index))
        ;
       else if (unformat (line_input, "vrf %u", &vrf_id))
        ;
       else if (unformat (line_input, "%U", unformat_nat_protocol, &proto))
-       proto_set = 1;
+       ;
       else if (unformat (line_input, "del"))
-       is_add = 0;
+       {
+         is_add = 0;
+       }
       else
        {
          error = clib_error_return (0, "unknown input: '%U'",
@@ -1037,25 +1045,33 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
        }
     }
 
-  if (addr_only)
+  if (l_port_set != e_port_set)
     {
-      if (proto_set)
-       {
-         error = clib_error_return (
-           0, "address only mapping doesn't support protocol");
-         goto done;
-       }
+      error = clib_error_return (0, "Either both ports are set or none.");
+      goto done;
     }
-  else if (!proto_set)
+
+  if (!l_port_set)
     {
-      error = clib_error_return (0, "protocol is required");
-      goto done;
+      flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+    }
+  else
+    {
+      l_port = clib_host_to_net_u16 (l_port);
+      e_port = clib_host_to_net_u16 (e_port);
     }
 
-  rv = nat44_ei_add_del_static_mapping (
-    l_addr, e_addr, clib_host_to_net_u16 (l_port),
-    clib_host_to_net_u16 (e_port), proto, sw_if_index, vrf_id, addr_only, 0, 0,
-    is_add);
+  if (is_add)
+    {
+      rv =
+       nat44_ei_add_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+                                    vrf_id, sw_if_index, flags, pool_addr, 0);
+    }
+  else
+    {
+      rv = nat44_ei_del_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+                                       vrf_id, sw_if_index, flags);
+    }
 
   switch (rv)
     {
@@ -1091,17 +1107,15 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
                                 vlib_cli_command_t *cmd)
 {
   unformat_input_t _line_input, *line_input = &_line_input;
-  clib_error_t *error = 0;
-  u32 port = 0, vrf_id = ~0;
-  ip4_address_t addr;
-  int is_add = 1;
-  int addr_only = 1;
-  u32 sw_if_index = ~0;
   vnet_main_t *vnm = vnet_get_main ();
-  int rv;
+  clib_error_t *error = 0;
+
+  int rv, is_add = 1, port_set = 0;
+  u32 sw_if_index = ~0, port, flags, vrf_id = ~0;
   nat_protocol_t proto;
+  ip4_address_t addr;
 
-  addr.as_u32 = 0;
+  flags = NAT44_EI_SM_FLAG_IDENTITY_NAT;
 
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT);
@@ -1117,9 +1131,13 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
        ;
       else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto,
                         &port))
-       addr_only = 0;
+       {
+         port_set = 1;
+       }
       else if (unformat (line_input, "del"))
-       is_add = 0;
+       {
+         is_add = 0;
+       }
       else
        {
          error = clib_error_return (0, "unknown input: '%U'",
@@ -1128,9 +1146,26 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
        }
     }
 
-  rv = nat44_ei_add_del_static_mapping (
-    addr, addr, clib_host_to_net_u16 (port), clib_host_to_net_u16 (port),
-    proto, sw_if_index, vrf_id, addr_only, 1, 0, is_add);
+  if (!port_set)
+    {
+      flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+    }
+  else
+    {
+      port = clib_host_to_net_u16 (port);
+    }
+
+  if (is_add)
+    {
+
+      rv = nat44_ei_add_static_mapping (addr, addr, port, port, proto, vrf_id,
+                                       sw_if_index, flags, addr, 0);
+    }
+  else
+    {
+      rv = nat44_ei_del_static_mapping (addr, addr, port, port, proto, vrf_id,
+                                       sw_if_index, flags);
+    }
 
   switch (rv)
     {
@@ -1184,12 +1219,11 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm,
                                           unformat_input_t *input,
                                           vlib_cli_command_t *cmd)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
   unformat_input_t _line_input, *line_input = &_line_input;
-  u32 sw_if_index;
-  int rv;
-  int is_del = 0;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   clib_error_t *error = 0;
+  int rv, is_del = 0;
+  u32 sw_if_index;
 
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT);
@@ -1200,7 +1234,9 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm,
                    nm->vnet_main, &sw_if_index))
        ;
       else if (unformat (line_input, "del"))
-       is_del = 1;
+       {
+         is_del = 1;
+       }
       else
        {
          error = clib_error_return (0, "unknown input '%U'",
@@ -1209,17 +1245,21 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm,
        }
     }
 
-  rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del);
-
-  switch (rv)
+  if (!is_del)
     {
-    case 0:
-      break;
-
-    default:
-      error = clib_error_return (
-       0, "nat44_ei_add_interface_address returned %d", rv);
-      goto done;
+      rv = nat44_ei_add_interface_address (sw_if_index);
+      if (rv)
+       {
+         error = clib_error_return (0, "add address returned %d", rv);
+       }
+    }
+  else
+    {
+      rv = nat44_ei_del_interface_address (sw_if_index);
+      if (rv)
+       {
+         error = clib_error_return (0, "del address returned %d", rv);
+       }
     }
 
 done:
@@ -1493,7 +1533,6 @@ nat_show_timeouts_command_fn (vlib_main_t *vm, unformat_input_t *input,
 {
   nat44_ei_main_t *nm = &nat44_ei_main;
 
-  // TODO: make format timeout function
   vlib_cli_output (vm, "udp timeout: %dsec", nm->timeouts.udp);
   vlib_cli_output (vm, "tcp-established timeout: %dsec",
                   nm->timeouts.tcp.established);
index c7a1317..5c16d87 100644 (file)
@@ -83,8 +83,6 @@ nat44_ei_worker_handoff_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
 
   vlib_get_buffers (vm, from, b, n_left_from);
 
-  // TODO: move to nm
-  // TODO: remove callbacks and use inlines that should be moved here
   if (is_in2out)
     {
       fq_index = is_output ? nm->fq_in2out_output_index : nm->fq_in2out_index;
index 5fdcf3f..6dcda8c 100644 (file)
@@ -2831,13 +2831,6 @@ class TestNAT44EI(MethodHolder):
     def test_output_feature(self):
         """ NAT44EI output feature (in2out postrouting) """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT44_EI_IF_INSIDE
-        self.vapi.nat44_ei_interface_add_del_output_feature(
-            is_add=1, flags=flags,
-            sw_if_index=self.pg0.sw_if_index)
-        self.vapi.nat44_ei_interface_add_del_output_feature(
-            is_add=1, flags=flags,
-            sw_if_index=self.pg1.sw_if_index)
         self.vapi.nat44_ei_interface_add_del_output_feature(
             is_add=1,
             sw_if_index=self.pg3.sw_if_index)
@@ -2884,13 +2877,6 @@ class TestNAT44EI(MethodHolder):
 
         self.nat44_add_address(nat_ip_vrf10, vrf_id=10)
         self.nat44_add_address(nat_ip_vrf20, vrf_id=20)
-        flags = self.config_flags.NAT44_EI_IF_INSIDE
-        self.vapi.nat44_ei_interface_add_del_output_feature(
-            is_add=1, flags=flags,
-            sw_if_index=self.pg4.sw_if_index)
-        self.vapi.nat44_ei_interface_add_del_output_feature(
-            is_add=1, flags=flags,
-            sw_if_index=self.pg6.sw_if_index)
         self.vapi.nat44_ei_interface_add_del_output_feature(
             is_add=1,
             sw_if_index=self.pg3.sw_if_index)
@@ -2937,9 +2923,8 @@ class TestNAT44EI(MethodHolder):
         server_out_port = 8765
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT44_EI_IF_INSIDE
         self.vapi.nat44_ei_interface_add_del_output_feature(
-            is_add=1, flags=flags,
+            is_add=1,
             sw_if_index=self.pg0.sw_if_index)
         self.vapi.nat44_ei_interface_add_del_output_feature(
             is_add=1,