nat: Final NAT44 EI/ED split patch 07/31107/10
authorFilip Varga <fivarga@cisco.com>
Wed, 17 Feb 2021 13:34:54 +0000 (14:34 +0100)
committerOle Tr�an <otroan@employees.org>
Wed, 24 Feb 2021 19:25:25 +0000 (19:25 +0000)
This patch achieves complete separation of
endpoint-dependent and endpoint-independent IPv4 NAT
features. Some common stuff is also moved to NAT
library.

Type: refactor

Change-Id: I52468b7e2b5ac28958a2baf8e2ea01787322e801
Signed-off-by: Filip Varga <fivarga@cisco.com>
44 files changed:
src/plugins/nat/CMakeLists.txt
src/plugins/nat/FEATURE.yaml
src/plugins/nat/det44/det44.api
src/plugins/nat/dslite/dslite_cli.c
src/plugins/nat/lib/lib.c [new file with mode: 0644]
src/plugins/nat/lib/lib.h
src/plugins/nat/lib/log.h [new file with mode: 0644]
src/plugins/nat/lib/nat_inlines.h
src/plugins/nat/lib/nat_types.api [moved from src/plugins/nat/nat_types.api with 100% similarity]
src/plugins/nat/nat44-ed/nat44_ed.api [moved from src/plugins/nat/nat44.api with 99% similarity]
src/plugins/nat/nat44-ed/nat44_ed.c [moved from src/plugins/nat/nat.c with 77% similarity]
src/plugins/nat/nat44-ed/nat44_ed.h [moved from src/plugins/nat/nat.h with 65% similarity]
src/plugins/nat/nat44-ed/nat44_ed_affinity.c [moved from src/plugins/nat/nat_affinity.c with 93% similarity]
src/plugins/nat/nat44-ed/nat44_ed_affinity.h [moved from src/plugins/nat/nat_affinity.h with 96% similarity]
src/plugins/nat/nat44-ed/nat44_ed_api.c [moved from src/plugins/nat/nat44_api.c with 78% similarity]
src/plugins/nat/nat44-ed/nat44_ed_classify.c [moved from src/plugins/nat/nat44_classify.c with 70% similarity]
src/plugins/nat/nat44-ed/nat44_ed_cli.c [moved from src/plugins/nat/nat44_cli.c with 78% similarity]
src/plugins/nat/nat44-ed/nat44_ed_format.c [moved from src/plugins/nat/nat_format.c with 87% similarity]
src/plugins/nat/nat44-ed/nat44_ed_handoff.c [moved from src/plugins/nat/nat44_handoff.c with 99% similarity]
src/plugins/nat/nat44-ed/nat44_ed_in2out.c [moved from src/plugins/nat/in2out_ed.c with 92% similarity]
src/plugins/nat/nat44-ed/nat44_ed_inlines.h [new file with mode: 0644]
src/plugins/nat/nat44-ed/nat44_ed_out2in.c [moved from src/plugins/nat/out2in_ed.c with 94% similarity]
src/plugins/nat/nat44-ei/nat44_ei.api [new file with mode: 0644]
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 [new file with mode: 0644]
src/plugins/nat/nat44-ei/nat44_ei_cli.c [new file with mode: 0644]
src/plugins/nat/nat44-ei/nat44_ei_dpo.c [moved from src/plugins/nat/nat_dpo.c with 84% similarity]
src/plugins/nat/nat44-ei/nat44_ei_dpo.h [moved from src/plugins/nat/nat_dpo.h with 94% similarity]
src/plugins/nat/nat44-ei/nat44_ei_ha.c
src/plugins/nat/nat44-ei/nat44_ei_ha.h
src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c [moved from src/plugins/nat/nat44_hairpinning.c with 57% similarity]
src/plugins/nat/nat44-ei/nat44_ei_hairpinning.h [moved from src/plugins/nat/nat44_hairpinning.h with 56% similarity]
src/plugins/nat/nat44-ei/nat44_ei_handoff.c [new file with mode: 0644]
src/plugins/nat/nat44-ei/nat44_ei_in2out.c
src/plugins/nat/nat44-ei/nat44_ei_inlines.h
src/plugins/nat/nat44-ei/nat44_ei_out2in.c
src/plugins/nat/nat44/ed_inlines.h [deleted file]
src/plugins/nat/nat44/inlines.h [deleted file]
src/plugins/nat/nat64/nat64.api
src/plugins/nat/nat66/nat66.api
src/plugins/nat/nat_inlines.h [deleted file]
src/plugins/nat/test/test_nat44_ed.py
src/plugins/nat/test/test_nat44_ei.py

index 8fefadf..623c92a 100644 (file)
@@ -18,43 +18,60 @@ add_vpp_library(nat
   lib/ipfix_logging.c
   lib/nat_syslog.c
   lib/alloc.c
+  lib/lib.c
 
   INSTALL_HEADERS
   lib/ipfix_logging.h
   lib/nat_syslog.h
   lib/alloc.h
+  lib/lib.h
 )
 
 add_vpp_plugin(nat
   SOURCES
-  nat.c
-  nat44_api.c
-  in2out_ed.c
-  out2in_ed.c
-  nat_dpo.c
-  nat44_cli.c
-  nat44_handoff.c
-  nat44_hairpinning.c
-  nat44_classify.c
-  nat_affinity.c
-  nat_format.c
+  nat44-ed/nat44_ed.c
+  nat44-ed/nat44_ed_api.c
+  nat44-ed/nat44_ed_in2out.c
+  nat44-ed/nat44_ed_out2in.c
+  nat44-ed/nat44_ed_cli.c
+  nat44-ed/nat44_ed_format.c
+  nat44-ed/nat44_ed_affinity.c
+  nat44-ed/nat44_ed_handoff.c
+  nat44-ed/nat44_ed_classify.c
+
+  MULTIARCH_SOURCES
+  nat44-ed/nat44_ed_in2out.c
+  nat44-ed/nat44_ed_out2in.c
+  nat44-ed/nat44_ed_handoff.c
+  nat44-ed/nat44_ed_classify.c
+
+  API_FILES
+  nat44-ed/nat44_ed.api
+  lib/nat_types.api
+
+  LINK_LIBRARIES nat
+)
+
+add_vpp_plugin(nat44_ei
+  SOURCES
   nat44-ei/nat44_ei.c
   nat44-ei/nat44_ei_ha.c
+  nat44-ei/nat44_ei_cli.c
+  nat44-ei/nat44_ei_api.c
+  nat44-ei/nat44_ei_dpo.c
   nat44-ei/nat44_ei_in2out.c
   nat44-ei/nat44_ei_out2in.c
+  nat44-ei/nat44_ei_handoff.c
+  nat44-ei/nat44_ei_hairpinning.c
 
   MULTIARCH_SOURCES
-  in2out_ed.c
-  out2in_ed.c
-  nat44_classify.c
-  nat44_hairpinning.c
-  nat44_handoff.c
   nat44-ei/nat44_ei_in2out.c
   nat44-ei/nat44_ei_out2in.c
+  nat44-ei/nat44_ei_hairpinning.c
 
   API_FILES
-  nat44.api
-  nat_types.api
+  nat44-ei/nat44_ei.api
+  lib/nat_types.api
 
   LINK_LIBRARIES nat
 )
@@ -96,7 +113,7 @@ add_vpp_plugin(nat66
 
   API_FILES
   nat66/nat66.api
-  nat_types.api
+  lib/nat_types.api
 
   LINK_LIBRARIES nat
 )
@@ -115,7 +132,7 @@ add_vpp_plugin(det44
 
   API_FILES
   det44/det44.api
-  nat_types.api
+  lib/nat_types.api
 
   LINK_LIBRARIES nat
 )
@@ -135,7 +152,7 @@ add_vpp_plugin(nat64
 
   API_FILES
   nat64/nat64.api
-  nat_types.api
+  lib/nat_types.api
 
   LINK_LIBRARIES nat
 )
index 175d2c8..bbb8586 100644 (file)
@@ -4,7 +4,17 @@ maintainer:
   - Ole Troan <ot@cisco.com>
   - Filip Varga <fivarga@cisco.com>
 features:
-  - NAT44:
+  - NAT44-EI - IPv4 Endpoint Independent NAT
+      - 1:1 NAT
+      - 1:1 NAT with ports
+      - VRF awareness
+      - Multiple inside interfaces
+      - Hairpinning
+      - IPFIX
+      - Syslog
+      - TCP MSS clamping
+      - Local bypass (DHCP)
+  - NAT44-ED - IPv4 Endpoint Dependent NAT
       - 1:1 NAT
       - 1:1 NAT with ports
       - VRF awareness
@@ -12,13 +22,12 @@ features:
       - Hairpinning
       - IPFIX
       - Syslog
-      - Endpoint dependent NAT
       - TCP MSS clamping
       - Local bypass (DHCP)
   - DET44 - deterministic NAT (CGN)
   - NAT64
   - NAT66
-  - DS-lite
+  - DSLITE
   - 464XLAT
 description: "The Network Address Translation (NAT) plugin offers a multiple address
               translation functions. These can be used in a raft of different
index 9b71b9c..7b6aef7 100644 (file)
@@ -16,7 +16,7 @@
 option version = "1.0.0";
 import "vnet/ip/ip_types.api";
 import "vnet/interface_types.api";
-import "plugins/nat/nat_types.api";
+import "plugins/nat/lib/nat_types.api";
 
 /**
  * @file det44.api
index 25fcd01..0537957 100644 (file)
@@ -203,25 +203,6 @@ dslite_show_b4_ip6_addr_command_fn (vlib_main_t * vm,
   return 0;
 }
 
-static u8 *
-format_nat_protocol (u8 * s, va_list * args)
-{
-  u32 i = va_arg (*args, u32);
-  u8 *t = 0;
-
-  switch (i)
-    {
-#define _(N, j, n, str) case NAT_PROTOCOL_##N: t = (u8 *) str; break;
-      foreach_nat_protocol
-#undef _
-    default:
-      s = format (s, "unknown");
-      return s;
-    }
-  s = format (s, "%s", t);
-  return s;
-}
-
 static u8 *
 format_dslite_session (u8 * s, va_list * args)
 {
diff --git a/src/plugins/nat/lib/lib.c b/src/plugins/nat/lib/lib.c
new file mode 100644 (file)
index 0000000..d2def2c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <nat/lib/lib.h>
+
+uword
+unformat_nat_protocol (unformat_input_t *input, va_list *args)
+{
+  u32 *r = va_arg (*args, u32 *);
+
+  if (0)
+    ;
+#define _(N, i, n, s) else if (unformat (input, s)) *r = NAT_PROTOCOL_##N;
+  foreach_nat_protocol
+#undef _
+    else return 0;
+  return 1;
+}
+
+u8 *
+format_nat_protocol (u8 *s, va_list *args)
+{
+  u32 i = va_arg (*args, u32);
+  u8 *t = 0;
+
+  switch (i)
+    {
+#define _(N, j, n, str)                                                       \
+  case NAT_PROTOCOL_##N:                                                      \
+    t = (u8 *) str;                                                           \
+    break;
+      foreach_nat_protocol
+#undef _
+       default : s = format (s, "unknown");
+      return s;
+    }
+  s = format (s, "%s", t);
+  return s;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 04bad5c..b0b5229 100644 (file)
@@ -95,7 +95,52 @@ nat_reset_timeouts (nat_timeouts_t * timeouts)
   timeouts->icmp = NAT_ICMP_TIMEOUT;
 }
 
-// TODO: move common formating definitions here
+static_always_inline u32
+nat_session_get_timeout (nat_timeouts_t *timeouts, nat_protocol_t proto,
+                        u8 state)
+{
+  switch (proto)
+    {
+    case NAT_PROTOCOL_ICMP:
+      return timeouts->icmp;
+    case NAT_PROTOCOL_UDP:
+      return timeouts->udp;
+    case NAT_PROTOCOL_TCP:
+      {
+       if (state)
+         return timeouts->tcp.transitory;
+       else
+         return timeouts->tcp.established;
+      }
+    default:
+      return timeouts->udp;
+    }
+  return 0;
+}
+
+static_always_inline u32
+nat_calc_bihash_buckets (u32 n_elts)
+{
+  n_elts = n_elts / 2.5;
+  u64 lower_pow2 = 1;
+  while (lower_pow2 * 2 < n_elts)
+    {
+      lower_pow2 = 2 * lower_pow2;
+    }
+  u64 upper_pow2 = 2 * lower_pow2;
+  if ((upper_pow2 - n_elts) < (n_elts - lower_pow2))
+    {
+      if (upper_pow2 <= UINT32_MAX)
+       {
+         return upper_pow2;
+       }
+    }
+  return lower_pow2;
+}
+
+u8 *format_nat_protocol (u8 *s, va_list *args);
+
+uword unformat_nat_protocol (unformat_input_t *input, va_list *args);
 
 #endif /* included_nat_lib_h__ */
 /*
diff --git a/src/plugins/nat/lib/log.h b/src/plugins/nat/lib/log.h
new file mode 100644 (file)
index 0000000..26bd93f
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file
+ * @brief NAT port/address allocation lib
+ */
+#ifndef included_nat_log_h__
+#define included_nat_log_h__
+
+#include <vppinfra/elog.h>
+
+#define foreach_nat_log_level                                                 \
+  _ (0x00, LOG_NONE)                                                          \
+  _ (0x01, LOG_ERROR)                                                         \
+  _ (0x02, LOG_WARNING)                                                       \
+  _ (0x03, LOG_NOTICE)                                                        \
+  _ (0x04, LOG_INFO)                                                          \
+  _ (0x05, LOG_DEBUG)
+
+typedef enum nat_log_level_t_
+{
+#define _(n, f) NAT_##f = n,
+  foreach_nat_log_level
+#undef _
+} nat_log_level_t;
+
+#define nat_elog(_pm, _level, _str)                                           \
+  do                                                                          \
+    {                                                                         \
+      if (PREDICT_FALSE (_pm->log_level >= _level))                           \
+       {                                                                     \
+         ELOG_TYPE_DECLARE (e) = {                                           \
+           .format = "nat-msg " _str,                                        \
+           .format_args = "",                                                \
+         };                                                                  \
+         ELOG_DATA (&vlib_global_main.elog_main, e);                         \
+       }                                                                     \
+    }                                                                         \
+  while (0);
+
+#define nat_elog_addr(_pm, _level, _str, _addr)                               \
+  do                                                                          \
+    {                                                                         \
+      if (PREDICT_FALSE (_pm->log_level >= _level))                           \
+       {                                                                     \
+         ELOG_TYPE_DECLARE (e) = {                                           \
+           .format = "nat-msg " _str " %d.%d.%d.%d",                         \
+           .format_args = "i1i1i1i1",                                        \
+         };                                                                  \
+         CLIB_PACKED (struct {                                               \
+           u8 oct1;                                                          \
+           u8 oct2;                                                          \
+           u8 oct3;                                                          \
+           u8 oct4;                                                          \
+         }) *                                                                \
+           ed;                                                               \
+         ed = ELOG_DATA (&vlib_global_main.elog_main, e);                    \
+         ed->oct4 = _addr >> 24;                                             \
+         ed->oct3 = _addr >> 16;                                             \
+         ed->oct2 = _addr >> 8;                                              \
+         ed->oct1 = _addr;                                                   \
+       }                                                                     \
+    }                                                                         \
+  while (0);
+
+#define nat_elog_debug_handoff(_pm, _str, _tid, _fib, _src, _dst)             \
+  do                                                                          \
+    {                                                                         \
+      if (PREDICT_FALSE (_pm->log_level >= NAT_LOG_DEBUG))                    \
+       {                                                                     \
+         ELOG_TYPE_DECLARE (e) = {                                           \
+           .format = "nat-msg " _str " ip src: %d.%d.%d.%d dst: %d.%d.%d.%d" \
+                     " tid from: %d to: %d fib: %d",                         \
+           .format_args = "i1i1i1i1i1i1i1i1i4i4i4",                          \
+         };                                                                  \
+         CLIB_PACKED (struct {                                               \
+           u8 src_oct1;                                                      \
+           u8 src_oct2;                                                      \
+           u8 src_oct3;                                                      \
+           u8 src_oct4;                                                      \
+           u8 dst_oct1;                                                      \
+           u8 dst_oct2;                                                      \
+           u8 dst_oct3;                                                      \
+           u8 dst_oct4;                                                      \
+           u32 ftid;                                                         \
+           u32 ttid;                                                         \
+           u32 fib;                                                          \
+         }) *                                                                \
+           ed;                                                               \
+         ed = ELOG_DATA (&vlib_global_main.elog_main, e);                    \
+         ed->src_oct1 = _src >> 24;                                          \
+         ed->src_oct2 = _src >> 16;                                          \
+         ed->src_oct3 = _src >> 8;                                           \
+         ed->src_oct4 = _src;                                                \
+         ed->dst_oct1 = _dst >> 24;                                          \
+         ed->dst_oct2 = _dst >> 16;                                          \
+         ed->dst_oct3 = _dst >> 8;                                           \
+         ed->dst_oct4 = _dst;                                                \
+         ed->ftid = vlib_get_thread_index ();                                \
+         ed->ttid = _tid;                                                    \
+         ed->fib = _fib;                                                     \
+       }                                                                     \
+    }                                                                         \
+  while (0);
+
+#define nat_elog_debug_handoff_v2(_pm, _str, _prt, _fib, _src, _dst)          \
+  do                                                                          \
+    {                                                                         \
+      if (PREDICT_FALSE (_pm->log_level >= NAT_LOG_DEBUG))                    \
+       {                                                                     \
+         ELOG_TYPE_DECLARE (e) = {                                           \
+           .format =                                                         \
+             "nat-msg " _str " ip_src:%d.%d.%d.%d ip_dst:%d.%d.%d.%d"        \
+             " tid:%d prt:%d fib:%d",                                        \
+           .format_args = "i1i1i1i1i1i1i1i1i4i4i4",                          \
+         };                                                                  \
+         CLIB_PACKED (struct {                                               \
+           u8 src_oct1;                                                      \
+           u8 src_oct2;                                                      \
+           u8 src_oct3;                                                      \
+           u8 src_oct4;                                                      \
+           u8 dst_oct1;                                                      \
+           u8 dst_oct2;                                                      \
+           u8 dst_oct3;                                                      \
+           u8 dst_oct4;                                                      \
+           u32 tid;                                                          \
+           u32 prt;                                                          \
+           u32 fib;                                                          \
+         }) *                                                                \
+           ed;                                                               \
+         ed = ELOG_DATA (&vlib_global_main.elog_main, e);                    \
+         ed->src_oct1 = _src >> 24;                                          \
+         ed->src_oct2 = _src >> 16;                                          \
+         ed->src_oct3 = _src >> 8;                                           \
+         ed->src_oct4 = _src;                                                \
+         ed->dst_oct1 = _dst >> 24;                                          \
+         ed->dst_oct2 = _dst >> 16;                                          \
+         ed->dst_oct3 = _dst >> 8;                                           \
+         ed->dst_oct4 = _dst;                                                \
+         ed->tid = vlib_get_thread_index ();                                 \
+         ed->prt = _prt;                                                     \
+         ed->fib = _fib;                                                     \
+       }                                                                     \
+    }                                                                         \
+  while (0);
+
+#define nat_elog_X1(_pm, _level, _fmt, _arg, _val1)                           \
+  do                                                                          \
+    {                                                                         \
+      if (PREDICT_FALSE (_pm->log_level >= _level))                           \
+       {                                                                     \
+         ELOG_TYPE_DECLARE (e) = {                                           \
+           .format = "nat-msg " _fmt,                                        \
+           .format_args = _arg,                                              \
+         };                                                                  \
+         CLIB_PACKED (struct { typeof (_val1) val1; }) * ed;                 \
+         ed = ELOG_DATA (&vlib_global_main.elog_main, e);                    \
+         ed->val1 = _val1;                                                   \
+       }                                                                     \
+    }                                                                         \
+  while (0);
+
+#define nat_elog_notice(_pm, nat_elog_str)                                    \
+  nat_elog (_pm, NAT_LOG_INFO, "[notice] " nat_elog_str)
+#define nat_elog_warn(_pm, nat_elog_str)                                      \
+  nat_elog (_pm, NAT_LOG_WARNING, "[warning] " nat_elog_str)
+#define nat_elog_err(_pm, nat_elog_str)                                       \
+  nat_elog (_pm, NAT_LOG_ERROR, "[error] " nat_elog_str)
+#define nat_elog_debug(_pm, nat_elog_str)                                     \
+  nat_elog (_pm, NAT_LOG_DEBUG, "[debug] " nat_elog_str)
+#define nat_elog_info(_pm, nat_elog_str)                                      \
+  nat_elog (_pm, NAT_LOG_INFO, "[info] " nat_elog_str)
+
+#define nat_elog_notice_X1(_pm, nat_elog_fmt_str, nat_elog_fmt_arg,           \
+                          nat_elog_val1)                                     \
+  nat_elog_X1 (_pm, NAT_LOG_NOTICE, "[notice] " nat_elog_fmt_str,             \
+              nat_elog_fmt_arg, nat_elog_val1)
+#define nat_elog_warn_X1(_pm, nat_elog_fmt_str, nat_elog_fmt_arg,             \
+                        nat_elog_val1)                                       \
+  nat_elog_X1 (_pm, NAT_LOG_WARNING, "[warning] " nat_elog_fmt_str,           \
+              nat_elog_fmt_arg, nat_elog_val1)
+#define nat_elog_err_X1(_pm, nat_elog_fmt_str, nat_elog_fmt_arg,              \
+                       nat_elog_val1)                                        \
+  nat_elog_X1 (_pm, NAT_LOG_ERROR, "[error] " nat_elog_fmt_str,               \
+              nat_elog_fmt_arg, nat_elog_val1)
+#define nat_elog_debug_X1(_pm, nat_elog_fmt_str, nat_elog_fmt_arg,            \
+                         nat_elog_val1)                                      \
+  nat_elog_X1 (_pm, NAT_LOG_DEBUG, "[debug] " nat_elog_fmt_str,               \
+              nat_elog_fmt_arg, nat_elog_val1)
+#define nat_elog_info_X1(_pm, nat_elog_fmt_str, nat_elog_fmt_arg,             \
+                        nat_elog_val1)                                       \
+  nat_elog_X1 (_pm, NAT_LOG_INFO, "[info] " nat_elog_fmt_str,                 \
+              nat_elog_fmt_arg, nat_elog_val1)
+
+#endif /* included_nat_lib_h__ */
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index c75b804..0bd7993 100644 (file)
@@ -77,6 +77,20 @@ mss_clamping (u16 mss_clamping, tcp_header_t * tcp, ip_csum_t * sum)
     }
 }
 
+static_always_inline u16
+nat_random_port (u32 *random_seed, u16 min, u16 max)
+{
+  u32 rwide;
+  u16 r;
+
+  rwide = random_u32 (random_seed);
+  r = rwide & 0xFFFF;
+  if (r >= min && r <= max)
+    return r;
+
+  return min + (rwide % (max - min + 1));
+}
+
 #endif /* __included_lib_nat_inlines_h__ */
 
 /*
similarity index 99%
rename from src/plugins/nat/nat44.api
rename to src/plugins/nat/nat44-ed/nat44_ed.api
index f7fe7fd..6a2d44a 100644 (file)
@@ -16,7 +16,7 @@
 option version = "5.2.0";
 import "vnet/ip/ip_types.api";
 import "vnet/interface_types.api";
-import "plugins/nat/nat_types.api";
+import "plugins/nat/lib/nat_types.api";
 
 /**
  * @file nat44.api
@@ -390,42 +390,6 @@ define nat_get_timeouts_reply {
   u32 icmp;
 };
 
-/** \brief Set NAT handoff frame queue options
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-    @param frame_queue_nelts - number of worker handoff frame queue elements
-*/
-autoreply define nat_set_fq_options {
-  option in_progress;
-  u32 client_index;
-  u32 context;
-  u32 frame_queue_nelts;
-};
-
-/** \brief Show NAT handoff frame queue options
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-*/
-define nat_show_fq_options
-{
-  option in_progress;
-  u32 client_index;
-  u32 context;
-};
-
-/** \brief Show NAT handoff frame queue options reply
-    @param context - sender context, to match reply w/ request
-    @param retval - return code for the request
-    @param frame_queue_nelts - number of worker handoff frame queue elements
-*/
-define nat_show_fq_options_reply
-{
-  option in_progress;
-  u32 context;
-  i32 retval;
-  u32 frame_queue_nelts;
-};
-
 /** \brief Set address and port assignment algorithm
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
@@ -1212,3 +1176,39 @@ define nat44_forwarding_is_enabled_reply {
   u32 context;
   bool enabled;
 };
+
+/** \brief Set NAT handoff frame queue options
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param frame_queue_nelts - number of worker handoff frame queue elements
+*/
+autoreply define nat44_ed_set_fq_options {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u32 frame_queue_nelts;
+};
+
+/** \brief Show NAT handoff frame queue options
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ed_show_fq_options
+{
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Show NAT handoff frame queue options reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code for the request
+    @param frame_queue_nelts - number of worker handoff frame queue elements
+*/
+define nat44_ed_show_fq_options_reply
+{
+  option in_progress;
+  u32 context;
+  i32 retval;
+  u32 frame_queue_nelts;
+};
similarity index 77%
rename from src/plugins/nat/nat.c
rename to src/plugins/nat/nat44-ed/nat44_ed.c
index 85d4775..d9d35fc 100644 (file)
  * limitations under the License.
  */
 
+#include <vpp/app/version.h>
+
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ip/ip4.h>
-#include <vnet/plugin/plugin.h>
-#include <nat/nat.h>
-#include <nat/nat_dpo.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/lib/nat_syslog.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44/inlines.h>
-#include <nat/nat_affinity.h>
+#include <vnet/ip/ip_table.h>
+#include <vnet/ip/reass/ip4_sv_reass.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/ip4_fib.h>
-#include <vnet/ip/reass/ip4_sv_reass.h>
+#include <vnet/plugin/plugin.h>
 #include <vppinfra/bihash_16_8.h>
-#include <nat/nat44/ed_inlines.h>
-#include <vnet/ip/ip_table.h>
 
-#include <nat/nat44-ei/nat44_ei_ha.h>
-#include <nat/nat44-ei/nat44_ei.h>
-
-#include <vpp/app/version.h>
+#include <nat/lib/log.h>
+#include <nat/lib/nat_syslog.h>
 #include <nat/lib/nat_inlines.h>
+#include <nat/lib/ipfix_logging.h>
+
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_affinity.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
 
 snat_main_t snat_main;
 
+static_always_inline void nat_validate_interface_counters (snat_main_t *sm,
+                                                          u32 sw_if_index);
+
 #define skip_if_disabled()                                                    \
   do                                                                          \
     {                                                                         \
@@ -111,11 +111,6 @@ VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
                                "ip4-dhcp-client-detect"),
 };
-VNET_FEATURE_INIT (ip4_nat_classify, static) = {
-  .arc_name = "ip4-unicast",
-  .node_name = "nat44-classify",
-  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
-};
 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
   .arc_name = "ip4-unicast",
   .node_name = "nat44-ed-in2out",
@@ -148,11 +143,6 @@ VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
                                "ip4-dhcp-client-detect"),
 };
-VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
-  .arc_name = "ip4-unicast",
-  .node_name = "nat44-hairpin-dst",
-  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
-};
 
 /* Hook up output features */
 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
@@ -165,11 +155,6 @@ VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
   .node_name = "nat44-in2out-output-worker-handoff",
   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
 };
-VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
-  .arc_name = "ip4-output",
-  .node_name = "nat44-hairpin-src",
-  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
-};
 VNET_FEATURE_INIT (nat_pre_in2out_output, static) = {
   .arc_name = "ip4-output",
   .node_name = "nat-pre-in2out-output",
@@ -183,22 +168,13 @@ VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
 };
 
-/* Hook up ip4-local features */
-VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
-{
-  .arc_name = "ip4-local",
-  .node_name = "nat44-hairpinning",
-  .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
-};
-
 VLIB_PLUGIN_REGISTER () = {
     .version = VPP_BUILD_VER,
     .description = "Network Address Translation (NAT)",
 };
 /* *INDENT-ON* */
 
-static void nat44_ed_db_init (u32 translations, u32 translation_buckets,
-                             u32 user_buckets);
+static void nat44_ed_db_init (u32 translations, u32 translation_buckets);
 
 static void nat44_ed_db_free ();
 
@@ -235,20 +211,6 @@ format_static_mapping_kvp (u8 * s, va_list * args)
   return s;
 }
 
-u8 *
-format_user_kvp (u8 * s, va_list * args)
-{
-  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
-  snat_user_key_t k;
-
-  k.as_u64 = v->key;
-
-  s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
-             k.fib_index, v->value);
-
-  return s;
-}
-
 u8 *
 format_ed_session_kvp (u8 * s, va_list * args)
 {
@@ -275,54 +237,29 @@ void
 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
                       u8 is_ha)
 {
-  clib_bihash_kv_8_8_t kv;
-
-  if (is_ed_session (s))
-    {
       per_vrf_sessions_unregister_session (s, thread_index);
 
       if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 0))
-       nat_elog_warn ("flow hash del failed");
+       nat_elog_warn (sm, "flow hash del failed");
 
       if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
-       nat_elog_warn ("flow hash del failed");
-    }
+       nat_elog_warn (sm, "flow hash del failed");
 
   if (is_fwd_bypass_session (s))
     {
       return;
     }
 
-  /* session lookup tables */
-  if (is_ed_session (s))
-    {
       if (is_affinity_sessions (s))
        nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
                             s->nat_proto, s->out2in.port);
 
       if (!is_ha)
-       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
-                              &s->in2out.addr, s->in2out.port,
-                              &s->ext_host_nat_addr, s->ext_host_nat_port,
-                              &s->out2in.addr, s->out2in.port,
-                              &s->ext_host_addr, s->ext_host_port,
-                              s->nat_proto, is_twice_nat_session (s));
-    }
-  else
-    {
-      init_nat_i2o_k (&kv, s);
-      if (clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0))
-       nat_elog_warn ("in2out key del failed");
-      init_nat_o2i_k (&kv, s);
-      if (clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0))
-       nat_elog_warn ("out2in key del failed");
-
-      if (!is_ha)
-       nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
-                                &s->in2out.addr, s->in2out.port,
-                                &s->out2in.addr, s->out2in.port,
-                                s->nat_proto);
-    }
+       nat_syslog_nat44_sdel (
+         0, s->in2out.fib_index, &s->in2out.addr, s->in2out.port,
+         &s->ext_host_nat_addr, s->ext_host_nat_port, &s->out2in.addr,
+         s->out2in.port, &s->ext_host_addr, s->ext_host_port, s->nat_proto,
+         is_twice_nat_session (s));
 
   if (snat_is_unk_proto_session (s))
     return;
@@ -337,10 +274,6 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
                                          s->in2out.port,
                                          s->out2in.port,
                                          s->in2out.fib_index);
-
-      nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
-                  s->ext_host_port, s->nat_proto, s->out2in.fib_index,
-                  thread_index);
     }
 
   /* Twice NAT address and port for external host */
@@ -360,143 +293,6 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
                                      s->nat_proto);
 }
 
-snat_user_t *
-nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
-                       u32 thread_index)
-{
-  snat_user_t *u = 0;
-  snat_user_key_t user_key;
-  clib_bihash_kv_8_8_t kv, value;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  dlist_elt_t *per_user_list_head_elt;
-
-  user_key.addr.as_u32 = addr->as_u32;
-  user_key.fib_index = fib_index;
-  kv.key = user_key.as_u64;
-
-  /* Ever heard of the "user" = src ip4 address before? */
-  if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
-    {
-      if (pool_elts (tsm->users) >= sm->max_users_per_thread)
-       {
-         vlib_increment_simple_counter (&sm->user_limit_reached,
-                                        thread_index, 0, 1);
-         nat_elog_warn ("maximum user limit reached");
-         return NULL;
-       }
-      /* no, make a new one */
-      pool_get (tsm->users, u);
-      clib_memset (u, 0, sizeof (*u));
-
-      u->addr.as_u32 = addr->as_u32;
-      u->fib_index = fib_index;
-
-      pool_get (tsm->list_pool, per_user_list_head_elt);
-
-      u->sessions_per_user_list_head_index = per_user_list_head_elt -
-       tsm->list_pool;
-
-      clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
-
-      kv.value = u - tsm->users;
-
-      /* add user */
-      if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
-       {
-         nat_elog_warn ("user_hash key add failed");
-         nat44_delete_user_with_no_session (sm, u, thread_index);
-         return NULL;
-       }
-
-      vlib_set_simple_counter (&sm->total_users, thread_index, 0,
-                              pool_elts (tsm->users));
-    }
-  else
-    {
-      u = pool_elt_at_index (tsm->users, value.value);
-    }
-
-  return u;
-}
-
-// only NAT EI
-snat_session_t *
-nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
-                             u32 thread_index, f64 now)
-{
-  snat_session_t *s;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  u32 oldest_per_user_translation_list_index, session_index;
-  dlist_elt_t *oldest_per_user_translation_list_elt;
-  dlist_elt_t *per_user_translation_list_elt;
-
-  /* Over quota? Recycle the least recently used translation */
-  if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
-    {
-      oldest_per_user_translation_list_index =
-       clib_dlist_remove_head (tsm->list_pool,
-                               u->sessions_per_user_list_head_index);
-
-      ASSERT (oldest_per_user_translation_list_index != ~0);
-
-      /* Add it back to the end of the LRU list */
-      clib_dlist_addtail (tsm->list_pool,
-                         u->sessions_per_user_list_head_index,
-                         oldest_per_user_translation_list_index);
-      /* Get the list element */
-      oldest_per_user_translation_list_elt =
-       pool_elt_at_index (tsm->list_pool,
-                          oldest_per_user_translation_list_index);
-
-      /* Get the session index from the list element */
-      session_index = oldest_per_user_translation_list_elt->value;
-
-      /* Get the session */
-      s = pool_elt_at_index (tsm->sessions, session_index);
-
-      // TODO: ONLY EI version should be called
-      nat_free_session_data (sm, s, thread_index, 0);
-      if (snat_is_session_static (s))
-       u->nstaticsessions--;
-      else
-       u->nsessions--;
-      s->flags = 0;
-      s->total_bytes = 0;
-      s->total_pkts = 0;
-      s->state = 0;
-      s->ext_host_addr.as_u32 = 0;
-      s->ext_host_port = 0;
-      s->ext_host_nat_addr.as_u32 = 0;
-      s->ext_host_nat_port = 0;
-    }
-  else
-    {
-      pool_get (tsm->sessions, s);
-      clib_memset (s, 0, sizeof (*s));
-
-      /* Create list elts */
-      pool_get (tsm->list_pool, per_user_translation_list_elt);
-      clib_dlist_init (tsm->list_pool,
-                      per_user_translation_list_elt - tsm->list_pool);
-
-      per_user_translation_list_elt->value = s - tsm->sessions;
-      s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
-      s->per_user_list_head_index = u->sessions_per_user_list_head_index;
-
-      clib_dlist_addtail (tsm->list_pool,
-                         s->per_user_list_head_index,
-                         per_user_translation_list_elt - tsm->list_pool);
-
-      s->user_index = u - tsm->users;
-      vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
-                              pool_elts (tsm->sessions));
-    }
-
-  s->ha_last_refreshed = now;
-
-  return s;
-}
-
 void
 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
                          int is_add)
@@ -534,12 +330,6 @@ snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
   snat_interface_t *i;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
 
-  if (twice_nat && !sm->endpoint_dependent)
-    {
-      nat_log_err ("unsupported");
-      return VNET_API_ERROR_UNSUPPORTED;
-    }
-
   /* Check if address already exists */
   /* *INDENT-OFF* */
   vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
@@ -582,19 +372,19 @@ snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
   /* *INDENT-OFF* */
   pool_foreach (i, sm->interfaces)
    {
-    if (nat_interface_is_inside(i) || sm->out2in_dpo)
-      continue;
+     if (nat_interface_is_inside (i))
+       continue;
 
-    snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
-    break;
+     snat_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
+     break;
   }
   pool_foreach (i, sm->output_feature_interfaces)
    {
-    if (nat_interface_is_inside(i) || sm->out2in_dpo)
-      continue;
+     if (nat_interface_is_inside (i))
+       continue;
 
-    snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
-    break;
+     snat_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
+     break;
   }
   /* *INDENT-ON* */
 
@@ -706,14 +496,12 @@ nat_ed_static_mapping_del_sessions (snat_main_t * sm,
   vec_free (indexes_to_free);
 }
 
-static_always_inline int
-nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
-                                u16 l_port, u16 e_port, u32 vrf_id,
-                                int addr_only, u32 sw_if_index,
-                                nat_protocol_t proto, int is_add,
-                                twice_nat_type_t twice_nat, u8 out2in_only,
-                                u8 *tag, u8 identity_nat,
-                                ip4_address_t pool_addr, int exact)
+int
+snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
+                        u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
+                        u32 sw_if_index, nat_protocol_t proto, int is_add,
+                        twice_nat_type_t twice_nat, u8 out2in_only, u8 *tag,
+                        u8 identity_nat, ip4_address_t pool_addr, int exact)
 {
   snat_main_t *sm = &snat_main;
   snat_static_mapping_t *m;
@@ -721,24 +509,11 @@ nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
   snat_address_t *a = 0;
   u32 fib_index = ~0;
   snat_interface_t *interface;
-  int i;
   snat_main_per_thread_data_t *tsm;
-  snat_user_key_t u_key;
-  snat_user_t *u;
-  dlist_elt_t *head, *elt;
-  u32 elt_index, head_index;
-  u32 ses_index;
-  u64 user_index;
-  snat_session_t *s;
   snat_static_map_resolve_t *rp, *rp_match = 0;
   nat44_lb_addr_port_t *local;
   u32 find = ~0;
-
-  if (!sm->endpoint_dependent)
-    {
-      if (twice_nat || out2in_only)
-       return VNET_API_ERROR_UNSUPPORTED;
-    }
+  int i;
 
   /* If the external address is a specific interface address */
   if (sw_if_index != ~0)
@@ -892,8 +667,7 @@ nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
                       break;
                      foreach_nat_protocol
 #undef _
-                   default:
-                     nat_elog_info ("unknown protocol");
+                       default : nat_elog_info (sm, "unknown protocol");
                      return VNET_API_ERROR_INVALID_VALUE_2;
                    }
                  break;
@@ -980,47 +754,6 @@ nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
       init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
                   m - sm->static_mappings);
       clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
-
-      /* Delete dynamic sessions matching local address (+ local port) */
-      // TODO: based on type of NAT EI/ED
-      if (!(sm->static_mapping_only))
-       {
-         u_key.addr = m->local_addr;
-         u_key.fib_index = m->fib_index;
-         kv.key = u_key.as_u64;
-         if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
-           {
-             user_index = value.value;
-             u = pool_elt_at_index (tsm->users, user_index);
-             if (u->nsessions)
-               {
-                 head_index = u->sessions_per_user_list_head_index;
-                 head = pool_elt_at_index (tsm->list_pool, head_index);
-                 elt_index = head->next;
-                 elt = pool_elt_at_index (tsm->list_pool, elt_index);
-                 ses_index = elt->value;
-                 while (ses_index != ~0)
-                   {
-                     s = pool_elt_at_index (tsm->sessions, ses_index);
-                     elt = pool_elt_at_index (tsm->list_pool, elt->next);
-                     ses_index = elt->value;
-
-                     if (snat_is_session_static (s))
-                       continue;
-
-                     if (!addr_only && s->in2out.port != m->local_port)
-                       continue;
-
-                     nat_free_session_data (sm, s,
-                                            tsm - sm->per_thread_data, 0);
-                     nat44_delete_session (sm, s, tsm - sm->per_thread_data);
-
-                     if (!addr_only && !sm->endpoint_dependent)
-                       break;
-                   }
-               }
-           }
-       }
     }
   else
     {
@@ -1075,8 +808,7 @@ nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
                       break;
                      foreach_nat_protocol
 #undef _
-                   default:
-                     nat_elog_info ("unknown protocol");
+                       default : nat_elog_info (sm, "unknown protocol");
                      return VNET_API_ERROR_INVALID_VALUE_2;
                    }
                  break;
@@ -1097,21 +829,9 @@ nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
       if (!(sm->static_mapping_only) ||
          (sm->static_mapping_only && sm->static_mapping_connection_tracking))
        {
-         if (sm->endpoint_dependent)
-           {
-             nat_ed_static_mapping_del_sessions (sm, tsm, m->local_addr,
-                                                 m->local_port, m->proto,
-                                                 fib_index, addr_only,
-                                                 e_addr, e_port);
-           }
-         else
-           {
-             u_key.addr = m->local_addr;
-             u_key.fib_index = fib_index;
-             kv.key = u_key.as_u64;
-             nat44_ei_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
-                                                   e_addr, e_port);
-           }
+         nat_ed_static_mapping_del_sessions (
+           sm, tsm, m->local_addr, m->local_port, m->proto, fib_index,
+           addr_only, e_addr, e_port);
        }
 
       fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
@@ -1134,50 +854,25 @@ nat44_ed_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
   /* *INDENT-OFF* */
   pool_foreach (interface, sm->interfaces)
    {
-    if (nat_interface_is_inside(interface) || sm->out2in_dpo)
-      continue;
+     if (nat_interface_is_inside (interface))
+       continue;
 
-    snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
-    break;
+     snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
+     break;
   }
   pool_foreach (interface, sm->output_feature_interfaces)
    {
-    if (nat_interface_is_inside(interface) || sm->out2in_dpo)
-      continue;
+     if (nat_interface_is_inside (interface))
+       continue;
 
-    snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
-    break;
+     snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
+     break;
   }
   /* *INDENT-ON* */
 
   return 0;
 }
 
-int
-snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
-                        u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
-                        u32 sw_if_index, nat_protocol_t proto, int is_add,
-                        twice_nat_type_t twice_nat, u8 out2in_only, u8 *tag,
-                        u8 identity_nat, ip4_address_t pool_addr, int exact)
-{
-  snat_main_t *sm = &snat_main;
-  int rv;
-
-  if (sm->endpoint_dependent)
-    {
-      rv = nat44_ed_add_del_static_mapping (
-       l_addr, e_addr, l_port, e_port, vrf_id, addr_only, sw_if_index, proto,
-       is_add, twice_nat, out2in_only, tag, identity_nat, pool_addr, exact);
-    }
-  else
-    {
-      rv = nat44_ei_add_del_static_mapping (
-       l_addr, e_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only,
-       identity_nat, tag, is_add);
-    }
-  return rv;
-}
-
 int
 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                                 nat_protocol_t proto,
@@ -1195,9 +890,6 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
   snat_session_t *s;
   uword *bitmap = 0;
 
-  if (!sm->endpoint_dependent)
-    return VNET_API_ERROR_UNSUPPORTED;
-
   init_nat_k (&kv, e_addr, e_port, 0, proto);
   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
     m = 0;
@@ -1237,8 +929,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       break;
                      foreach_nat_protocol
 #undef _
-                   default:
-                     nat_elog_info ("unknown protocol");
+                       default : nat_elog_info (sm, "unknown protocol");
                      return VNET_API_ERROR_INVALID_VALUE_2;
                    }
                  break;
@@ -1271,7 +962,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                   m - sm->static_mappings);
       if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
        {
-         nat_elog_err ("static_mapping_by_external key add failed");
+         nat_elog_err (sm, "static_mapping_by_external key add failed");
          return VNET_API_ERROR_UNSPECIFIED;
        }
 
@@ -1344,8 +1035,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
                       break;
                      foreach_nat_protocol
 #undef _
-                   default:
-                     nat_elog_info ("unknown protocol");
+                       default : nat_elog_info (sm, "unknown protocol");
                      return VNET_API_ERROR_INVALID_VALUE_2;
                    }
                  break;
@@ -1356,7 +1046,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
       init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
       if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
        {
-         nat_elog_err ("static_mapping_by_external key del failed");
+         nat_elog_err (sm, "static_mapping_by_external key del failed");
          return VNET_API_ERROR_UNSPECIFIED;
        }
 
@@ -1370,34 +1060,36 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
 init_nat_k(&              kv, local->addr, local->port, local->fib_index, m->proto);
               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
                 {
-                  nat_elog_err ("static_mapping_by_local key del failed");
-                  return VNET_API_ERROR_UNSPECIFIED;
-                }
-            }
+                 nat_elog_err (sm, "static_mapping_by_local key del failed");
+                 return VNET_API_ERROR_UNSPECIFIED;
+               }
+           }
 
-          if (sm->num_workers > 1)
-            {
-              ip4_header_t ip = {
-                .src_address = local->addr,
-              };
-              tsm = vec_elt_at_index (sm->per_thread_data,
-                                      sm->worker_in2out_cb (&ip, m->fib_index, 0));
-            }
-          else
-            tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
+         if (sm->num_workers > 1)
+           {
+             ip4_header_t ip = {
+               .src_address = local->addr,
+             };
+             tsm =
+               vec_elt_at_index (sm->per_thread_data,
+                                 sm->worker_in2out_cb (&ip, m->fib_index, 0));
+           }
+         else
+           tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
 
-          /* Delete sessions */
-          pool_foreach (s, tsm->sessions) {
-            if (!(is_lb_session (s)))
-              continue;
+         /* Delete sessions */
+         pool_foreach (s, tsm->sessions)
+           {
+             if (!(is_lb_session (s)))
+               continue;
 
-            if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
-                s->in2out.port != local->port)
-              continue;
+             if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
+                 s->in2out.port != local->port)
+               continue;
 
-            nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
-            nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
-          }
+             nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
+             nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
+           }
       }
       /* *INDENT-ON* */
       if (m->affinity)
@@ -1428,9 +1120,6 @@ nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
   uword *bitmap = 0;
   int i;
 
-  if (!sm->endpoint_dependent)
-    return VNET_API_ERROR_FEATURE_DISABLED;
-
   init_nat_k (&kv, e_addr, e_port, 0, proto);
   if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
     m = pool_elt_at_index (sm->static_mappings, value.value);
@@ -1473,7 +1162,7 @@ nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
          init_nat_kv (&kv, l_addr, l_port, local->fib_index, proto, 0,
                       m - sm->static_mappings);
          if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
-           nat_elog_err ("static_mapping_by_local key add failed");
+           nat_elog_err (sm, "static_mapping_by_local key add failed");
        }
     }
   else
@@ -1491,7 +1180,7 @@ nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
        {
          init_nat_k (&kv, l_addr, l_port, match_local->fib_index, proto);
          if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
-           nat_elog_err ("static_mapping_by_local key del failed");
+           nat_elog_err (sm, "static_mapping_by_local key del failed");
        }
 
       if (sm->num_workers > 1)
@@ -1630,7 +1319,6 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
     {
       vec_foreach (tsm, sm->per_thread_data)
       {
-        /* *INDENT-OFF* */
         pool_foreach (ses, tsm->sessions)  {
           if (ses->out2in.addr.as_u32 == addr.as_u32)
             {
@@ -1638,24 +1326,12 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
               vec_add1 (ses_to_be_removed, ses - tsm->sessions);
             }
         }
-        /* *INDENT-ON* */
 
-       if (sm->endpoint_dependent)
-         {
            vec_foreach (ses_index, ses_to_be_removed)
            {
              ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
              nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1);
            }
-         }
-       else
-         {
-           vec_foreach (ses_index, ses_to_be_removed)
-           {
-             ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
-             nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
-           }
-         }
 
        vec_free (ses_to_be_removed);
       }
@@ -1676,59 +1352,24 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
   /* Delete external address from FIB */
   pool_foreach (interface, sm->interfaces)
     {
-      if (nat_interface_is_inside (interface) || sm->out2in_dpo)
+      if (nat_interface_is_inside (interface))
        continue;
 
       snat_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
       break;
     }
-
   pool_foreach (interface, sm->output_feature_interfaces)
    {
-    if (nat_interface_is_inside(interface) || sm->out2in_dpo)
-      continue;
+     if (nat_interface_is_inside (interface))
+       continue;
 
-    snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
-    break;
+     snat_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
+     break;
   }
 
   return 0;
 }
 
-static void
-nat_validate_counters (snat_main_t * sm, u32 sw_if_index)
-{
-#define _(x)                                                                  \
-  vlib_validate_simple_counter (&sm->counters.fastpath.in2out.x,              \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.fastpath.in2out.x, sw_if_index);    \
-  vlib_validate_simple_counter (&sm->counters.fastpath.out2in.x,              \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.fastpath.out2in.x, sw_if_index);    \
-  vlib_validate_simple_counter (&sm->counters.slowpath.in2out.x,              \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.slowpath.in2out.x, sw_if_index);    \
-  vlib_validate_simple_counter (&sm->counters.slowpath.out2in.x,              \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.slowpath.out2in.x, sw_if_index);    \
-  vlib_validate_simple_counter (&sm->counters.fastpath.in2out_ed.x,           \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.fastpath.in2out_ed.x, sw_if_index); \
-  vlib_validate_simple_counter (&sm->counters.fastpath.out2in_ed.x,           \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.fastpath.out2in_ed.x, sw_if_index); \
-  vlib_validate_simple_counter (&sm->counters.slowpath.in2out_ed.x,           \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.slowpath.in2out_ed.x, sw_if_index); \
-  vlib_validate_simple_counter (&sm->counters.slowpath.out2in_ed.x,           \
-                                sw_if_index);                                 \
-  vlib_zero_simple_counter (&sm->counters.slowpath.out2in_ed.x, sw_if_index);
-  foreach_nat_counter;
-#undef _
-  vlib_validate_simple_counter (&sm->counters.hairpinning, sw_if_index);
-  vlib_zero_simple_counter (&sm->counters.hairpinning, sw_if_index);
-}
-
 void
 expire_per_vrf_sessions (u32 fib_index)
 {
@@ -1806,12 +1447,6 @@ snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
       return VNET_API_ERROR_UNSUPPORTED;
     }
 
-  if (sm->out2in_dpo && !is_inside)
-    {
-      nat_log_err ("error unsupported");
-      return VNET_API_ERROR_UNSUPPORTED;
-    }
-
   /* *INDENT-OFF* */
   pool_foreach (i, sm->output_feature_interfaces)
    {
@@ -1831,12 +1466,8 @@ snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
        feature_name =
          is_inside ? "nat44-in2out-worker-handoff" :
          "nat44-out2in-worker-handoff";
-      else if (sm->endpoint_dependent)
-       {
-         feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
-       }
       else
-       feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
+       feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
     }
 
   ASSERT (sm->frame_queue_nelts > 0);
@@ -1849,8 +1480,7 @@ snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
                                                      sm->frame_queue_nelts);
 
-  if (sm->endpoint_dependent)
-    update_per_vrf_sessions_vec (fib_index, is_del);
+  update_per_vrf_sessions_vec (fib_index, is_del);
 
   if (!is_inside)
     {
@@ -1900,17 +1530,12 @@ feature_set:
                     feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
                                                  "nat44-out2in-worker-handoff";
                   }
-                else if (sm->endpoint_dependent)
-                  {
-                    del_feature_name = "nat44-ed-classify";
-                    feature_name = !is_inside ?  "nat-pre-in2out" :
-                                                 "nat-pre-out2in";
-                  }
-                else
-                  {
-                    del_feature_name = "nat44-classify";
-                    feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
-                  }
+               else
+                 {
+                   del_feature_name = "nat44-ed-classify";
+                   feature_name =
+                     !is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
+                 }
 
                int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
                if (rv)
@@ -1919,13 +1544,6 @@ feature_set:
                                              sw_if_index, 0, 0, 0);
                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
                                              sw_if_index, 1, 0, 0);
-                if (!is_inside)
-                  {
-                   if (!sm->endpoint_dependent)
-                     vnet_feature_enable_disable ("ip4-local",
-                                                  "nat44-hairpinning",
-                                                  sw_if_index, 1, 0, 0);
-                 }
              }
            else
              {
@@ -1935,13 +1553,6 @@ feature_set:
                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
                                              sw_if_index, 0, 0, 0);
                 pool_put (sm->interfaces, i);
-                if (is_inside)
-                  {
-                   if (!sm->endpoint_dependent)
-                     vnet_feature_enable_disable ("ip4-local",
-                                                  "nat44-hairpinning",
-                                                  sw_if_index, 0, 0, 0);
-                 }
              }
          }
        else
@@ -1956,19 +1567,13 @@ feature_set:
                                                "nat44-out2in-worker-handoff";
                feature_name = "nat44-handoff-classify";
              }
-           else if (sm->endpoint_dependent)
+           else
              {
                del_feature_name =
                  !is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
 
                feature_name = "nat44-ed-classify";
              }
-           else
-             {
-               del_feature_name =
-                 !is_inside ? "nat44-in2out" : "nat44-out2in";
-               feature_name = "nat44-classify";
-             }
 
            int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
            if (rv)
@@ -1977,12 +1582,6 @@ feature_set:
                                          sw_if_index, 0, 0, 0);
             vnet_feature_enable_disable ("ip4-unicast", feature_name,
                                          sw_if_index, 1, 0, 0);
-            if (!is_inside)
-              {
-               if (!sm->endpoint_dependent)
-                 vnet_feature_enable_disable (
-                   "ip4-local", "nat44-hairpinning", sw_if_index, 0, 0, 0);
-             }
            goto set_flags;
          }
 
@@ -2000,7 +1599,7 @@ feature_set:
   pool_get (sm->interfaces, i);
   i->sw_if_index = sw_if_index;
   i->flags = 0;
-  nat_validate_counters (sm, sw_if_index);
+  nat_validate_interface_counters (sm, sw_if_index);
 
   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
                               0);
@@ -2009,13 +1608,6 @@ feature_set:
   if (rv)
     return rv;
 
-  if (is_inside && !sm->out2in_dpo)
-    {
-      if (!sm->endpoint_dependent)
-       vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
-                                    sw_if_index, 1, 0, 0);
-    }
-
 set_flags:
   if (is_inside)
     {
@@ -2078,8 +1670,7 @@ snat_interface_add_del_output_feature (u32 sw_if_index,
   }
   /* *INDENT-ON* */
 
-  if (sm->endpoint_dependent)
-    update_per_vrf_sessions_vec (fib_index, is_del);
+  update_per_vrf_sessions_vec (fib_index, is_del);
 
   if (!is_inside)
     {
@@ -2111,20 +1702,6 @@ snat_interface_add_del_output_feature (u32 sw_if_index,
 feature_set:
   if (is_inside)
     {
-      if (sm->endpoint_dependent)
-       {
-         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);
-         if (rv)
-           return rv;
-       }
-      else
-       {
          int rv =
            ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
          if (rv)
@@ -2134,11 +1711,6 @@ feature_set:
                                                            !is_del);
          if (rv)
            return rv;
-         vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
-                                      sw_if_index, !is_del, 0, 0);
-         vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
-                                      sw_if_index, !is_del, 0, 0);
-       }
       goto fq;
     }
 
@@ -2160,8 +1732,6 @@ feature_set:
     }
   else
     {
-      if (sm->endpoint_dependent)
-       {
          int rv =
            ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
          if (rv)
@@ -2175,23 +1745,6 @@ feature_set:
                                       sw_if_index, !is_del, 0, 0);
          vnet_feature_enable_disable ("ip4-output", "nat-pre-in2out-output",
                                       sw_if_index, !is_del, 0, 0);
-       }
-      else
-       {
-         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);
-         if (rv)
-           return rv;
-         vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
-                                      sw_if_index, !is_del, 0, 0);
-         vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
-                                      sw_if_index, !is_del, 0, 0);
-       }
     }
 
 fq:
@@ -2227,7 +1780,7 @@ fq:
   pool_get (sm->output_feature_interfaces, i);
   i->sw_if_index = sw_if_index;
   i->flags = 0;
-  nat_validate_counters (sm, sw_if_index);
+  nat_validate_interface_counters (sm, sw_if_index);
   if (is_inside)
     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
   else
@@ -2283,7 +1836,7 @@ snat_set_workers (uword * bitmap)
 }
 
 int
-snat_set_frame_queue_nelts (u32 frame_queue_nelts)
+nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts)
 {
   fail_if_enabled ();
   snat_main_t *sm = &snat_main;
@@ -2438,11 +1991,8 @@ test_key_calc_split ()
 static clib_error_t *
 nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add)
 {
-  snat_main_t *sm = &snat_main;
   u32 fib_index;
 
-  if (sm->endpoint_dependent)
-    {
       // TODO: consider removing all NAT interfaces
       if (!is_add)
        {
@@ -2450,7 +2000,6 @@ nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add)
          if (fib_index != ~0)
            expire_per_vrf_sessions (fib_index);
        }
-    }
   return 0;
 }
 
@@ -2461,65 +2010,45 @@ nat44_set_node_indexes (snat_main_t * sm, vlib_main_t * vm)
 {
   vlib_node_t *node;
 
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
-  sm->ei_out2in_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
-  sm->ei_in2out_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
-  sm->ei_in2out_output_node_index = node->index;
-
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
-  sm->ed_out2in_node_index = node->index;
+  sm->in2out_node_index = node->index;
+
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
-  sm->ed_in2out_node_index = node->index;
+  sm->out2in_node_index = node->index;
+
   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output");
-  sm->ed_in2out_output_node_index = node->index;
-
-  node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
-  sm->error_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
-  sm->pre_in2out_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
-  sm->pre_out2in_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
-  sm->pre_in2out_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
-  sm->pre_out2in_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
-  sm->in2out_fast_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
-  sm->in2out_slowpath_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
-  sm->in2out_slowpath_output_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
-  sm->ed_in2out_slowpath_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
-  sm->out2in_fast_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
-  sm->ed_out2in_slowpath_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
-  sm->hairpinning_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
-  sm->hairpin_dst_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
-  sm->hairpin_src_node_index = node->index;
+  sm->in2out_output_node_index = node->index;
 }
 
-#define nat_init_simple_counter(c, n, sn) \
-do                                        \
-  {                                       \
-    c.name = n;                           \
-    c.stat_segment_name = sn;             \
-    vlib_validate_simple_counter (&c, 0); \
-    vlib_zero_simple_counter (&c, 0);     \
-  } while (0);
-
-extern vlib_node_registration_t nat44_hairpinning_node;
-extern vlib_node_registration_t snat_hairpin_dst_node;
-extern vlib_node_registration_t
-  nat44_in2out_hairpinning_finish_ip4_lookup_node;
-extern vlib_node_registration_t
-  nat44_in2out_hairpinning_finish_interface_output_node;
+#define nat_validate_simple_counter(c, i)                                     \
+  do                                                                          \
+    {                                                                         \
+      vlib_validate_simple_counter (&c, i);                                   \
+      vlib_zero_simple_counter (&c, i);                                       \
+    }                                                                         \
+  while (0);
+
+#define nat_init_simple_counter(c, n, sn)                                     \
+  do                                                                          \
+    {                                                                         \
+      c.name = n;                                                             \
+      c.stat_segment_name = sn;                                               \
+      nat_validate_simple_counter (c, 0);                                     \
+    }                                                                         \
+  while (0);
+
+static_always_inline void
+nat_validate_interface_counters (snat_main_t *sm, u32 sw_if_index)
+{
+#define _(x)                                                                  \
+  nat_validate_simple_counter (sm->counters.fastpath.in2out.x, sw_if_index);  \
+  nat_validate_simple_counter (sm->counters.fastpath.out2in.x, sw_if_index);  \
+  nat_validate_simple_counter (sm->counters.slowpath.in2out.x, sw_if_index);  \
+  nat_validate_simple_counter (sm->counters.slowpath.out2in.x, sw_if_index);
+  foreach_nat_counter;
+#undef _
+  nat_validate_simple_counter (sm->counters.hairpinning, sw_if_index);
+}
 
 static clib_error_t *
 nat_init (vlib_main_t * vm)
@@ -2546,48 +2075,28 @@ nat_init (vlib_main_t * vm)
   sm->fq_in2out_index = ~0;
   sm->fq_in2out_output_index = ~0;
 
-  sm->log_level = SNAT_LOG_ERROR;
+  sm->log_level = NAT_LOG_ERROR;
 
   nat44_set_node_indexes (sm, vm);
   sm->log_class = vlib_log_register_class ("nat", 0);
   nat_ipfix_logging_init (vm);
 
-  nat_init_simple_counter (sm->total_users, "total-users",
-                          "/nat44/total-users");
   nat_init_simple_counter (sm->total_sessions, "total-sessions",
-                          "/nat44/total-sessions");
-  nat_init_simple_counter (sm->user_limit_reached, "user-limit-reached",
-                          "/nat44/user-limit-reached");
-
-#define _(x)                                            \
-  sm->counters.fastpath.in2out.x.name = #x;             \
-  sm->counters.fastpath.in2out.x.stat_segment_name =    \
-      "/nat44/in2out/fastpath/" #x;                     \
-  sm->counters.slowpath.in2out.x.name = #x;             \
-  sm->counters.slowpath.in2out.x.stat_segment_name =    \
-      "/nat44/in2out/slowpath/" #x;                     \
-  sm->counters.fastpath.out2in.x.name = #x;             \
-  sm->counters.fastpath.out2in.x.stat_segment_name =    \
-      "/nat44/out2in/fastpath/" #x;                     \
-  sm->counters.slowpath.out2in.x.name = #x;             \
-  sm->counters.slowpath.out2in.x.stat_segment_name =    \
-      "/nat44/out2in/slowpath/" #x;                     \
-  sm->counters.fastpath.in2out_ed.x.name = #x;          \
-  sm->counters.fastpath.in2out_ed.x.stat_segment_name = \
-      "/nat44/ed/in2out/fastpath/" #x;                  \
-  sm->counters.slowpath.in2out_ed.x.name = #x;          \
-  sm->counters.slowpath.in2out_ed.x.stat_segment_name = \
-      "/nat44/ed/in2out/slowpath/" #x;                  \
-  sm->counters.fastpath.out2in_ed.x.name = #x;          \
-  sm->counters.fastpath.out2in_ed.x.stat_segment_name = \
-      "/nat44/ed/out2in/fastpath/" #x;                  \
-  sm->counters.slowpath.out2in_ed.x.name = #x;          \
-  sm->counters.slowpath.out2in_ed.x.stat_segment_name = \
-      "/nat44/ed/out2in/slowpath/" #x;
+                          "/nat44-ed/total-sessions");
+
+#define _(x)                                                                  \
+  nat_init_simple_counter (sm->counters.fastpath.in2out.x, #x,                \
+                          "/nat44-ed/in2out/fastpath/" #x);                  \
+  nat_init_simple_counter (sm->counters.fastpath.out2in.x, #x,                \
+                          "/nat44-ed/out2in/fastpath/" #x);                  \
+  nat_init_simple_counter (sm->counters.slowpath.in2out.x, #x,                \
+                          "/nat44-ed/in2out/slowpath/" #x);                  \
+  nat_init_simple_counter (sm->counters.slowpath.out2in.x, #x,                \
+                          "/nat44-ed/out2in/slowpath/" #x);
   foreach_nat_counter;
 #undef _
-  sm->counters.hairpinning.name = "hairpinning";
-  sm->counters.hairpinning.stat_segment_name = "/nat44/hairpinning";
+  nat_init_simple_counter (sm->counters.hairpinning, "hairpinning",
+                          "/nat44-ed/hairpinning");
 
   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
   if (p)
@@ -2632,34 +2141,27 @@ nat_init (vlib_main_t * vm)
     fib_source_allocate ("nat-hi", FIB_SOURCE_PRIORITY_HI,
                         FIB_SOURCE_BH_SIMPLE);
 
-  /* used only by out2in-dpo feature */
-  nat_dpo_module_init ();
-
   nat_affinity_init (vm);
-  nat_ha_init (vm, sm->num_workers, num_threads);
-
   test_key_calc_split ();
 
-  sm->nat44_hairpinning_fq_index =
-    vlib_frame_queue_main_init (nat44_hairpinning_node.index, 0);
-  sm->snat_hairpin_dst_fq_index =
-    vlib_frame_queue_main_init (snat_hairpin_dst_node.index, 0);
-  sm->nat44_in2out_hairpinning_finish_ip4_lookup_node_fq_index =
-    vlib_frame_queue_main_init (
-      nat44_in2out_hairpinning_finish_ip4_lookup_node.index, 0);
-  sm->nat44_in2out_hairpinning_finish_interface_output_node_fq_index =
-    vlib_frame_queue_main_init (
-      nat44_in2out_hairpinning_finish_interface_output_node.index, 0);
   return nat44_api_hookup (vm);
 }
 
 VLIB_INIT_FUNCTION (nat_init);
 
-static int
-nat44_ed_plugin_enable (nat44_config_t c)
+int
+nat44_plugin_enable (nat44_config_t c)
 {
   snat_main_t *sm = &snat_main;
 
+  fail_if_enabled ();
+
+  // UPDATE based on these appropriate API/CLI
+  // c.static_mapping_only + c.connection_tracking
+  //  - supported in NAT EI & NAT ED
+  // c.out2in_dpo, c.static_mapping_only
+  //  - supported in NAT EI
+
   if (c.static_mapping_only && !c.connection_tracking)
     {
       nat_log_err ("unsupported combination of configuration");
@@ -2667,25 +2169,14 @@ nat44_ed_plugin_enable (nat44_config_t c)
     }
 
   // nat44 feature configuration
-  sm->endpoint_dependent = c.endpoint_dependent;
   sm->static_mapping_only = c.static_mapping_only;
   sm->static_mapping_connection_tracking = c.connection_tracking;
 
-  // EI only feature (could break ED)
-  sm->out2in_dpo = c.out2in_dpo;
-
   sm->forwarding_enabled = 0;
   sm->mss_clamping = 0;
   sm->pat = (!c.static_mapping_only ||
             (c.static_mapping_only && c.connection_tracking));
 
-  if (!c.users)
-    c.users = 1024;
-
-  // EI only feature (could break ED)
-  sm->max_users_per_thread = c.users;
-  sm->user_buckets = nat_calc_bihash_buckets (c.users);
-
   if (!c.sessions)
     c.sessions = 63 * 1024;
 
@@ -2695,10 +2186,6 @@ nat44_ed_plugin_enable (nat44_config_t c)
   // ED only feature
   vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
 
-  // EI only feature (could break ED)
-  sm->max_translations_per_user
-    = c.user_sessions ? c.user_sessions : sm->max_translations_per_thread;
-
   sm->inside_vrf_id = c.inside_vrf;
   sm->inside_fib_index =
     fib_table_find_or_create_and_lock
@@ -2711,33 +2198,13 @@ nat44_ed_plugin_enable (nat44_config_t c)
   sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
   sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
 
-  sm->in2out_node_index = sm->ed_in2out_node_index;
-  sm->out2in_node_index = sm->ed_out2in_node_index;
-
-  sm->in2out_output_node_index = sm->ed_in2out_output_node_index;
-
-  if (sm->pat)
-    {
-      sm->icmp_match_in2out_cb = NULL;
-      sm->icmp_match_out2in_cb = NULL;
-    }
-  else
-    {
-      sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
-      sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
-    }
-
-  nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets,
-                   sm->user_buckets);
+  nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets);
 
   nat_affinity_enable ();
 
   nat_reset_timeouts (&sm->timeouts);
 
-  // TODO: function for reset counters
-  vlib_zero_simple_counter (&sm->total_users, 0);
   vlib_zero_simple_counter (&sm->total_sessions, 0);
-  vlib_zero_simple_counter (&sm->user_limit_reached, 0);
 
   if (!sm->frame_queue_nelts)
     sm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
@@ -2748,48 +2215,10 @@ nat44_ed_plugin_enable (nat44_config_t c)
   return 0;
 }
 
-int
-nat44_plugin_enable (nat44_config_t c)
-{
-  fail_if_enabled ();
-
-  // c.static_mapping_only + c.connection_tracking
-  //  - supported in NAT EI & NAT ED
-  // c.out2in_dpo, c.static_mapping_only
-  //  - supported in NAT EI
-
-  if (c.endpoint_dependent)
-    {
-      if (c.out2in_dpo || c.users || c.user_sessions)
-       {
-         nat_log_err ("unsupported combination of configuration");
-         return 1;
-       }
-      return nat44_ed_plugin_enable (c);
-    }
-
-  // separation:
-  // for now just copy variables
-
-  nat44_ei_config_t ei_c = {
-    .inside_vrf = c.inside_vrf,
-    .outside_vrf = c.outside_vrf,
-    .users = c.users,
-    .sessions = c.sessions,
-    .user_sessions = c.user_sessions,
-    .out2in_dpo = c.out2in_dpo,
-    .static_mapping_only = c.static_mapping_only,
-    .connection_tracking = c.connection_tracking,
-  };
-
-  return nat44_ei_plugin_enable (ei_c);
-}
-
 void
 nat44_addresses_free (snat_address_t ** addresses)
 {
   snat_address_t *ap;
-  /* *INDENT-OFF* */
   vec_foreach (ap, *addresses)
     {
     #define _(N, i, n, s) \
@@ -2797,21 +2226,21 @@ nat44_addresses_free (snat_address_t ** addresses)
       foreach_nat_protocol
     #undef _
     }
-  /* *INDENT-ON* */
   vec_free (*addresses);
   *addresses = 0;
 }
 
-static int
-nat44_ed_plugin_disable ()
+int
+nat44_plugin_disable ()
 {
   snat_main_t *sm = &snat_main;
   snat_interface_t *i, *vec;
   int error = 0;
 
+  fail_if_disabled ();
+
   // first unregister all nodes from interfaces
   vec = vec_dup (sm->interfaces);
-  /* *INDENT-OFF* */
   vec_foreach (i, vec)
     {
       if (nat_interface_is_inside(i))
@@ -2825,12 +2254,10 @@ nat44_ed_plugin_disable ()
                        i->sw_if_index);
         }
     }
-  /* *INDENT-ON* */
   vec_free (vec);
   sm->interfaces = 0;
 
   vec = vec_dup (sm->output_feature_interfaces);
-  /* *INDENT-OFF* */
   vec_foreach (i, vec)
     {
       if (nat_interface_is_inside(i))
@@ -2844,7 +2271,6 @@ nat44_ed_plugin_disable ()
                        i->sw_if_index);
         }
     }
-  /* *INDENT-ON* */
   vec_free (vec);
   sm->output_feature_interfaces = 0;
 
@@ -2855,7 +2281,6 @@ nat44_ed_plugin_disable ()
   nat44_addresses_free (&sm->addresses);
   nat44_addresses_free (&sm->twice_nat_addresses);
 
-
   vec_free (sm->to_resolve);
   vec_free (sm->auto_add_sw_if_indices);
   vec_free (sm->auto_add_sw_if_indices_twice_nat);
@@ -2872,16 +2297,38 @@ nat44_ed_plugin_disable ()
   return 0;
 }
 
-int
-nat44_plugin_disable ()
+void
+nat44_ed_forwarding_enable_disable (u8 is_enable)
 {
+  snat_main_per_thread_data_t *tsm;
   snat_main_t *sm = &snat_main;
+  snat_session_t *s;
 
-  fail_if_disabled ();
+  u32 *ses_to_be_removed = 0, *ses_index;
+
+  sm->forwarding_enabled = is_enable != 0;
+
+  if (is_enable)
+    return;
+
+  vec_foreach (tsm, sm->per_thread_data)
+    {
+      pool_foreach (s, tsm->sessions)
+       {
+         if (is_fwd_bypass_session (s))
+           {
+             vec_add1 (ses_to_be_removed, s - tsm->sessions);
+           }
+       }
+      vec_foreach (ses_index, ses_to_be_removed)
+       {
+         s = pool_elt_at_index (tsm->sessions, ses_index[0]);
+         nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
+         nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
+       }
 
-  if (sm->endpoint_dependent)
-    return nat44_ed_plugin_disable ();
-  return nat44_ei_plugin_disable ();
+      vec_free (ses_to_be_removed);
+    }
 }
 
 void
@@ -2889,6 +2336,7 @@ snat_free_outside_address_and_port (snat_address_t *addresses,
                                    u32 thread_index, ip4_address_t *addr,
                                    u16 port, nat_protocol_t protocol)
 {
+  snat_main_t *sm = &snat_main;
   snat_address_t *a;
   u32 address_index;
   u16 port_host_byte_order = clib_net_to_host_u16 (port);
@@ -2915,8 +2363,7 @@ snat_free_outside_address_and_port (snat_address_t *addresses,
       break;
       foreach_nat_protocol
 #undef _
-    default:
-      nat_elog_info ("unknown protocol");
+       default : nat_elog_info (sm, "unknown protocol");
       return;
     }
 }
@@ -2926,6 +2373,7 @@ nat_set_outside_address_and_port (snat_address_t *addresses, u32 thread_index,
                                  ip4_address_t addr, u16 port,
                                  nat_protocol_t protocol)
 {
+  snat_main_t *sm = &snat_main;
   snat_address_t *a = 0;
   u32 address_index;
   u16 port_host_byte_order = clib_net_to_host_u16 (port);
@@ -2949,8 +2397,7 @@ nat_set_outside_address_and_port (snat_address_t *addresses, u32 thread_index,
           return 0;
          foreach_nat_protocol
 #undef _
-       default:
-         nat_elog_info ("unknown protocol");
+           default : nat_elog_info (sm, "unknown protocol");
          return 1;
        }
     }
@@ -3030,7 +2477,6 @@ snat_static_mapping_match (snat_main_t * sm,
          if (PREDICT_FALSE (sm->num_workers > 1))
            {
              u32 thread_index = vlib_get_thread_index ();
-              /* *INDENT-OFF* */
               pool_foreach_index (i, m->locals)
                {
                 local = pool_elt_at_index (m->locals, i);
@@ -3045,17 +2491,14 @@ snat_static_mapping_match (snat_main_t * sm,
                     vec_add1 (tmp, i);
                   }
               }
-              /* *INDENT-ON* */
              ASSERT (vec_len (tmp) != 0);
            }
          else
            {
-              /* *INDENT-OFF* */
               pool_foreach_index (i, m->locals)
                {
                 vec_add1 (tmp, i);
               }
-              /* *INDENT-ON* */
            }
          hi = vec_len (tmp) - 1;
          local = pool_elt_at_index (m->locals, tmp[hi]);
@@ -3078,7 +2521,7 @@ snat_static_mapping_match (snat_main_t * sm,
                                                match_protocol, match_port,
                                                tmp[lo], m->affinity,
                                                m->affinity_per_service_list_head_index))
-               nat_elog_info ("create affinity record failed");
+               nat_elog_info (sm, "create affinity record failed");
            }
          vec_free (tmp);
        }
@@ -3118,30 +2561,6 @@ end:
   return 0;
 }
 
-void
-nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
-{
-  snat_main_t *sm = &snat_main;
-  dpo_id_t dpo_v4 = DPO_INVALID;
-  fib_prefix_t pfx = {
-    .fp_proto = FIB_PROTOCOL_IP4,
-    .fp_len = 32,
-    .fp_addr.ip4.as_u32 = addr.as_u32,
-  };
-
-  if (is_add)
-    {
-      nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
-      fib_table_entry_special_dpo_add (0, &pfx, sm->fib_src_hi,
-                                      FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
-      dpo_reset (&dpo_v4);
-    }
-  else
-    {
-      fib_table_entry_special_remove (0, &pfx, sm->fib_src_hi);
-    }
-}
-
 static u32
 nat44_ed_get_worker_in2out_cb (ip4_header_t *ip, u32 rx_fib_index,
                               u8 is_output)
@@ -3207,12 +2626,10 @@ nat44_ed_get_worker_in2out_cb (ip4_header_t *ip, u32 rx_fib_index,
                              ed_value_get_thread_index (&value16));
          next_worker_index += tsm->thread_index;
 
-         nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
-                                 next_worker_index, fib_index,
-                                 clib_net_to_host_u32 (ip->
-                                                       src_address.as_u32),
-                                 clib_net_to_host_u32 (ip->
-                                                       dst_address.as_u32));
+         nat_elog_debug_handoff (
+           sm, "HANDOFF IN2OUT-OUTPUT-FEATURE (session)", next_worker_index,
+           fib_index, clib_net_to_host_u32 (ip->src_address.as_u32),
+           clib_net_to_host_u32 (ip->dst_address.as_u32));
 
          return next_worker_index;
        }
@@ -3228,14 +2645,14 @@ nat44_ed_get_worker_in2out_cb (ip4_header_t *ip, u32 rx_fib_index,
 
   if (PREDICT_TRUE (!is_output))
     {
-      nat_elog_debug_handoff ("HANDOFF IN2OUT",
-                             next_worker_index, rx_fib_index,
+      nat_elog_debug_handoff (sm, "HANDOFF IN2OUT", next_worker_index,
+                             rx_fib_index,
                              clib_net_to_host_u32 (ip->src_address.as_u32),
                              clib_net_to_host_u32 (ip->dst_address.as_u32));
     }
   else
     {
-      nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
+      nat_elog_debug_handoff (sm, "HANDOFF IN2OUT-OUTPUT-FEATURE",
                              next_worker_index, rx_fib_index,
                              clib_net_to_host_u32 (ip->src_address.as_u32),
                              clib_net_to_host_u32 (ip->dst_address.as_u32));
@@ -3277,12 +2694,10 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
          vnet_buffer2 (b)->nat.cached_session_index =
            ed_value_get_session_index (&value16);
          next_worker_index = sm->first_worker_index + tsm->thread_index;
-         nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
-                                 next_worker_index, rx_fib_index,
-                                 clib_net_to_host_u32 (ip->
-                                                       src_address.as_u32),
-                                 clib_net_to_host_u32 (ip->
-                                                       dst_address.as_u32));
+         nat_elog_debug_handoff (
+           sm, "HANDOFF OUT2IN (session)", next_worker_index, rx_fib_index,
+           clib_net_to_host_u32 (ip->src_address.as_u32),
+           clib_net_to_host_u32 (ip->dst_address.as_u32));
          return next_worker_index;
        }
     }
@@ -3304,12 +2719,10 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
                vec_elt_at_index (sm->per_thread_data,
                                  ed_value_get_thread_index (&value16));
              next_worker_index = sm->first_worker_index + tsm->thread_index;
-             nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
-                                     next_worker_index, rx_fib_index,
-                                     clib_net_to_host_u32 (ip->
-                                                           src_address.as_u32),
-                                     clib_net_to_host_u32 (ip->
-                                                           dst_address.as_u32));
+             nat_elog_debug_handoff (
+               sm, "HANDOFF OUT2IN (session)", next_worker_index,
+               rx_fib_index, clib_net_to_host_u32 (ip->src_address.as_u32),
+               clib_net_to_host_u32 (ip->dst_address.as_u32));
              return next_worker_index;
            }
        }
@@ -3402,32 +2815,13 @@ nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
 
 done:
-  nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
+  nat_elog_debug_handoff (sm, "HANDOFF OUT2IN", next_worker_index,
+                         rx_fib_index,
                          clib_net_to_host_u32 (ip->src_address.as_u32),
                          clib_net_to_host_u32 (ip->dst_address.as_u32));
   return next_worker_index;
 }
 
-u32
-nat_calc_bihash_buckets (u32 n_elts)
-{
-  n_elts = n_elts / 2.5;
-  u64 lower_pow2 = 1;
-  while (lower_pow2 * 2 < n_elts)
-    {
-      lower_pow2 = 2 * lower_pow2;
-    }
-  u64 upper_pow2 = 2 * lower_pow2;
-  if ((upper_pow2 - n_elts) < (n_elts - lower_pow2))
-    {
-      if (upper_pow2 <= UINT32_MAX)
-       {
-         return upper_pow2;
-       }
-    }
-  return lower_pow2;
-}
-
 u32
 nat44_get_max_session_limit ()
 {
@@ -3473,13 +2867,13 @@ nat44_update_session_limit (u32 session_limit, u32 vrf_id)
   sm->translation_buckets =
     nat_calc_bihash_buckets (sm->max_translations_per_thread);
 
-  nat44_sessions_clear ();
+  nat44_ed_sessions_clear ();
   return 0;
 }
 
 static void
 nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
-                        u32 translation_buckets, u32 user_buckets)
+                        u32 translation_buckets)
 {
   dlist_elt_t *head;
 
@@ -3505,12 +2899,6 @@ nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
   pool_get (tsm->lru_pool, head);
   tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
   clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
-
-  // TODO: ED nat is not using these
-  // before removal large refactor required
-  pool_alloc (tsm->list_pool, translations);
-  clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, 0);
-  clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
 }
 
 static void
@@ -3525,7 +2913,7 @@ reinit_ed_flow_hash ()
 }
 
 static void
-nat44_ed_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
+nat44_ed_db_init (u32 translations, u32 translation_buckets)
 {
   snat_main_t *sm = &snat_main;
   snat_main_per_thread_data_t *tsm;
@@ -3551,7 +2939,7 @@ nat44_ed_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
       vec_foreach (tsm, sm->per_thread_data)
        {
          nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread,
-                                  sm->translation_buckets, sm->user_buckets);
+                                  sm->translation_buckets);
        }
     }
 }
@@ -3559,15 +2947,9 @@ nat44_ed_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
 static void
 nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm)
 {
-  pool_free (tsm->sessions);
   pool_free (tsm->lru_pool);
-
+  pool_free (tsm->sessions);
   vec_free (tsm->per_vrf_sessions_vec);
-
-  // TODO: resolve static mappings (put only to !ED)
-  pool_free (tsm->list_pool);
-  pool_free (tsm->users);
-  clib_bihash_free_8_8 (&tsm->user_hash);
 }
 
 static void
@@ -3605,25 +2987,10 @@ nat44_ed_sessions_clear ()
 
          nat44_ed_worker_db_free (tsm);
          nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread,
-                                  sm->translation_buckets, sm->user_buckets);
+                                  sm->translation_buckets);
        }
     }
-
-  // TODO: function for reset counters
-  vlib_zero_simple_counter (&sm->total_users, 0);
   vlib_zero_simple_counter (&sm->total_sessions, 0);
-  vlib_zero_simple_counter (&sm->user_limit_reached, 0);
-}
-
-void
-nat44_sessions_clear ()
-{
-  snat_main_t *sm = &snat_main;
-
-  if (sm->endpoint_dependent)
-    nat44_ed_sessions_clear ();
-  else
-    nat44_ei_sessions_clear ();
 }
 
 static void
@@ -3691,7 +3058,7 @@ match:
                                rp->out2in_only, rp->tag, rp->identity_nat,
                                rp->pool_addr, rp->exact);
   if (rv)
-    nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
+    nat_elog_notice_X1 (sm, "snat_add_static_mapping returned %d", "i4", rv);
 }
 
 static void
@@ -3759,7 +3126,7 @@ match:
                rp->twice_nat, rp->out2in_only, rp->tag, rp->identity_nat,
                rp->pool_addr, rp->exact);
              if (rv)
-               nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
+               nat_elog_notice_X1 (sm, "snat_add_static_mapping returned %d",
                                    "i4", rv);
            }
        }
@@ -3851,9 +3218,6 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
   snat_session_t *s;
   snat_main_per_thread_data_t *tsm;
 
-  if (!sm->endpoint_dependent)
-    return VNET_API_ERROR_FEATURE_DISABLED;
-
   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
   if (sm->num_workers > 1)
     tsm =
similarity index 65%
rename from src/plugins/nat/nat.h
rename to src/plugins/nat/nat44-ed/nat44_ed.h
index c1dc31e..10d1207 100644 (file)
@@ -16,8 +16,8 @@
  * @file nat.c
  * NAT plugin global declarations
  */
-#ifndef __included_nat_h__
-#define __included_nat_h__
+#ifndef __included_nat44_ed_h__
+#define __included_nat44_ed_h__
 
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
@@ -31,8 +31,7 @@
 #include <vppinfra/dlist.h>
 #include <vppinfra/error.h>
 #include <vlibapi/api.h>
-#include <vlib/log.h>
-#include <vppinfra/bihash_16_8.h>
+
 #include <nat/lib/lib.h>
 #include <nat/lib/inlines.h>
 
@@ -62,20 +61,13 @@ typedef struct
   /* nat44 plugin features */
   u8 static_mapping_only;
   u8 connection_tracking;
-  u8 endpoint_dependent;
-  u8 out2in_dpo;
 
   u32 inside_vrf;
   u32 outside_vrf;
 
-  /* maximum number of users */
-  u32 users;
-
   /* maximum number of sessions */
   u32 sessions;
 
-  /* maximum number of ssessions per user */
-  u32 user_sessions;
 } nat44_config_t;
 
 typedef enum
@@ -99,20 +91,6 @@ typedef struct
   u32 arc_next_index;
 } nat_pre_trace_t;
 
-/* user (internal host) key */
-typedef struct
-{
-  union
-  {
-    struct
-    {
-      ip4_address_t addr;
-      u32 fib_index;
-    };
-    u64 as_u64;
-  };
-} snat_user_key_t;
-
 /* External address and port allocation modes */
 #define foreach_nat_addr_and_port_alloc_alg \
   _(0, DEFAULT, "default")         \
@@ -168,8 +146,6 @@ typedef enum
   _ (BAD_ICMP_TYPE, "unsupported ICMP type")                                  \
   _ (NO_TRANSLATION, "no translation")                                        \
   _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")                      \
-  _ (MAX_USER_SESS_EXCEEDED, "max user sessions exceeded")                    \
-  _ (CANNOT_CREATE_USER, "cannot create NAT user")                            \
   _ (NON_SYN, "non-SYN packet try to create session")                         \
   _ (TCP_CLOSED, "drops due to TCP in transitory timeout")                    \
   _ (HASH_ADD_FAILED, "hash table add failed")
@@ -252,6 +228,8 @@ typedef struct
   uword l4_csum_delta;
 } nat_6t_flow_t;
 
+void nat44_ed_forwarding_enable_disable (u8 is_enable);
+
 always_inline void
 nat_6t_flow_saddr_rewrite_set (nat_6t_flow_t *f, u32 saddr)
 {
@@ -321,10 +299,6 @@ typedef CLIB_PACKED(struct
   /* Flags */
   u32 flags;
 
-  /* Per-user translations */
-  u32 per_user_index;
-  u32 per_user_list_head_index;
-
   /* head of LRU list in which this session is tracked */
   u32 lru_head_index;
   /* index in global LRU list */
@@ -355,24 +329,12 @@ typedef CLIB_PACKED(struct
   u32 o2i_fin_seq;
   u64 tcp_closed_timestamp;
 
-  /* user index */
-  u32 user_index;
-
   /* per vrf sessions index */
   u32 per_vrf_sessions_index;
 
 }) snat_session_t;
 /* *INDENT-ON* */
 
-typedef struct
-{
-  ip4_address_t addr;
-  u32 fib_index;
-  u32 sessions_per_user_list_head_index;
-  u32 nsessions;
-  u32 nstaticsessions;
-} snat_user_t;
-
 typedef struct
 {
   ip4_address_t addr;
@@ -492,12 +454,6 @@ typedef struct
 
 typedef struct
 {
-  /* Find-a-user => src address lookup */
-  clib_bihash_8_8_t user_hash;
-
-  /* User pool */
-  snat_user_t *users;
-
   /* Session pool */
   snat_session_t *sessions;
 
@@ -524,13 +480,6 @@ typedef struct
 
 struct snat_main_s;
 
-/* ICMP session match function */
-typedef u32 (snat_icmp_match_function_t) (
-  struct snat_main_s *sm, vlib_node_runtime_t *node, u32 thread_index,
-  vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t *addr, u16 *port,
-  u32 *fib_index, nat_protocol_t *proto, snat_session_t **s_out,
-  u8 *dont_translate);
-
 /* Return worker thread index for given packet */
 typedef u32 (snat_get_worker_in2out_function_t) (ip4_header_t * ip,
                                                 u32 rx_fib_index,
@@ -552,14 +501,8 @@ typedef int (nat_alloc_out_addr_and_port_function_t) (snat_address_t *
                                                      u16 port_per_thread,
                                                      u32 snat_thread_index);
 
-#define foreach_nat_counter _ (tcp) _ (udp) _ (icmp) _ (other) _ (drops)
-
 typedef struct snat_main_s
 {
-  /* ICMP session match functions */
-  snat_icmp_match_function_t *icmp_match_in2out_cb;
-  snat_icmp_match_function_t *icmp_match_out2in_cb;
-
   /* Thread settings */
   u32 num_workers;
   u32 first_worker_index;
@@ -629,52 +572,16 @@ typedef struct snat_main_s
   u32 fq_in2out_output_index;
   u32 fq_out2in_index;
 
-  /* node indexes */
-  u32 error_node_index;
-
-  /* handoff fq nodes  */
-  u32 handoff_out2in_index;
-  u32 handoff_in2out_index;
-  u32 handoff_in2out_output_index;
-
-  /* respect feature arc nodes */
-  u32 pre_out2in_node_index;
-  u32 pre_in2out_node_index;
-
   u32 out2in_node_index;
   u32 in2out_node_index;
   u32 in2out_output_node_index;
 
-  u32 in2out_fast_node_index;
-  u32 in2out_slowpath_node_index;
-  u32 in2out_slowpath_output_node_index;
-  u32 out2in_fast_node_index;
-
-  u32 ei_out2in_node_index;
-  u32 ei_in2out_node_index;
-  u32 ei_in2out_output_node_index;
-
-  u32 ed_out2in_node_index;
-  u32 ed_in2out_node_index;
-  u32 ed_in2out_output_node_index;
-
-  u32 ed_in2out_slowpath_node_index;
-  u32 ed_out2in_slowpath_node_index;
-
-  u32 hairpinning_node_index;
-  u32 hairpin_dst_node_index;
-  u32 hairpin_src_node_index;
-
   nat44_config_t rconfig;
   //nat44_config_t cconfig;
 
   /* If forwarding is enabled */
   u8 forwarding_enabled;
 
-  /* Config parameters */
-  u8 endpoint_dependent;
-
-  u8 out2in_dpo;
   /* static mapping config */
   u8 static_mapping_only;
   u8 static_mapping_connection_tracking;
@@ -685,9 +592,6 @@ typedef struct snat_main_s
   u32 translation_buckets;
   u32 max_translations_per_thread;
   u32 *max_translations_per_fib;
-  u32 max_users_per_thread;
-  u32 user_buckets;
-  u32 max_translations_per_user;
 
   u32 outside_vrf_id;
   u32 outside_fib_index;
@@ -700,9 +604,7 @@ typedef struct snat_main_s
   u16 mss_clamping;
 
   /* counters */
-  vlib_simple_counter_main_t total_users;
   vlib_simple_counter_main_t total_sessions;
-  vlib_simple_counter_main_t user_limit_reached;
 
 #define _(x) vlib_simple_counter_main_t x;
   struct
@@ -718,16 +620,6 @@ typedef struct snat_main_s
       {
        foreach_nat_counter;
       } out2in;
-
-      struct
-      {
-       foreach_nat_counter;
-      } in2out_ed;
-
-      struct
-      {
-       foreach_nat_counter;
-      } out2in_ed;
     } fastpath;
 
     struct
@@ -741,16 +633,6 @@ typedef struct snat_main_s
       {
        foreach_nat_counter;
       } out2in;
-
-      struct
-      {
-       foreach_nat_counter;
-      } in2out_ed;
-
-      struct
-      {
-       foreach_nat_counter;
-      } out2in_ed;
     } slowpath;
 
     vlib_simple_counter_main_t hairpinning;
@@ -784,10 +666,6 @@ typedef struct snat_main_s
 
   vnet_main_t *vnet_main;
 
-  u32 nat44_in2out_hairpinning_finish_ip4_lookup_node_fq_index;
-  u32 nat44_in2out_hairpinning_finish_interface_output_node_fq_index;
-  u32 nat44_hairpinning_fq_index;
-  u32 snat_hairpin_dst_fq_index;
 } snat_main_t;
 
 typedef struct
@@ -823,7 +701,6 @@ extern fib_source_t nat_fib_src_hi;
 extern fib_source_t nat_fib_src_low;
 
 /* format functions */
-format_function_t format_snat_user;
 format_function_t format_snat_static_mapping;
 format_function_t format_snat_static_map_to_resolve;
 format_function_t format_snat_session;
@@ -952,225 +829,6 @@ tcp_flags_is_init (u8 f)
 #define nat_log_debug(...)\
   vlib_log(VLIB_LOG_LEVEL_DEBUG, snat_main.log_class, __VA_ARGS__)
 
-/* NAT API Logging Levels */
-#define foreach_nat_log_level \
-  _(0x00, LOG_NONE)           \
-  _(0x01, LOG_ERROR)          \
-  _(0x02, LOG_WARNING)        \
-  _(0x03, LOG_NOTICE)         \
-  _(0x04, LOG_INFO)           \
-  _(0x05, LOG_DEBUG)
-
-typedef enum nat_log_level_t_
-{
-#define _(n,f) SNAT_##f = n,
-  foreach_nat_log_level
-#undef _
-} nat_log_level_t;
-
-#define nat_elog(_level, _str)                           \
-do                                                       \
-  {                                                      \
-    snat_main_t *sm = &snat_main;                        \
-    if (PREDICT_FALSE (sm->log_level >= _level))         \
-      {                                                  \
-        ELOG_TYPE_DECLARE (e) =                          \
-          {                                              \
-            .format = "nat-msg " _str,                   \
-            .format_args = "",                           \
-          };                                             \
-        ELOG_DATA (&vlib_global_main.elog_main, e);      \
-      }                                                  \
-  } while (0);
-
-#define nat_elog_addr(_level, _str, _addr)               \
-do                                                       \
-  {                                                      \
-    if (PREDICT_FALSE (sm->log_level >= _level))         \
-      {                                                  \
-        ELOG_TYPE_DECLARE (e) =                          \
-          {                                              \
-            .format = "nat-msg " _str " %d.%d.%d.%d",    \
-            .format_args = "i1i1i1i1",                   \
-          };                                             \
-        CLIB_PACKED(struct                               \
-          {                                              \
-            u8 oct1;                                     \
-            u8 oct2;                                     \
-            u8 oct3;                                     \
-            u8 oct4;                                     \
-          }) *ed;                                        \
-        ed = ELOG_DATA (&vlib_global_main.elog_main, e); \
-        ed->oct4 = _addr >> 24;                          \
-        ed->oct3 = _addr >> 16;                          \
-        ed->oct2 = _addr >> 8;                           \
-        ed->oct1 = _addr;                                \
-    }                                                    \
-  } while (0);
-
-#define nat_elog_debug_handoff(_str, _tid, _fib, _src, _dst)                \
-do                                                                          \
-  {                                                                         \
-  if (PREDICT_FALSE (sm->log_level >= SNAT_LOG_DEBUG))                      \
-    {                                                                       \
-      ELOG_TYPE_DECLARE (e) =                                               \
-        {                                                                   \
-          .format = "nat-msg " _str " ip src: %d.%d.%d.%d dst: %d.%d.%d.%d" \
-                                    " tid from: %d to: %d fib: %d",         \
-        .format_args = "i1i1i1i1i1i1i1i1i4i4i4",                            \
-      };                                                                    \
-      CLIB_PACKED(struct                                                    \
-        {                                                                   \
-          u8 src_oct1;                                                      \
-          u8 src_oct2;                                                      \
-          u8 src_oct3;                                                      \
-          u8 src_oct4;                                                      \
-          u8 dst_oct1;                                                      \
-          u8 dst_oct2;                                                      \
-          u8 dst_oct3;                                                      \
-          u8 dst_oct4;                                                      \
-          u32 ftid;                                                         \
-          u32 ttid;                                                         \
-          u32 fib;                                                          \
-        }) *ed;                                                             \
-      ed = ELOG_DATA (&vlib_global_main.elog_main, e);                      \
-      ed->src_oct1 = _src >> 24;                                            \
-      ed->src_oct2 = _src >> 16;                                            \
-      ed->src_oct3 = _src >> 8;                                             \
-      ed->src_oct4 = _src;                                                  \
-      ed->dst_oct1 = _dst >> 24;                                            \
-      ed->dst_oct2 = _dst >> 16;                                            \
-      ed->dst_oct3 = _dst >> 8;                                             \
-      ed->dst_oct4 = _dst;                                                  \
-      ed->ftid = vlib_get_thread_index ();                                  \
-      ed->ttid = _tid;                                                      \
-      ed->fib = _fib;                                                       \
-    }                                                                       \
-  } while (0);
-
-#define nat_elog_debug_handoff_v2(_str, _prt, _fib, _src, _dst)              \
-do                                                                           \
-  {                                                                          \
-  if (PREDICT_FALSE (sm->log_level >= SNAT_LOG_DEBUG))                       \
-    {                                                                        \
-      ELOG_TYPE_DECLARE (e) =                                                \
-        {                                                                    \
-          .format = "nat-msg " _str " ip_src:%d.%d.%d.%d ip_dst:%d.%d.%d.%d" \
-                                    " tid:%d prt:%d fib:%d",                 \
-        .format_args = "i1i1i1i1i1i1i1i1i4i4i4",                             \
-      };                                                                     \
-      CLIB_PACKED(struct                                                     \
-        {                                                                    \
-          u8 src_oct1;                                                       \
-          u8 src_oct2;                                                       \
-          u8 src_oct3;                                                       \
-          u8 src_oct4;                                                       \
-          u8 dst_oct1;                                                       \
-          u8 dst_oct2;                                                       \
-          u8 dst_oct3;                                                       \
-          u8 dst_oct4;                                                       \
-          u32 tid;                                                           \
-          u32 prt;                                                           \
-          u32 fib;                                                           \
-        }) *ed;                                                              \
-      ed = ELOG_DATA (&vlib_global_main.elog_main, e);                       \
-      ed->src_oct1 = _src >> 24;                                             \
-      ed->src_oct2 = _src >> 16;                                             \
-      ed->src_oct3 = _src >> 8;                                              \
-      ed->src_oct4 = _src;                                                   \
-      ed->dst_oct1 = _dst >> 24;                                             \
-      ed->dst_oct2 = _dst >> 16;                                             \
-      ed->dst_oct3 = _dst >> 8;                                              \
-      ed->dst_oct4 = _dst;                                                   \
-      ed->tid = vlib_get_thread_index ();                                    \
-      ed->prt = _prt;                                                        \
-      ed->fib = _fib;                                                        \
-    }                                                                        \
-  } while (0);
-
-#define nat_elog_X1(_level, _fmt, _arg, _val1)            \
-do                                                        \
-  {                                                       \
-    snat_main_t *sm = &snat_main;                         \
-    if (PREDICT_FALSE (sm->log_level >= _level))          \
-      {                                                   \
-        ELOG_TYPE_DECLARE (e) =                           \
-          {                                               \
-            .format = "nat-msg " _fmt,                    \
-            .format_args = _arg,                          \
-          };                                              \
-        CLIB_PACKED(struct                                \
-          {                                               \
-            typeof (_val1) val1;                          \
-          }) *ed;                                         \
-        ed = ELOG_DATA (&vlib_global_main.elog_main, e);  \
-        ed->val1 = _val1;                                 \
-      }                                                   \
-  } while (0);
-
-#define nat_elog_notice(nat_elog_str) \
-  nat_elog(SNAT_LOG_INFO, "[notice] " nat_elog_str)
-#define nat_elog_warn(nat_elog_str) \
-  nat_elog(SNAT_LOG_WARNING, "[warning] " nat_elog_str)
-#define nat_elog_err(nat_elog_str) \
-  nat_elog(SNAT_LOG_ERROR, "[error] " nat_elog_str)
-#define nat_elog_debug(nat_elog_str) \
-  nat_elog(SNAT_LOG_DEBUG, "[debug] " nat_elog_str)
-#define nat_elog_info(nat_elog_str) \
-  nat_elog(SNAT_LOG_INFO, "[info] " nat_elog_str)
-
-#define nat_elog_notice_X1(nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1) \
-  nat_elog_X1(SNAT_LOG_NOTICE, "[notice] " nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1)
-#define nat_elog_warn_X1(nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1) \
-  nat_elog_X1(SNAT_LOG_WARNING, "[warning] " nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1)
-#define nat_elog_err_X1(nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1) \
-  nat_elog_X1(SNAT_LOG_ERROR, "[error] " nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1)
-#define nat_elog_debug_X1(nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1) \
-  nat_elog_X1(SNAT_LOG_DEBUG, "[debug] " nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1)
-#define nat_elog_info_X1(nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1) \
-  nat_elog_X1(SNAT_LOG_INFO, "[info] " nat_elog_fmt_str, nat_elog_fmt_arg, nat_elog_val1)
-
-/* ICMP session match functions */
-u32 icmp_match_in2out_fast (snat_main_t *sm, vlib_node_runtime_t *node,
-                           u32 thread_index, vlib_buffer_t *b0,
-                           ip4_header_t *ip0, ip4_address_t *addr, u16 *port,
-                           u32 *fib_index, nat_protocol_t *proto,
-                           snat_session_t **s0, u8 *dont_translate);
-u32 icmp_match_in2out_slow (snat_main_t *sm, vlib_node_runtime_t *node,
-                           u32 thread_index, vlib_buffer_t *b0,
-                           ip4_header_t *ip0, ip4_address_t *addr, u16 *port,
-                           u32 *fib_index, nat_protocol_t *proto,
-                           snat_session_t **s0, u8 *dont_translate);
-u32 icmp_match_out2in_fast (snat_main_t *sm, vlib_node_runtime_t *node,
-                           u32 thread_index, vlib_buffer_t *b0,
-                           ip4_header_t *ip0, ip4_address_t *addr, u16 *port,
-                           u32 *fib_index, nat_protocol_t *proto,
-                           snat_session_t **s0, u8 *dont_translate);
-u32 icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
-                           u32 thread_index, vlib_buffer_t *b0,
-                           ip4_header_t *ip0, ip4_address_t *addr, u16 *port,
-                           u32 *fib_index, nat_protocol_t *proto,
-                           snat_session_t **s0, u8 *dont_translate);
-
-/* hairpinning functions */
-u32 snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0,
-                          u32 thread_index, ip4_header_t *ip0,
-                          icmp46_header_t *icmp0, u32 *required_thread_index);
-
-void nat_hairpinning_sm_unknown_proto (snat_main_t * sm, vlib_buffer_t * b,
-                                      ip4_header_t * ip);
-
-int snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node,
-                     snat_main_t *sm, u32 thread_index, vlib_buffer_t *b0,
-                     ip4_header_t *ip0, udp_header_t *udp0,
-                     tcp_header_t *tcp0, u32 proto0, int do_trace,
-                     u32 *required_thread_index);
-
-/* 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);
-
-
 /**
  * @brief Enable NAT44 plugin
  *
@@ -1378,39 +1036,6 @@ int nat44_set_session_limit (u32 session_limit, u32 vrf_id);
  */
 int nat44_update_session_limit (u32 session_limit, u32 vrf_id);
 
-/**
- * @brief Free all NAT44 sessions
- */
-void nat44_sessions_clear ();
-
-/**
- * @brief Find or create NAT user
- *
- * @param sm           snat global configuration data
- * @param addr         IPv4 address
- * @param fib_index    FIB table index
- * @param thread_index thread index
- *
- * @return NAT user data structure on success otherwise zero value
- */
-snat_user_t *nat_user_get_or_create (snat_main_t * sm,
-                                    ip4_address_t * addr, u32 fib_index,
-                                    u32 thread_index);
-
-/**
- * @brief Allocate new NAT session or recycle last used
- *
- * @param sm           snat global configuration data
- * @param u            NAT user
- * @param thread_index thread index
- * @param now          time now
- *
- * @return session data structure on success otherwise zero value
- */
-snat_session_t *nat_session_alloc_or_recycle (snat_main_t * sm,
-                                             snat_user_t * u,
-                                             u32 thread_index, f64 now);
-
 /**
  * @brief Free outside address and port pair
  *
@@ -1516,20 +1141,20 @@ typedef struct
   u16 src_port, dst_port;
 } tcp_udp_header_t;
 
-u8 *format_user_kvp (u8 * s, va_list * args);
-
 u32 get_thread_idx_by_port (u16 e_port);
 
 u8 *format_static_mapping_kvp (u8 *s, va_list *args);
 
 u8 *format_session_kvp (u8 *s, va_list *args);
 
-u8 *format_user_kvp (u8 *s, va_list *args);
-
 u32 nat_calc_bihash_buckets (u32 n_elts);
 
 void nat44_addresses_free (snat_address_t **addresses);
 
+void nat44_ed_sessions_clear ();
+
+int nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts);
+
 typedef enum
 {
   NAT_ED_TRNSL_ERR_SUCCESS = 0,
@@ -1548,7 +1173,7 @@ format_function_t format_nat_ed_translation_error;
 format_function_t format_nat_6t_flow;
 format_function_t format_ed_session_kvp;
 
-#endif /* __included_nat_h__ */
+#endif /* __included_nat44_ed_h__ */
 /*
  * fd.io coding-style-patch-verification: ON
  *
similarity index 93%
rename from src/plugins/nat/nat_affinity.c
rename to src/plugins/nat/nat44-ed/nat44_ed_affinity.c
index e7a7354..6debe40 100644 (file)
  * @brief NAT plugin client-IP based session affinity for load-balancing
  */
 
-#include <nat/nat_affinity.h>
-#include <nat/nat.h>
+#include <nat/lib/log.h>
+
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_affinity.h>
 
 nat_affinity_main_t nat_affinity_main;
 
@@ -109,6 +111,7 @@ nat_affinity_get_per_service_list_head_index (void)
 void
 nat_affinity_flush_service (u32 affinity_per_service_list_head_index)
 {
+  snat_main_t *sm = &snat_main;
   nat_affinity_main_t *nam = &nat_affinity_main;
   u32 elt_index;
   dlist_elt_t *elt;
@@ -128,7 +131,7 @@ nat_affinity_flush_service (u32 affinity_per_service_list_head_index)
       kv.key[1] = a->key.as_u64[1];
       pool_put_index (nam->affinity_pool, elt->value);
       if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
-       nat_elog_warn ("affinity key del failed");
+       nat_elog_warn (sm, "affinity key del failed");
       pool_put_index (nam->list_pool, elt_index);
     }
   pool_put_index (nam->list_pool, affinity_per_service_list_head_index);
@@ -141,6 +144,7 @@ nat_affinity_find_and_lock (ip4_address_t client_addr,
                            ip4_address_t service_addr, u8 proto,
                            u16 service_port, u8 * backend_index)
 {
+  snat_main_t *sm = &snat_main;
   nat_affinity_main_t *nam = &nat_affinity_main;
   clib_bihash_kv_16_8_t kv, value;
   nat_affinity_t *a;
@@ -164,7 +168,7 @@ nat_affinity_find_and_lock (ip4_address_t client_addr,
          pool_put_index (nam->list_pool, a->per_service_index);
          pool_put_index (nam->affinity_pool, value.value);
          if (clib_bihash_add_del_16_8 (&nam->affinity_hash, &kv, 0))
-           nat_elog_warn ("affinity key del failed");
+           nat_elog_warn (sm, "affinity key del failed");
          rv = 1;
          goto unlock;
        }
@@ -180,6 +184,7 @@ unlock:
 static int
 affinity_is_expired_cb (clib_bihash_kv_16_8_t * kv, void *arg)
 {
+  snat_main_t *sm = &snat_main;
   nat_affinity_main_t *nam = &nat_affinity_main;
   nat_affinity_t *a;
 
@@ -192,7 +197,7 @@ affinity_is_expired_cb (clib_bihash_kv_16_8_t * kv, void *arg)
          pool_put_index (nam->list_pool, a->per_service_index);
          pool_put_index (nam->affinity_pool, kv->value);
          if (clib_bihash_add_del_16_8 (&nam->affinity_hash, kv, 0))
-           nat_elog_warn ("affinity key del failed");
+           nat_elog_warn (sm, "affinity key del failed");
          return 1;
        }
     }
@@ -207,6 +212,7 @@ nat_affinity_create_and_lock (ip4_address_t client_addr,
                              u32 sticky_time,
                              u32 affinity_per_service_list_head_index)
 {
+  snat_main_t *sm = &snat_main;
   nat_affinity_main_t *nam = &nat_affinity_main;
   clib_bihash_kv_16_8_t kv, value;
   nat_affinity_t *a;
@@ -218,7 +224,7 @@ nat_affinity_create_and_lock (ip4_address_t client_addr,
   if (!clib_bihash_search_16_8 (&nam->affinity_hash, &kv, &value))
     {
       rv = 1;
-      nat_elog_notice ("affinity key already exist");
+      nat_elog_notice (sm, "affinity key already exist");
       goto unlock;
     }
 
@@ -229,7 +235,7 @@ nat_affinity_create_and_lock (ip4_address_t client_addr,
                                             affinity_is_expired_cb, NULL);
   if (rv)
     {
-      nat_elog_notice ("affinity key add failed");
+      nat_elog_notice (sm, "affinity key add failed");
       pool_put (nam->affinity_pool, a);
       goto unlock;
     }
similarity index 96%
rename from src/plugins/nat/nat_affinity.h
rename to src/plugins/nat/nat44-ed/nat44_ed_affinity.h
index d6bda6a..2cfa9d2 100644 (file)
@@ -17,8 +17,8 @@
  * @brief NAT plugin client-IP based session affinity for load-balancing
  */
 
-#ifndef __included_nat_affinity_h__
-#define __included_nat_affinity_h__
+#ifndef __included_nat44_ed_affinity_h__
+#define __included_nat44_ed_affinity_h__
 
 #include <vnet/ip/ip.h>
 #include <vppinfra/bihash_16_8.h>
@@ -141,7 +141,7 @@ void nat_affinity_unlock (ip4_address_t client_addr,
                          ip4_address_t service_addr, u8 proto,
                          u16 service_port);
 
-#endif /* __included_nat_affinity_h__ */
+#endif /* __included_nat44_ed_affinity_h__ */
 
 /*
  * fd.io coding-style-patch-verification: ON
similarity index 78%
rename from src/plugins/nat/nat44_api.c
rename to src/plugins/nat/nat44-ed/nat44_ed_api.c
index a5e2919..ea812da 100644 (file)
 #include <nat/lib/nat_inlines.h>
 #include <nat/lib/ipfix_logging.h>
 
-#include <nat/nat.h>
+#include <nat/nat44-ed/nat44_ed.h>
 
-#include <nat/nat44.api_enum.h>
-#include <nat/nat44.api_types.h>
-
-#include <nat/nat44-ei/nat44_ei_ha.h>
-#include <nat/nat44-ei/nat44_ei.h>
-#include <nat/nat_inlines.h>
-
-#include <nat/nat44/inlines.h>
-#include <nat/nat44/ed_inlines.h>
+#include <nat/nat44-ed/nat44_ed.api_enum.h>
+#include <nat/nat44-ed/nat44_ed.api_types.h>
 
 #define REPLY_MSG_ID_BASE sm->msg_id_base
 #include <vlibapi/api_helper_macros.h>
@@ -48,12 +41,10 @@ vl_api_nat_control_ping_t_handler (vl_api_nat_control_ping_t * mp)
   snat_main_t *sm = &snat_main;
   int rv = 0;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2 (VL_API_NAT_CONTROL_PING_REPLY,
   ({
     rmp->vpe_pid = ntohl (getpid ());
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -63,21 +54,19 @@ vl_api_nat_show_config_t_handler (vl_api_nat_show_config_t * mp)
   snat_main_t *sm = &snat_main;
   int rv = 0;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2_ZERO (VL_API_NAT_SHOW_CONFIG_REPLY,
   ({
     rmp->translation_buckets = htonl (sm->translation_buckets);
-    rmp->user_buckets = htonl (sm->user_buckets);
-    rmp->max_translations_per_user = htonl (sm->max_translations_per_user);
+    rmp->user_buckets = 0;
+    rmp->max_translations_per_user = 0;
     rmp->outside_vrf_id = htonl (sm->outside_vrf_id);
     rmp->inside_vrf_id = htonl (sm->inside_vrf_id);
     rmp->static_mapping_only = sm->static_mapping_only;
     rmp->static_mapping_connection_tracking =
       sm->static_mapping_connection_tracking;
-    rmp->endpoint_dependent = sm->endpoint_dependent;
-    rmp->out2in_dpo = sm->out2in_dpo;
+    rmp->endpoint_dependent = 1;
+    rmp->out2in_dpo = 0;
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -87,23 +76,22 @@ vl_api_nat_show_config_2_t_handler (vl_api_nat_show_config_2_t * mp)
   snat_main_t *sm = &snat_main;
   int rv = 0;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2_ZERO (VL_API_NAT_SHOW_CONFIG_2_REPLY,
   ({
     rmp->translation_buckets = htonl (sm->translation_buckets);
-    rmp->user_buckets = htonl (sm->user_buckets);
-    rmp->max_translations_per_user = htonl (sm->max_translations_per_user);
+    rmp->user_buckets = 0;
+    rmp->max_translations_per_user = 0;
     rmp->outside_vrf_id = htonl (sm->outside_vrf_id);
     rmp->inside_vrf_id = htonl (sm->inside_vrf_id);
     rmp->static_mapping_only = sm->static_mapping_only;
     rmp->static_mapping_connection_tracking =
       sm->static_mapping_connection_tracking;
-    rmp->endpoint_dependent = sm->endpoint_dependent;
-    rmp->out2in_dpo = sm->out2in_dpo;
-    rmp->max_translations_per_thread = clib_net_to_host_u32(sm->max_translations_per_thread);
-    rmp->max_users_per_thread = clib_net_to_host_u32(sm->max_users_per_thread);
+    rmp->endpoint_dependent = 1;
+    rmp->out2in_dpo = 0;
+    rmp->max_translations_per_thread =
+      clib_net_to_host_u32 (sm->max_translations_per_thread);
+    rmp->max_users_per_thread = 0;
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -115,18 +103,19 @@ vl_api_nat44_show_running_config_t_handler (vl_api_nat44_show_running_config_t
   nat44_config_t *rc = &sm->rconfig;
   int rv = 0;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2_ZERO (VL_API_NAT44_SHOW_RUNNING_CONFIG_REPLY,
   ({
     rmp->inside_vrf = htonl (rc->inside_vrf);
     rmp->outside_vrf = htonl (rc->outside_vrf);
-    rmp->users = htonl (rc->users);
-    rmp->sessions = htonl (rc->sessions);
-    rmp->user_sessions = htonl (rc->user_sessions);
 
-    rmp->user_buckets = htonl (sm->user_buckets);
+    rmp->sessions = htonl (rc->sessions);
     rmp->translation_buckets = htonl (sm->translation_buckets);
 
+    // OBSOLETE
+    rmp->users = 0;
+    rmp->user_buckets = 0;
+    rmp->user_sessions = 0;
+
     rmp->timeouts.udp = htonl (sm->timeouts.udp);
     rmp->timeouts.tcp_established = htonl (sm->timeouts.tcp.established);
     rmp->timeouts.tcp_transitory = htonl (sm->timeouts.tcp.transitory);
@@ -135,20 +124,12 @@ vl_api_nat44_show_running_config_t_handler (vl_api_nat44_show_running_config_t
     rmp->forwarding_enabled = sm->forwarding_enabled == 1;
     // consider how to split functionality between subplugins
     rmp->ipfix_logging_enabled = nat_ipfix_logging_enabled ();
-
-    if (rc->endpoint_dependent)
-      rmp->flags |= NAT44_IS_ENDPOINT_DEPENDENT;
-    else
-      rmp->flags |= NAT44_IS_ENDPOINT_INDEPENDENT;
-
+    rmp->flags |= NAT44_IS_ENDPOINT_DEPENDENT;
     if (rc->static_mapping_only)
       rmp->flags |= NAT44_IS_STATIC_MAPPING_ONLY;
     if (rc->connection_tracking)
       rmp->flags |= NAT44_IS_CONNECTION_TRACKING;
-    if (rc->out2in_dpo)
-      rmp->flags |= NAT44_IS_OUT2IN_DPO;
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -207,10 +188,10 @@ vl_api_nat_worker_dump_t_handler (vl_api_nat_worker_dump_t * mp)
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   vec_foreach (worker_index, sm->workers)
-    send_nat_worker_details(*worker_index, reg, mp->context);
-  /* *INDENT-ON* */
+    {
+      send_nat_worker_details (*worker_index, reg, mp->context);
+    }
 }
 
 static void
@@ -218,7 +199,7 @@ vl_api_nat44_session_cleanup_t_handler (vl_api_nat44_session_cleanup_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat44_session_cleanup_reply_t *rmp;
-  int rv = 0;
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT44_SESSION_CLEANUP_REPLY);
 }
 
@@ -262,24 +243,28 @@ static void
 
   if (mp->enable)
     {
-      c.endpoint_dependent = mp->flags & NAT44_API_IS_ENDPOINT_DEPENDENT;
-      c.static_mapping_only = mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY;
-      c.connection_tracking = mp->flags & NAT44_API_IS_CONNECTION_TRACKING;
-      c.out2in_dpo = mp->flags & NAT44_API_IS_OUT2IN_DPO;
-
-      c.inside_vrf = ntohl (mp->inside_vrf);
-      c.outside_vrf = ntohl (mp->outside_vrf);
-
-      c.users = ntohl (mp->users);
+      if (mp->flags & NAT44_API_IS_OUT2IN_DPO || mp->users ||
+         mp->user_sessions)
+       {
+         rv = VNET_API_ERROR_UNSUPPORTED;
+       }
+      else
+       {
+         c.static_mapping_only = mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY;
+         c.connection_tracking = mp->flags & NAT44_API_IS_CONNECTION_TRACKING;
 
-      c.sessions = ntohl (mp->sessions);
+         c.inside_vrf = ntohl (mp->inside_vrf);
+         c.outside_vrf = ntohl (mp->outside_vrf);
 
-      c.user_sessions = ntohl (mp->user_sessions);
+         c.sessions = ntohl (mp->sessions);
 
-      rv = nat44_plugin_enable (c);
+         rv = nat44_plugin_enable (c);
+       }
     }
   else
-    rv = nat44_plugin_disable ();
+    {
+      rv = nat44_plugin_disable ();
+    }
 
   REPLY_MACRO (VL_API_NAT44_PLUGIN_ENABLE_DISABLE_REPLY);
 }
@@ -322,7 +307,6 @@ vl_api_nat_get_timeouts_t_handler (vl_api_nat_get_timeouts_t * mp)
   vl_api_nat_get_timeouts_reply_t *rmp;
   int rv = 0;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2 (VL_API_NAT_GET_TIMEOUTS_REPLY,
   ({
     rmp->udp = htonl (sm->timeouts.udp);
@@ -330,32 +314,6 @@ vl_api_nat_get_timeouts_t_handler (vl_api_nat_get_timeouts_t * mp)
     rmp->tcp_transitory = htonl (sm->timeouts.tcp.transitory);
     rmp->icmp = htonl (sm->timeouts.icmp);
   }))
-  /* *INDENT-ON* */
-}
-
-static void
-vl_api_nat_set_fq_options_t_handler (vl_api_nat_set_fq_options_t *mp)
-{
-  snat_main_t *sm = &snat_main;
-  vl_api_nat_set_fq_options_reply_t *rmp;
-  int rv = 0;
-  u32 frame_queue_nelts = ntohl (mp->frame_queue_nelts);
-  rv = snat_set_frame_queue_nelts (frame_queue_nelts);
-  REPLY_MACRO (VL_API_NAT_SET_FQ_OPTIONS_REPLY);
-}
-
-static void
-vl_api_nat_show_fq_options_t_handler (vl_api_nat_show_fq_options_t *mp)
-{
-  vl_api_nat_show_fq_options_reply_t *rmp;
-  snat_main_t *sm = &snat_main;
-  int rv = 0;
-  /* clang-format off */
-  REPLY_MACRO2_ZERO (VL_API_NAT_SHOW_FQ_OPTIONS_REPLY,
-  ({
-    rmp->frame_queue_nelts = htonl (sm->frame_queue_nelts);
-  }));
-  /* clang-format on */
 }
 
 static void
@@ -364,40 +322,7 @@ static void
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_set_addr_and_port_alloc_alg_reply_t *rmp;
-  int rv = 0;
-  u16 port_start, port_end;
-
-  if (sm->endpoint_dependent)
-    {
-      rv = VNET_API_ERROR_UNSUPPORTED;
-      goto send_reply;
-    }
-
-  switch (mp->alg)
-    {
-    case NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT:
-      nat44_ei_set_alloc_default ();
-      break;
-    case NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE:
-      nat44_ei_set_alloc_mape (ntohs (mp->psid), mp->psid_offset,
-                              mp->psid_length);
-      break;
-    case NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE:
-      port_start = ntohs (mp->start_port);
-      port_end = ntohs (mp->end_port);
-      if (port_end <= port_start)
-       {
-         rv = VNET_API_ERROR_INVALID_VALUE;
-         goto send_reply;
-       }
-      nat44_ei_set_alloc_range (port_start, port_end);
-      break;
-    default:
-      rv = VNET_API_ERROR_INVALID_VALUE;
-      break;
-    }
-
-send_reply:
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT_SET_ADDR_AND_PORT_ALLOC_ALG_REPLY);
 }
 
@@ -407,19 +332,8 @@ static void
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_get_addr_and_port_alloc_alg_reply_t *rmp;
-  int rv = 0;
-
-  /* *INDENT-OFF* */
-  REPLY_MACRO2 (VL_API_NAT_GET_ADDR_AND_PORT_ALLOC_ALG_REPLY,
-  ({
-    rmp->alg = sm->addr_and_port_alloc_alg;
-    rmp->psid_offset = sm->psid_offset;
-    rmp->psid_length = sm->psid_length;
-    rmp->psid = htons (sm->psid);
-    rmp->start_port = htons (sm->start_port);
-    rmp->end_port = htons (sm->end_port);
-  }))
-  /* *INDENT-ON* */
+  int rv = VNET_API_ERROR_UNSUPPORTED;
+  REPLY_MACRO (VL_API_NAT_GET_ADDR_AND_PORT_ALLOC_ALG_REPLY);
 }
 
 static void
@@ -444,13 +358,11 @@ vl_api_nat_get_mss_clamping_t_handler (vl_api_nat_get_mss_clamping_t * mp)
   vl_api_nat_get_mss_clamping_reply_t *rmp;
   int rv = 0;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2 (VL_API_NAT_GET_MSS_CLAMPING_REPLY,
   ({
     rmp->enable = sm->mss_clamping ? 1 : 0;
     rmp->mss_value = htons (sm->mss_clamping);
   }))
-  /* *INDENT-ON* */
 }
 
 static void
@@ -458,14 +370,7 @@ vl_api_nat_ha_set_listener_t_handler (vl_api_nat_ha_set_listener_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_ha_set_listener_reply_t *rmp;
-  ip4_address_t addr;
-  int rv;
-
-  memcpy (&addr, &mp->ip_address, sizeof (addr));
-  rv =
-    nat_ha_set_listener (&addr, clib_net_to_host_u16 (mp->port),
-                        clib_net_to_host_u32 (mp->path_mtu));
-
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT_HA_SET_LISTENER_REPLY);
 }
 
@@ -474,21 +379,8 @@ vl_api_nat_ha_get_listener_t_handler (vl_api_nat_ha_get_listener_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_ha_get_listener_reply_t *rmp;
-  int rv = 0;
-  ip4_address_t addr;
-  u16 port;
-  u32 path_mtu;
-
-  nat_ha_get_listener (&addr, &port, &path_mtu);
-
-  /* *INDENT-OFF* */
-  REPLY_MACRO2 (VL_API_NAT_HA_GET_LISTENER_REPLY,
-  ({
-    clib_memcpy (rmp->ip_address, &addr, sizeof (ip4_address_t));
-    rmp->port = clib_host_to_net_u16 (port);
-    rmp->path_mtu = clib_host_to_net_u32 (path_mtu);
-  }))
-  /* *INDENT-ON* */
+  int rv = VNET_API_ERROR_UNSUPPORTED;
+  REPLY_MACRO (VL_API_NAT_HA_GET_LISTENER_REPLY);
 }
 
 static void
@@ -496,14 +388,7 @@ vl_api_nat_ha_set_failover_t_handler (vl_api_nat_ha_set_failover_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_ha_set_failover_reply_t *rmp;
-  ip4_address_t addr;
-  int rv;
-
-  memcpy (&addr, &mp->ip_address, sizeof (addr));
-  rv =
-    nat_ha_set_failover (&addr, clib_net_to_host_u16 (mp->port),
-                        clib_net_to_host_u32 (mp->session_refresh_interval));
-
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT_HA_SET_FAILOVER_REPLY);
 }
 
@@ -512,21 +397,8 @@ vl_api_nat_ha_get_failover_t_handler (vl_api_nat_ha_get_failover_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_ha_get_failover_reply_t *rmp;
-  int rv = 0;
-  ip4_address_t addr;
-  u16 port;
-  u32 session_refresh_interval;
-
-  nat_ha_get_failover (&addr, &port, &session_refresh_interval);
-
-  /* *INDENT-OFF* */
-  REPLY_MACRO2 (VL_API_NAT_HA_GET_FAILOVER_REPLY,
-  ({
-    clib_memcpy (rmp->ip_address, &addr, sizeof (ip4_address_t));
-    rmp->port = clib_host_to_net_u16 (port);
-    rmp->session_refresh_interval = clib_host_to_net_u32 (session_refresh_interval);
-  }))
-  /* *INDENT-ON* */
+  int rv = VNET_API_ERROR_UNSUPPORTED;
+  REPLY_MACRO (VL_API_NAT_HA_GET_FAILOVER_REPLY);
 }
 
 static void
@@ -534,47 +406,16 @@ vl_api_nat_ha_flush_t_handler (vl_api_nat_ha_flush_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_ha_flush_reply_t *rmp;
-  int rv = 0;
-
-  nat_ha_flush (0);
-
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT_HA_FLUSH_REPLY);
 }
 
-static void
-nat_ha_resync_completed_event_cb (u32 client_index, u32 pid, u32 missed_count)
-{
-  snat_main_t *sm = &snat_main;
-  vl_api_registration_t *reg;
-  vl_api_nat_ha_resync_completed_event_t *mp;
-
-  reg = vl_api_client_index_to_registration (client_index);
-  if (!reg)
-    return;
-
-  mp = vl_msg_api_alloc (sizeof (*mp));
-  clib_memset (mp, 0, sizeof (*mp));
-  mp->client_index = client_index;
-  mp->pid = pid;
-  mp->missed_count = clib_host_to_net_u32 (missed_count);
-  mp->_vl_msg_id =
-    ntohs (VL_API_NAT_HA_RESYNC_COMPLETED_EVENT + sm->msg_id_base);
-
-  vl_api_send_msg (reg, (u8 *) mp);
-}
-
 static void
 vl_api_nat_ha_resync_t_handler (vl_api_nat_ha_resync_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat_ha_resync_reply_t *rmp;
-  int rv;
-
-  rv =
-    nat_ha_resync (mp->client_index, mp->pid,
-                  mp->want_resync_event ? nat_ha_resync_completed_event_cb :
-                  NULL);
-
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT_HA_RESYNC_REPLY);
 }
 
@@ -583,10 +424,7 @@ vl_api_nat44_del_user_t_handler (vl_api_nat44_del_user_t * mp)
 {
   snat_main_t *sm = &snat_main;
   vl_api_nat44_del_user_reply_t *rmp;
-  ip4_address_t addr;
-  int rv;
-  memcpy (&addr.as_u8, mp->ip_address, 4);
-  rv = nat44_ei_user_del (&addr, ntohl (mp->fib_index));
+  int rv = VNET_API_ERROR_UNSUPPORTED;
   REPLY_MACRO (VL_API_NAT44_DEL_USER_REPLY);
 }
 
@@ -639,9 +477,6 @@ static void
       if (rv)
        goto send_reply;
 
-      if (sm->out2in_dpo)
-       nat44_add_del_address_dpo (this_addr, is_add);
-
       increment_v4_address (&this_addr);
     }
 
@@ -686,12 +521,10 @@ vl_api_nat44_address_dump_t_handler (vl_api_nat44_address_dump_t * mp)
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   vec_foreach (a, sm->addresses)
     send_nat44_address_details (a, reg, mp->context, 0);
   vec_foreach (a, sm->twice_nat_addresses)
     send_nat44_address_details (a, reg, mp->context, 1);
-  /* *INDENT-ON* */
 }
 
 static void
@@ -750,12 +583,10 @@ vl_api_nat44_interface_dump_t_handler (vl_api_nat44_interface_dump_t * mp)
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   pool_foreach (i, sm->interfaces)
    {
     send_nat44_interface_details(i, reg, mp->context);
   }
-  /* *INDENT-ON* */
 }
 
 static void
@@ -810,12 +641,10 @@ static void
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   pool_foreach (i, sm->output_feature_interfaces)
    {
-    send_nat44_interface_output_feature_details(i, reg, mp->context);
+     send_nat44_interface_output_feature_details (i, reg, mp->context);
   }
-  /* *INDENT-ON* */
 }
 
 static void
@@ -1004,13 +833,11 @@ vl_api_nat44_static_mapping_dump_t_handler (vl_api_nat44_static_mapping_dump_t
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   pool_foreach (m, sm->static_mappings)
    {
       if (!is_identity_static_mapping(m) && !is_lb_static_mapping (m))
         send_nat44_static_mapping_details (m, reg, mp->context);
   }
-  /* *INDENT-ON* */
 
   for (j = 0; j < vec_len (sm->to_resolve); j++)
     {
@@ -1126,7 +953,6 @@ static void
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   pool_foreach (m, sm->static_mappings)
    {
       if (is_identity_static_mapping(m) && !is_lb_static_mapping (m))
@@ -1137,7 +963,6 @@ static void
           }
         }
   }
-  /* *INDENT-ON* */
 
   for (j = 0; j < vec_len (sm->to_resolve); j++)
     {
@@ -1209,14 +1034,45 @@ vl_api_nat44_interface_addr_dump_t_handler (vl_api_nat44_interface_addr_dump_t
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   vec_foreach (i, sm->auto_add_sw_if_indices)
-    send_nat44_interface_addr_details(*i, reg, mp->context, 0);
+    {
+      send_nat44_interface_addr_details (*i, reg, mp->context, 0);
+    }
   vec_foreach (i, sm->auto_add_sw_if_indices_twice_nat)
-    send_nat44_interface_addr_details(*i, reg, mp->context, 1);
-  /* *INDENT-ON* */
+    {
+      send_nat44_interface_addr_details (*i, reg, mp->context, 1);
+    }
 }
 
+/* user (internal host) key */
+typedef struct
+{
+  union
+  {
+    struct
+    {
+      ip4_address_t addr;
+      u32 fib_index;
+    };
+    u64 as_u64;
+  };
+} snat_user_key_t;
+
+typedef struct
+{
+  ip4_address_t addr;
+  u32 fib_index;
+  u32 nsessions;
+  u32 nstaticsessions;
+} snat_user_t;
+
+typedef struct
+{
+  u32 user_buckets;
+  snat_user_t *users;
+  clib_bihash_8_8_t user_hash;
+} user_create_helper_t;
+
 static void
 send_nat44_user_details (snat_user_t * u, vl_api_registration_t * reg,
                         u32 context)
@@ -1244,8 +1100,7 @@ send_nat44_user_details (snat_user_t * u, vl_api_registration_t * reg,
 }
 
 static void
-nat_ed_user_create_helper (snat_main_per_thread_data_t * tsm,
-                          snat_session_t * s)
+nat_ed_user_create_helper (user_create_helper_t *uch, snat_session_t *s)
 {
   snat_user_key_t k;
   k.addr = s->in2out.addr;
@@ -1253,19 +1108,20 @@ nat_ed_user_create_helper (snat_main_per_thread_data_t * tsm,
   clib_bihash_kv_8_8_t key, value;
   key.key = k.as_u64;
   snat_user_t *u;
-  if (clib_bihash_search_8_8 (&tsm->user_hash, &key, &value))
+
+  if (clib_bihash_search_8_8 (&uch->user_hash, &key, &value))
     {
-      pool_get (tsm->users, u);
+      pool_get (uch->users, u);
       u->addr = k.addr;
       u->fib_index = k.fib_index;
       u->nsessions = 0;
       u->nstaticsessions = 0;
-      key.value = u - tsm->users;
-      clib_bihash_add_del_8_8 (&tsm->user_hash, &key, 1);
+      key.value = u - uch->users;
+      clib_bihash_add_del_8_8 (&uch->user_hash, &key, 1);
     }
   else
     {
-      u = pool_elt_at_index (tsm->users, value.value);
+      u = pool_elt_at_index (uch->users, value.value);
     }
   if (snat_is_session_static (s))
     {
@@ -1277,56 +1133,63 @@ nat_ed_user_create_helper (snat_main_per_thread_data_t * tsm,
     }
 }
 
+u8 *
+format_user_kvp (u8 *s, va_list *args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+  snat_user_key_t k;
+  k.as_u64 = v->key;
+  s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
+             k.fib_index, v->value);
+  return s;
+}
+
 static void
-nat_ed_users_create (snat_main_per_thread_data_t * tsm)
+nat_ed_users_create (snat_main_per_thread_data_t *tsm,
+                    user_create_helper_t *uch)
 {
   snat_session_t *s;
-  /* *INDENT-OFF* */
-  pool_foreach (s, tsm->sessions) { nat_ed_user_create_helper (tsm, s); }
-  /* *INDENT-ON* */
+  clib_bihash_init_8_8 (&uch->user_hash, "users", uch->user_buckets, 0);
+  clib_bihash_set_kvp_format_fn_8_8 (&uch->user_hash, format_user_kvp);
+  pool_foreach (s, tsm->sessions)
+    {
+      nat_ed_user_create_helper (uch, s);
+    }
 }
 
 static void
-nat_ed_users_destroy (snat_main_per_thread_data_t * tsm)
+nat_ed_users_destroy (user_create_helper_t *uch)
 {
-  snat_user_t *u;
-  /* *INDENT-OFF* */
-  pool_flush (u, tsm->users, { });
-  /* *INDENT-ON* */
-  clib_bihash_free_8_8 (&tsm->user_hash);
-  clib_bihash_init_8_8 (&tsm->user_hash, "users", snat_main.user_buckets, 0);
-  clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
+  pool_free (uch->users);
+  clib_bihash_free_8_8 (&uch->user_hash);
 }
 
 static void
 vl_api_nat44_user_dump_t_handler (vl_api_nat44_user_dump_t * mp)
 {
+  user_create_helper_t uch;
   vl_api_registration_t *reg;
   snat_main_t *sm = &snat_main;
   snat_main_per_thread_data_t *tsm;
   snat_user_t *u;
 
+  clib_memset (&uch, 0, sizeof (uch));
+
+  uch.user_buckets = nat_calc_bihash_buckets (1024);
+
   reg = vl_api_client_index_to_registration (mp->client_index);
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   vec_foreach (tsm, sm->per_thread_data)
     {
-      if (sm->endpoint_dependent)
-       {
-         nat_ed_users_create (tsm);
-       }
-      pool_foreach (u, tsm->users)
-       {
-        send_nat44_user_details (u, reg, mp->context);
-      }
-      if (sm->endpoint_dependent)
+      nat_ed_users_create (tsm, &uch);
+      pool_foreach (u, uch.users)
        {
-         nat_ed_users_destroy (tsm);
+         send_nat44_user_details (u, reg, mp->context);
        }
+      nat_ed_users_destroy (&uch);
     }
-  /* *INDENT-ON* */
 }
 
 static void
@@ -1386,15 +1249,11 @@ static void
 vl_api_nat44_user_session_dump_t_handler (vl_api_nat44_user_session_dump_t *
                                          mp)
 {
-  vl_api_registration_t *reg;
-  snat_main_t *sm = &snat_main;
   snat_main_per_thread_data_t *tsm;
-  snat_session_t *s;
-  clib_bihash_kv_8_8_t key, value;
+  snat_main_t *sm = &snat_main;
+  vl_api_registration_t *reg;
   snat_user_key_t ukey;
-  snat_user_t *u;
-  u32 session_index, head_index, elt_index;
-  dlist_elt_t *head, *elt;
+  snat_session_t *s;
   ip4_header_t ip;
 
   reg = vl_api_client_index_to_registration (mp->client_index);
@@ -1404,48 +1263,19 @@ vl_api_nat44_user_session_dump_t_handler (vl_api_nat44_user_session_dump_t *
   clib_memcpy (&ukey.addr, mp->ip_address, 4);
   ip.src_address.as_u32 = ukey.addr.as_u32;
   ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id));
-  key.key = ukey.as_u64;
   if (sm->num_workers > 1)
     tsm =
       vec_elt_at_index (sm->per_thread_data,
                        sm->worker_in2out_cb (&ip, ukey.fib_index, 0));
   else
     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
-  if (!sm->endpoint_dependent)
-    {
-      if (clib_bihash_search_8_8 (&tsm->user_hash, &key, &value))
-       return;
-      u = pool_elt_at_index (tsm->users, value.value);
-      if (!u->nsessions && !u->nstaticsessions)
-       return;
-
-      head_index = u->sessions_per_user_list_head_index;
-      head = pool_elt_at_index (tsm->list_pool, head_index);
-      elt_index = head->next;
-      elt = pool_elt_at_index (tsm->list_pool, elt_index);
-      session_index = elt->value;
-      while (session_index != ~0)
-       {
-         s = pool_elt_at_index (tsm->sessions, session_index);
 
-         send_nat44_user_session_details (s, reg, mp->context);
-
-         elt_index = elt->next;
-         elt = pool_elt_at_index (tsm->list_pool, elt_index);
-         session_index = elt->value;
-       }
-    }
-  else
-    {
-      /* *INDENT-OFF* */
       pool_foreach (s, tsm->sessions) {
         if (s->in2out.addr.as_u32 == ukey.addr.as_u32)
           {
             send_nat44_user_session_details (s, reg, mp->context);
           }
       }
-      /* *INDENT-ON* */
-    }
 }
 
 static nat44_lb_addr_port_t *
@@ -1483,12 +1313,6 @@ static void
   nat_protocol_t proto;
   u8 *tag = 0;
 
-  if (!sm->endpoint_dependent)
-    {
-      rv = VNET_API_ERROR_UNSUPPORTED;
-      goto send_reply;
-    }
-
   locals =
     unformat_nat44_lb_addr_port (mp->locals,
                                 clib_net_to_host_u32 (mp->local_num));
@@ -1513,8 +1337,6 @@ static void
 
   vec_free (locals);
   vec_free (tag);
-
-send_reply:
   REPLY_MACRO (VL_API_NAT44_ADD_DEL_LB_STATIC_MAPPING_REPLY);
 }
 
@@ -1528,12 +1350,6 @@ static void
   ip4_address_t e_addr, l_addr;
   nat_protocol_t proto;
 
-  if (!sm->endpoint_dependent)
-    {
-      rv = VNET_API_ERROR_UNSUPPORTED;
-      goto send_reply;
-    }
-
   clib_memcpy (&e_addr, mp->external_addr, 4);
   clib_memcpy (&l_addr, mp->local.addr, 4);
   proto = ip_proto_to_nat_proto (mp->protocol);
@@ -1548,7 +1364,6 @@ static void
                                                                 local.vrf_id),
                                           mp->local.probability, mp->is_add);
 
-send_reply:
   REPLY_MACRO (VL_API_NAT44_LB_STATIC_MAPPING_ADD_DEL_LOCAL_REPLY);
 }
 
@@ -1586,7 +1401,6 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t * m,
     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
   locals = (vl_api_nat44_lb_addr_port_t *) rmp->locals;
-  /* *INDENT-OFF* */
   pool_foreach (ap, m->locals)
    {
     clib_memcpy (locals->addr, &(ap->addr), 4);
@@ -1596,7 +1410,6 @@ send_nat44_lb_static_mapping_details (snat_static_mapping_t * m,
     locals++;
     local_num++;
   }
-  /* *INDENT-ON* */
   rmp->local_num = ntohl (local_num);
 
   vl_api_send_msg (reg, (u8 *) rmp);
@@ -1610,20 +1423,15 @@ static void
   snat_main_t *sm = &snat_main;
   snat_static_mapping_t *m;
 
-  if (!sm->endpoint_dependent)
-    return;
-
   reg = vl_api_client_index_to_registration (mp->client_index);
   if (!reg)
     return;
 
-  /* *INDENT-OFF* */
   pool_foreach (m, sm->static_mappings)
    {
       if (is_lb_static_mapping(m))
         send_nat44_lb_static_mapping_details (m, reg, mp->context);
   }
-  /* *INDENT-ON* */
 }
 
 static void
@@ -1636,23 +1444,17 @@ vl_api_nat44_del_session_t_handler (vl_api_nat44_del_session_t * mp)
   u32 vrf_id;
   int rv = 0;
   u8 is_in;
-  nat_protocol_t proto;
 
   memcpy (&addr.as_u8, mp->address, 4);
   port = mp->port;
   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
-  proto = ip_proto_to_nat_proto (mp->protocol);
   memcpy (&eh_addr.as_u8, mp->ext_host_address, 4);
   eh_port = mp->ext_host_port;
 
   is_in = mp->flags & NAT_API_IS_INSIDE;
 
-  if (mp->flags & NAT_API_IS_EXT_HOST_VALID)
-    rv =
-      nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol,
-                           vrf_id, is_in);
-  else
-    rv = nat44_ei_del_session (sm, &addr, port, proto, vrf_id, is_in);
+  rv = nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port, mp->protocol,
+                            vrf_id, is_in);
 
   REPLY_MACRO (VL_API_NAT44_DEL_SESSION_REPLY);
 }
@@ -1661,47 +1463,10 @@ static void
   vl_api_nat44_forwarding_enable_disable_t_handler
   (vl_api_nat44_forwarding_enable_disable_t * mp)
 {
-  snat_main_t *sm = &snat_main;
   vl_api_nat44_forwarding_enable_disable_reply_t *rmp;
+  snat_main_t *sm = &snat_main;
   int rv = 0;
-  u32 *ses_to_be_removed = 0, *ses_index;
-  snat_main_per_thread_data_t *tsm;
-  snat_session_t *s;
-
-  sm->forwarding_enabled = mp->enable != 0;
-
-  if (mp->enable == 0)
-    {
-      /* *INDENT-OFF* */
-      vec_foreach (tsm, sm->per_thread_data)
-      {
-        pool_foreach (s, tsm->sessions)
-         {
-          if (is_fwd_bypass_session(s))
-            {
-              vec_add1 (ses_to_be_removed, s - tsm->sessions);
-            }
-        }
-       if(sm->endpoint_dependent){
-           vec_foreach (ses_index, ses_to_be_removed)
-             {
-               s = pool_elt_at_index(tsm->sessions, ses_index[0]);
-               nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
-               nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
-             }
-       }else{
-           vec_foreach (ses_index, ses_to_be_removed)
-             {
-               s = pool_elt_at_index(tsm->sessions, ses_index[0]);
-               nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
-               nat44_delete_session (sm, s, tsm - sm->per_thread_data);
-             }
-       }
-        vec_free (ses_to_be_removed);
-      }
-      /* *INDENT-ON* */
-    }
-
+  nat44_ed_forwarding_enable_disable (mp->enable);
   REPLY_MACRO (VL_API_NAT44_FORWARDING_ENABLE_DISABLE_REPLY);
 }
 
@@ -1728,9 +1493,35 @@ static void
   vl_api_send_msg (reg, (u8 *) rmp);
 }
 
+static void
+vl_api_nat44_ed_set_fq_options_t_handler (vl_api_nat44_ed_set_fq_options_t *mp)
+{
+  snat_main_t *sm = &snat_main;
+  vl_api_nat44_ed_set_fq_options_reply_t *rmp;
+  int rv = 0;
+  u32 frame_queue_nelts = ntohl (mp->frame_queue_nelts);
+  rv = nat44_ed_set_frame_queue_nelts (frame_queue_nelts);
+  REPLY_MACRO (VL_API_NAT44_ED_SET_FQ_OPTIONS_REPLY);
+}
+
+static void
+vl_api_nat44_ed_show_fq_options_t_handler (
+  vl_api_nat44_ed_show_fq_options_t *mp)
+{
+  snat_main_t *sm = &snat_main;
+  vl_api_nat44_ed_show_fq_options_reply_t *rmp;
+  int rv = 0;
+  /* clang-format off */
+  REPLY_MACRO2_ZERO (VL_API_NAT44_ED_SHOW_FQ_OPTIONS_REPLY,
+  ({
+    rmp->frame_queue_nelts = htonl (sm->frame_queue_nelts);
+  }));
+  /* clang-format on */
+}
+
 /* API definitions */
 #include <vnet/format_fns.h>
-#include <nat/nat44.api.c>
+#include <nat/nat44-ed/nat44_ed.api.c>
 
 /* Set up the API message handling tables */
 clib_error_t *
similarity index 70%
rename from src/plugins/nat/nat44_classify.c
rename to src/plugins/nat/nat44-ed/nat44_ed_classify.c
index 85f8c64..5a9f4e4 100644 (file)
@@ -20,9 +20,9 @@
 #include <vlib/vlib.h>
 #include <vnet/vnet.h>
 #include <vnet/fib/ip4_fib.h>
-#include <nat/nat.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44/ed_inlines.h>
+
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
 
 #define foreach_nat44_classify_error                      \
 _(NEXT_IN2OUT, "next in2out")                             \
@@ -37,12 +37,6 @@ typedef enum
     NAT44_CLASSIFY_N_ERROR,
 } nat44_classify_error_t;
 
-static char *nat44_classify_error_strings[] = {
-#define _(sym,string) string,
-  foreach_nat44_classify_error
-#undef _
-};
-
 typedef enum
 {
   NAT44_CLASSIFY_NEXT_IN2OUT,
@@ -69,118 +63,13 @@ format_nat44_classify_trace (u8 * s, va_list * args)
     s = format (s, "nat44-classify: fragment cached");
   else
     {
-      next = t->next_in2out ? "nat44-in2out" : "nat44-out2in";
+      next = t->next_in2out ? "nat44-ed-in2out" : "nat44-ed-out2in";
       s = format (s, "nat44-classify: next %s", next);
     }
 
   return s;
 }
 
-static inline uword
-nat44_classify_node_fn_inline (vlib_main_t * vm,
-                              vlib_node_runtime_t * node,
-                              vlib_frame_t * frame)
-{
-  u32 n_left_from, *from, *to_next;
-  nat44_classify_next_t next_index;
-  snat_main_t *sm = &snat_main;
-  snat_static_mapping_t *m;
-  u32 next_in2out = 0, next_out2in = 0;
-
-  from = vlib_frame_vector_args (frame);
-  n_left_from = frame->n_vectors;
-  next_index = node->cached_next_index;
-
-  while (n_left_from > 0)
-    {
-      u32 n_left_to_next;
-
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
-      while (n_left_from > 0 && n_left_to_next > 0)
-       {
-         u32 bi0;
-         vlib_buffer_t *b0;
-         u32 next0 = NAT44_CLASSIFY_NEXT_IN2OUT;
-         ip4_header_t *ip0;
-         snat_address_t *ap;
-         clib_bihash_kv_8_8_t kv0, value0;
-
-         /* speculatively enqueue b0 to the current next frame */
-         bi0 = from[0];
-         to_next[0] = bi0;
-         from += 1;
-         to_next += 1;
-         n_left_from -= 1;
-         n_left_to_next -= 1;
-
-         b0 = vlib_get_buffer (vm, bi0);
-         ip0 = vlib_buffer_get_current (b0);
-
-          /* *INDENT-OFF* */
-          vec_foreach (ap, sm->addresses)
-            {
-              if (ip0->dst_address.as_u32 == ap->addr.as_u32)
-                {
-                  next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
-                  goto enqueue0;
-                }
-            }
-          /* *INDENT-ON* */
-
-         if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
-           {
-             init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
-             /* try to classify the fragment based on IP header alone */
-             if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external,
-                                          &kv0, &value0))
-               {
-                 m = pool_elt_at_index (sm->static_mappings, value0.value);
-                 if (m->local_addr.as_u32 != m->external_addr.as_u32)
-                   next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
-                 goto enqueue0;
-               }
-             init_nat_k (&kv0, ip0->dst_address,
-                         vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
-                         ip_proto_to_nat_proto (ip0->protocol));
-             if (!clib_bihash_search_8_8
-                 (&sm->static_mapping_by_external, &kv0, &value0))
-               {
-                 m = pool_elt_at_index (sm->static_mappings, value0.value);
-                 if (m->local_addr.as_u32 != m->external_addr.as_u32)
-                   next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
-               }
-           }
-
-       enqueue0:
-         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
-                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
-           {
-             nat44_classify_trace_t *t =
-               vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->cached = 0;
-             t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
-           }
-
-         next_in2out += next0 == NAT44_CLASSIFY_NEXT_IN2OUT;
-         next_out2in += next0 == NAT44_CLASSIFY_NEXT_OUT2IN;
-
-         /* verify speculative enqueue, maybe switch current next frame */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, next0);
-       }
-
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
-    }
-
-  vlib_node_increment_counter (vm, node->node_index,
-                              NAT44_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
-  vlib_node_increment_counter (vm, node->node_index,
-                              NAT44_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
-  return frame->n_vectors;
-}
-
 static inline uword
 nat44_handoff_classify_node_fn_inline (vlib_main_t * vm,
                                       vlib_node_runtime_t * node,
@@ -222,7 +111,6 @@ nat44_handoff_classify_node_fn_inline (vlib_main_t * vm,
          b0 = vlib_get_buffer (vm, bi0);
          ip0 = vlib_buffer_get_current (b0);
 
-          /* *INDENT-OFF* */
           vec_foreach (ap, sm->addresses)
             {
               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
@@ -231,7 +119,6 @@ nat44_handoff_classify_node_fn_inline (vlib_main_t * vm,
                   goto enqueue0;
                 }
             }
-          /* *INDENT-ON* */
 
          if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
            {
@@ -374,7 +261,6 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm,
              /* session doesn't exist so continue in code */
            }
 
-          /* *INDENT-OFF* */
           vec_foreach (ap, sm->addresses)
             {
               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
@@ -383,7 +269,6 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm,
                   goto enqueue0;
                 }
             }
-          /* *INDENT-ON* */
 
          if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
            {
@@ -438,30 +323,6 @@ nat44_ed_classify_node_fn_inline (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
-VLIB_NODE_FN (nat44_classify_node) (vlib_main_t * vm,
-                                   vlib_node_runtime_t * node,
-                                   vlib_frame_t * frame)
-{
-  return nat44_classify_node_fn_inline (vm, node, frame);
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (nat44_classify_node) = {
-  .name = "nat44-classify",
-  .vector_size = sizeof (u32),
-  .format_trace = format_nat44_classify_trace,
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = ARRAY_LEN(nat44_classify_error_strings),
-  .error_strings = nat44_classify_error_strings,
-  .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
-  .next_nodes = {
-    [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
-    [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
-    [NAT44_CLASSIFY_NEXT_DROP] = "error-drop",
-  },
-};
-/* *INDENT-ON* */
-
 VLIB_NODE_FN (nat44_ed_classify_node) (vlib_main_t * vm,
                                       vlib_node_runtime_t * node,
                                       vlib_frame_t * frame)
@@ -469,7 +330,6 @@ VLIB_NODE_FN (nat44_ed_classify_node) (vlib_main_t * vm,
   return nat44_ed_classify_node_fn_inline (vm, node, frame);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat44_ed_classify_node) = {
   .name = "nat44-ed-classify",
   .vector_size = sizeof (u32),
@@ -477,7 +337,6 @@ VLIB_REGISTER_NODE (nat44_ed_classify_node) = {
   .format_trace = format_nat44_classify_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FN (nat44_handoff_classify_node) (vlib_main_t * vm,
                                            vlib_node_runtime_t * node,
@@ -486,7 +345,6 @@ VLIB_NODE_FN (nat44_handoff_classify_node) (vlib_main_t * vm,
   return nat44_handoff_classify_node_fn_inline (vm, node, frame);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
   .name = "nat44-handoff-classify",
   .vector_size = sizeof (u32),
@@ -495,8 +353,6 @@ VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
   .type = VLIB_NODE_TYPE_INTERNAL,
 };
 
-/* *INDENT-ON* */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
similarity index 78%
rename from src/plugins/nat/nat44_cli.c
rename to src/plugins/nat/nat44-ed/nat44_ed_cli.c
index 68c53d0..714b410 100644 (file)
  * @brief NAT44 CLI
  */
 
-#include <nat/nat.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/lib/nat_inlines.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44/inlines.h>
-#include <nat/nat_affinity.h>
 #include <vnet/fib/fib_table.h>
 
-#include <nat/nat44-ei/nat44_ei_ha.h>
-#include <nat/nat44-ei/nat44_ei.h>
+#include <nat/lib/log.h>
+#include <nat/lib/nat_inlines.h>
+#include <nat/lib/ipfix_logging.h>
 
-#define UNSUPPORTED_IN_ED_MODE_STR \
-  "This command is unsupported in endpoint dependent mode"
-#define SUPPORTED_ONLY_IN_ED_MODE_STR \
-  "This command is supported only in endpoint dependent mode"
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
+#include <nat/nat44-ed/nat44_ed_affinity.h>
 
 static clib_error_t *
 nat44_enable_command_fn (vlib_main_t * vm,
@@ -66,21 +60,9 @@ nat44_enable_command_fn (vlib_main_t * vm,
              c.connection_tracking = 1;
            }
        }
-      else if (!mode_set && unformat (line_input, "out2in-dpo"))
-       {
-         mode_set = 1;
-         c.out2in_dpo = 1;
-       }
-      else if (!mode_set && unformat (line_input, "endpoint-dependent"))
-       {
-         mode_set = 1;
-         c.endpoint_dependent = 1;
-       }
       else if (unformat (line_input, "inside-vrf %u", &c.inside_vrf));
       else if (unformat (line_input, "outside-vrf %u", &c.outside_vrf));
-      else if (unformat (line_input, "users %u", &c.users));
       else if (unformat (line_input, "sessions %u", &c.sessions));
-      else if (unformat (line_input, "user-sessions %u", &c.user_sessions));
       else
        {
          error = clib_error_return (0, "unknown input '%U'",
@@ -182,14 +164,12 @@ nat_show_workers_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
   if (sm->num_workers > 1)
     {
       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
-      /* *INDENT-OFF* */
       vec_foreach (worker, sm->workers)
         {
           vlib_worker_thread_t *w =
             vlib_worker_threads + *worker + sm->first_worker_index;
           vlib_cli_output (vm, "  %s", w->name);
         }
-      /* *INDENT-ON* */
     }
 
   return 0;
@@ -202,7 +182,7 @@ snat_set_log_level_command_fn (vlib_main_t * vm,
 {
   unformat_input_t _line_input, *line_input = &_line_input;
   snat_main_t *sm = &snat_main;
-  u8 log_level = SNAT_LOG_NONE;
+  u8 log_level = NAT_LOG_NONE;
   clib_error_t *error = 0;
 
   /* Get a line of input. */
@@ -215,7 +195,7 @@ snat_set_log_level_command_fn (vlib_main_t * vm,
                                 format_unformat_error, line_input);
       goto done;
     }
-  if (log_level > SNAT_LOG_DEBUG)
+  if (log_level > NAT_LOG_DEBUG)
     {
       error = clib_error_return (0, "unknown logging level '%d'", log_level);
       goto done;
@@ -285,7 +265,6 @@ nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input,
                            vlib_cli_command_t * cmd)
 {
   snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
   nat_affinity_main_t *nam = &nat_affinity_main;
   int i;
   int verbose = 0;
@@ -300,116 +279,19 @@ nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input,
   vlib_cli_output (vm, "%U",
                   format_bihash_8_8, &sm->static_mapping_by_external,
                   verbose);
-  if (sm->endpoint_dependent)
-    {
       vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
-    }
-  else
-    {
-      vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out, verbose);
-      vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in, verbose);
-    }
   vec_foreach_index (i, sm->per_thread_data)
   {
-    tsm = vec_elt_at_index (sm->per_thread_data, i);
     vlib_cli_output (vm, "-------- thread %d %s --------\n",
                     i, vlib_worker_threads[i].name);
-    vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->user_hash, verbose);
+    vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
   }
 
-  if (sm->endpoint_dependent)
-    {
       vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash,
                       verbose);
-    }
 
   vlib_cli_output (vm, "-------- hash table parameters --------\n");
   vlib_cli_output (vm, "translation buckets: %u", sm->translation_buckets);
-  if (!sm->endpoint_dependent)
-    {
-      vlib_cli_output (vm, "user buckets: %u", sm->user_buckets);
-    }
-  return 0;
-}
-
-static clib_error_t *
-nat44_set_alloc_addr_and_port_alg_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 psid, psid_offset, psid_length, port_start, port_end;
-  snat_main_t *sm = &snat_main;
-
-  if (sm->endpoint_dependent)
-    return clib_error_return (0, UNSUPPORTED_IN_ED_MODE_STR);
-
-  /* Get a line of input. */
-  if (!unformat_user (input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "default"))
-       nat44_ei_set_alloc_default ();
-      else
-       if (unformat
-           (line_input, "map-e psid %d psid-offset %d psid-len %d", &psid,
-            &psid_offset, &psid_length))
-       nat44_ei_set_alloc_mape ((u16) psid, (u16) psid_offset,
-                                (u16) psid_length);
-      else
-       if (unformat
-           (line_input, "port-range %d - %d", &port_start, &port_end))
-       {
-         if (port_end <= port_start)
-           {
-             error =
-               clib_error_return (0,
-                                  "The end-port must be greater than start-port");
-             goto done;
-           }
-         nat44_ei_set_alloc_range ((u16) port_start, (u16) port_end);
-       }
-      else
-       {
-         error = clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input);
-         goto done;
-       }
-    }
-
-done:
-  unformat_free (line_input);
-
-  return error;
-};
-
-static clib_error_t *
-nat44_show_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
-                                              unformat_input_t * input,
-                                              vlib_cli_command_t * cmd)
-{
-  snat_main_t *sm = &snat_main;
-
-  vlib_cli_output (vm, "NAT address and port: %U",
-                  format_nat_addr_and_port_alloc_alg,
-                  sm->addr_and_port_alloc_alg);
-  switch (sm->addr_and_port_alloc_alg)
-    {
-    case NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE:
-      vlib_cli_output (vm, "  psid %d psid-offset %d psid-len %d", sm->psid,
-                      sm->psid_offset, sm->psid_length);
-      break;
-    case NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE:
-      vlib_cli_output (vm, "  start-port %d end-port %d", sm->start_port,
-                      sm->end_port);
-      break;
-    default:
-      break;
-    }
-
   return 0;
 }
 
@@ -460,143 +342,6 @@ nat_show_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
   return 0;
 }
 
-static clib_error_t *
-nat_ha_failover_command_fn (vlib_main_t * vm, unformat_input_t * input,
-                           vlib_cli_command_t * cmd)
-{
-  unformat_input_t _line_input, *line_input = &_line_input;
-  ip4_address_t addr;
-  u32 port, session_refresh_interval = 10;
-  int rv;
-  clib_error_t *error = 0;
-
-  /* Get a line of input. */
-  if (!unformat_user (input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U:%u", unformat_ip4_address, &addr, &port))
-       ;
-      else
-       if (unformat
-           (line_input, "refresh-interval %u", &session_refresh_interval))
-       ;
-      else
-       {
-         error = clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input);
-         goto done;
-       }
-    }
-
-  rv = nat_ha_set_failover (&addr, (u16) port, session_refresh_interval);
-  if (rv)
-    error = clib_error_return (0, "set HA failover failed");
-
-done:
-  unformat_free (line_input);
-
-  return error;
-}
-
-static clib_error_t *
-nat_ha_listener_command_fn (vlib_main_t * vm, unformat_input_t * input,
-                           vlib_cli_command_t * cmd)
-{
-  unformat_input_t _line_input, *line_input = &_line_input;
-  ip4_address_t addr;
-  u32 port, path_mtu = 512;
-  int rv;
-  clib_error_t *error = 0;
-
-  /* Get a line of input. */
-  if (!unformat_user (input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U:%u", unformat_ip4_address, &addr, &port))
-       ;
-      else if (unformat (line_input, "path-mtu %u", &path_mtu))
-       ;
-      else
-       {
-         error = clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input);
-         goto done;
-       }
-    }
-
-  rv = nat_ha_set_listener (&addr, (u16) port, path_mtu);
-  if (rv)
-    error = clib_error_return (0, "set HA listener failed");
-
-done:
-  unformat_free (line_input);
-
-  return error;
-}
-
-static clib_error_t *
-nat_show_ha_command_fn (vlib_main_t * vm, unformat_input_t * input,
-                       vlib_cli_command_t * cmd)
-{
-  ip4_address_t addr;
-  u16 port;
-  u32 path_mtu, session_refresh_interval, resync_ack_missed;
-  u8 in_resync;
-
-  nat_ha_get_listener (&addr, &port, &path_mtu);
-  if (!port)
-    {
-      vlib_cli_output (vm, "NAT HA disabled\n");
-      return 0;
-    }
-
-  vlib_cli_output (vm, "LISTENER:\n");
-  vlib_cli_output (vm, "  %U:%u path-mtu %u\n",
-                  format_ip4_address, &addr, port, path_mtu);
-
-  nat_ha_get_failover (&addr, &port, &session_refresh_interval);
-  vlib_cli_output (vm, "FAILOVER:\n");
-  if (port)
-    vlib_cli_output (vm, "  %U:%u refresh-interval %usec\n",
-                    format_ip4_address, &addr, port,
-                    session_refresh_interval);
-  else
-    vlib_cli_output (vm, "  NA\n");
-
-  nat_ha_get_resync_status (&in_resync, &resync_ack_missed);
-  vlib_cli_output (vm, "RESYNC:\n");
-  if (in_resync)
-    vlib_cli_output (vm, "  in progress\n");
-  else
-    vlib_cli_output (vm, "  completed (%d ACK missed)\n", resync_ack_missed);
-
-  return 0;
-}
-
-static clib_error_t *
-nat_ha_flush_command_fn (vlib_main_t * vm, unformat_input_t * input,
-                        vlib_cli_command_t * cmd)
-{
-  nat_ha_flush (0);
-  return 0;
-}
-
-static clib_error_t *
-nat_ha_resync_command_fn (vlib_main_t * vm, unformat_input_t * input,
-                         vlib_cli_command_t * cmd)
-{
-  clib_error_t *error = 0;
-
-  if (nat_ha_resync (0, 0, 0))
-    error = clib_error_return (0, "NAT HA resync already running");
-
-  return error;
-}
-
 static clib_error_t *
 add_address_command_fn (vlib_main_t * vm,
                        unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -681,18 +426,10 @@ add_address_command_fn (vlib_main_t * vm,
          error =
            clib_error_return (0, "NAT address used in static mapping.");
          goto done;
-       case VNET_API_ERROR_FEATURE_DISABLED:
-         error =
-           clib_error_return (0,
-                              "twice NAT available only for endpoint-dependent mode.");
-         goto done;
        default:
          break;
        }
 
-      if (sm->out2in_dpo)
-       nat44_add_del_address_dpo (this_addr, is_add);
-
       increment_v4_address (&this_addr);
     }
 
@@ -741,9 +478,6 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
   snat_main_t *sm = &snat_main;
   snat_session_t *s;
 
-  if (!sm->endpoint_dependent)
-    return clib_error_return (0, SUPPORTED_ONLY_IN_ED_MODE_STR);
-
   u32 count = 0;
 
   u64 now = vlib_time_now (vm);
@@ -767,7 +501,6 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
 
   if (sm->num_workers > 1)
     {
-      /* *INDENT-OFF* */
       vec_foreach (tsm, sm->per_thread_data)
         {
           pool_foreach (s, tsm->sessions)
@@ -811,12 +544,10 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
           nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
           count += pool_elts (tsm->sessions);
         }
-      /* *INDENT-ON* */
     }
   else
     {
       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
-      /* *INDENT-OFF* */
       pool_foreach (s, tsm->sessions)
        {
         sess_timeout_time = s->last_heard +
@@ -855,7 +586,6 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
             break;
           }
       }
-      /* *INDENT-ON* */
       nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
       count = pool_elts (tsm->sessions);
     }
@@ -882,7 +612,6 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
   snat_address_t *ap;
 
   vlib_cli_output (vm, "NAT44 pool addresses:");
-  /* *INDENT-OFF* */
   vec_foreach (ap, sm->addresses)
     {
       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
@@ -910,7 +639,6 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
       foreach_nat_protocol
     #undef _
     }
-  /* *INDENT-ON* */
   return 0;
 }
 
@@ -1033,7 +761,6 @@ nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
   vnet_main_t *vnm = vnet_get_main ();
 
   vlib_cli_output (vm, "NAT44 interfaces:");
-  /* *INDENT-OFF* */
   pool_foreach (i, sm->interfaces)
    {
     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
@@ -1052,7 +779,6 @@ nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
                       nat_interface_is_outside(i)) ? "in out" :
                      (nat_interface_is_inside(i) ? "in" : "out"));
   }
-  /* *INDENT-ON* */
 
   return 0;
 }
@@ -1166,11 +892,6 @@ add_static_mapping_command_fn (vlib_main_t * vm,
     case VNET_API_ERROR_VALUE_EXIST:
       error = clib_error_return (0, "Mapping already exist.");
       goto done;
-    case VNET_API_ERROR_FEATURE_DISABLED:
-      error =
-       clib_error_return (0,
-                          "twice-nat/out2in-only available only for endpoint-dependent mode.");
-      goto done;
     default:
       break;
     }
@@ -1353,10 +1074,6 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
     case VNET_API_ERROR_VALUE_EXIST:
       error = clib_error_return (0, "Mapping already exist.");
       goto done;
-    case VNET_API_ERROR_FEATURE_DISABLED:
-      error =
-       clib_error_return (0, "Available only for endpoint-dependent mode.");
-      goto done;
     default:
       break;
     }
@@ -1439,10 +1156,6 @@ add_lb_backend_command_fn (vlib_main_t * vm,
     case VNET_API_ERROR_VALUE_EXIST:
       error = clib_error_return (0, "Back-end already exist.");
       goto done;
-    case VNET_API_ERROR_FEATURE_DISABLED:
-      error =
-       clib_error_return (0, "Available only for endpoint-dependent mode.");
-      goto done;
     case VNET_API_ERROR_UNSPECIFIED:
       error = clib_error_return (0, "At least two back-ends must remain");
       goto done;
@@ -1466,14 +1179,12 @@ nat44_show_static_mappings_command_fn (vlib_main_t * vm,
   snat_static_map_resolve_t *rp;
 
   vlib_cli_output (vm, "NAT44 static mappings:");
-  /* *INDENT-OFF* */
   pool_foreach (m, sm->static_mappings)
    {
     vlib_cli_output (vm, " %U", format_snat_static_mapping, m);
   }
   vec_foreach (rp, sm->to_resolve)
     vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp);
-  /* *INDENT-ON* */
 
   return 0;
 }
@@ -1540,7 +1251,6 @@ nat44_show_interface_address_command_fn (vlib_main_t * vm,
   vnet_main_t *vnm = vnet_get_main ();
   u32 *sw_if_index;
 
-  /* *INDENT-OFF* */
   vlib_cli_output (vm, "NAT44 pool address interfaces:");
   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
     {
@@ -1553,7 +1263,6 @@ nat44_show_interface_address_command_fn (vlib_main_t * vm,
       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
                        *sw_if_index);
     }
-  /* *INDENT-ON* */
 
   return 0;
 }
@@ -1564,11 +1273,9 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
 {
   unformat_input_t _line_input, *line_input = &_line_input;
   clib_error_t *error = 0;
-
   snat_main_per_thread_data_t *tsm;
   snat_main_t *sm = &snat_main;
 
-  int detail = 0;
   int i = 0;
 
   if (!unformat_user (input, unformat_line_input, line_input))
@@ -1576,24 +1283,15 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (line_input, "detail"))
-       detail = 1;
-      else
-       {
-         error = clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input);
-         break;
-       }
+      error = clib_error_return (0, "unknown input '%U'",
+                                format_unformat_error, line_input);
+      break;
     }
   unformat_free (line_input);
 
 print:
-  if (!sm->endpoint_dependent)
-    vlib_cli_output (vm, "NAT44 sessions:");
-  else
     vlib_cli_output (vm, "NAT44 ED sessions:");
 
-  /* *INDENT-OFF* */
   vec_foreach_index (i, sm->per_thread_data)
     {
       tsm = vec_elt_at_index (sm->per_thread_data, i);
@@ -1602,24 +1300,12 @@ print:
                        i, vlib_worker_threads[i].name,
                        pool_elts (tsm->sessions));
 
-      if (!sm->endpoint_dependent)
-        {
-          snat_user_t *u;
-          pool_foreach (u, tsm->users)
-           {
-            vlib_cli_output (vm, "  %U", format_snat_user, tsm, u, detail);
-          }
-        }
-      else
-        {
           snat_session_t *s;
           pool_foreach (s, tsm->sessions)
            {
             vlib_cli_output (vm, "  %U\n", format_snat_session, tsm, s);
           }
-        }
     }
-  /* *INDENT-ON* */
   return error;
 }
 
@@ -1662,61 +1348,6 @@ done:
   return error;
 }
 
-static clib_error_t *
-nat44_del_user_command_fn (vlib_main_t * vm,
-                          unformat_input_t * input, vlib_cli_command_t * cmd)
-{
-  snat_main_t *sm = &snat_main;
-  unformat_input_t _line_input, *line_input = &_line_input;
-  clib_error_t *error = 0;
-  ip4_address_t addr;
-  u32 fib_index = 0;
-  int rv;
-
-  if (sm->endpoint_dependent)
-    return clib_error_return (0, UNSUPPORTED_IN_ED_MODE_STR);
-
-  /* Get a line of input. */
-  if (!unformat_user (input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U", unformat_ip4_address, &addr))
-       ;
-      else if (unformat (line_input, "fib %u", &fib_index))
-       ;
-      else
-       {
-         error = clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input);
-         goto done;
-       }
-    }
-
-  rv = nat44_ei_user_del (&addr, fib_index);
-
-  if (!rv)
-    {
-      error = clib_error_return (0, "nat44_ei_user_del returned %d", rv);
-    }
-
-done:
-  unformat_free (line_input);
-
-  return error;
-}
-
-static clib_error_t *
-nat44_clear_sessions_command_fn (vlib_main_t * vm,
-                                unformat_input_t * input,
-                                vlib_cli_command_t * cmd)
-{
-  clib_error_t *error = 0;
-  nat44_sessions_clear ();
-  return error;
-}
-
 static clib_error_t *
 nat44_del_session_command_fn (vlib_main_t * vm,
                              unformat_input_t * input,
@@ -1724,11 +1355,11 @@ nat44_del_session_command_fn (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
   unformat_input_t _line_input, *line_input = &_line_input;
-  int is_in = 0, is_ed = 0;
+  u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
   clib_error_t *error = 0;
   ip4_address_t addr, eh_addr;
-  u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
   nat_protocol_t proto;
+  int is_in = 0;
   int rv;
 
   /* Get a line of input. */
@@ -1753,11 +1384,9 @@ nat44_del_session_command_fn (vlib_main_t * vm,
        }
       else if (unformat (line_input, "vrf %u", &vrf_id))
        ;
-      else
-       if (unformat
-           (line_input, "external-host %U:%u", unformat_ip4_address,
-            &eh_addr, &eh_port))
-       is_ed = 1;
+      else if (unformat (line_input, "external-host %U:%u",
+                        unformat_ip4_address, &eh_addr, &eh_port))
+       ;
       else
        {
          error = clib_error_return (0, "unknown input '%U'",
@@ -1766,14 +1395,10 @@ nat44_del_session_command_fn (vlib_main_t * vm,
        }
     }
 
-  if (is_ed)
     rv =
       nat44_del_ed_session (sm, &addr, clib_host_to_net_u16 (port), &eh_addr,
                            clib_host_to_net_u16 (eh_port),
                            nat_proto_to_ip_proto (proto), vrf_id, is_in);
-  else
-    rv = nat44_ei_del_session (sm, &addr, clib_host_to_net_u16 (port), proto,
-                              vrf_id, is_in);
 
   switch (rv)
     {
@@ -1927,79 +1552,6 @@ done:
   return error;
 }
 
-static clib_error_t *
-nat44_debug_fib_expire_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 fib = ~0;
-
-  /* Get a line of input. */
-  if (!unformat_user (input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%u", &fib))
-       ;
-      else
-       {
-         error = clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input);
-         goto done;
-       }
-    }
-  expire_per_vrf_sessions (fib);
-done:
-  unformat_free (line_input);
-  return error;
-}
-
-static clib_error_t *
-nat44_debug_fib_registration_command_fn (vlib_main_t * vm,
-                                        unformat_input_t * input,
-                                        vlib_cli_command_t * cmd)
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
-  per_vrf_sessions_t *per_vrf_sessions;
-
-  vlib_cli_output (vm, "VRF registration debug:");
-  vec_foreach (tsm, sm->per_thread_data)
-  {
-    vlib_cli_output (vm, "thread %u:", tsm->thread_index);
-    vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
-    {
-      vlib_cli_output (vm, "rx fib %u tx fib %u ses count %u %s",
-                      per_vrf_sessions->rx_fib_index,
-                      per_vrf_sessions->tx_fib_index,
-                      per_vrf_sessions->ses_count,
-                      per_vrf_sessions->expired ? "expired" : "");
-    }
-  }
-  return 0;
-}
-
-/* *INDENT-OFF* */
-
-/*?
-?*/
-VLIB_CLI_COMMAND (nat44_debug_fib_expire_command, static) = {
-  .path = "debug nat44 fib expire",
-  .short_help = "debug nat44 fib expire <fib-index>",
-  .function = nat44_debug_fib_expire_command_fn,
-};
-
-/*?
-?*/
-VLIB_CLI_COMMAND (nat44_debug_fib_registration_command, static) = {
-  .path = "debug nat44 fib registration",
-  .short_help = "debug nat44 fib registration",
-  .function = nat44_debug_fib_registration_command_fn,
-};
-
 /*?
  * @cliexpar
  * @cliexstart{nat44 enable}
@@ -2010,17 +1562,15 @@ VLIB_CLI_COMMAND (nat44_debug_fib_registration_command, static) = {
  *  vpp# nat44 enable sessions <n> static-mapping
  * To enable nat44 static mapping with connection tracking, use:
  *  vpp# nat44 enable sessions <n> static-mapping connection-tracking
- * To enable nat44 out2in dpo, use:
- *  vpp# nat44 enable sessions <n> out2in-dpo
- * To enable nat44 endpoint-dependent, use:
- *  vpp# nat44 enable sessions <n> endpoint-dependent
  * To set inside-vrf outside-vrf, use:
  *  vpp# nat44 enable sessions <n> inside-vrf <id> outside-vrf <id>
  * @cliexend
 ?*/
 VLIB_CLI_COMMAND (nat44_enable_command, static) = {
   .path = "nat44 enable",
-  .short_help = "nat44 enable sessions <max-number> [users <max-number>] [static-mappig-only [connection-tracking]|out2in-dpo|endpoint-dependent] [inside-vrf <vrf-id>] [outside-vrf <vrf-id>] [user-sessions <max-number>]",
+  .short_help =
+    "nat44 enable sessions <max-number> [static-mappig-only "
+    "[connection-tracking]] [inside-vrf <vrf-id>] [outside-vrf <vrf-id>]",
   .function = nat44_enable_command_fn,
 };
 
@@ -2141,36 +1691,6 @@ VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
 };
 
-/*?
- * @cliexpar
- * @cliexstart{nat addr-port-assignment-alg}
- * Set address and port assignment algorithm
- * For the MAP-E CE limit port choice based on PSID use:
- *  vpp# nat addr-port-assignment-alg map-e psid 10 psid-offset 6 psid-len 6
- * For port range use:
- *  vpp# nat addr-port-assignment-alg port-range <start-port> - <end-port>
- * To set standard (default) address and port assignment algorithm use:
- *  vpp# nat addr-port-assignment-alg default
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
-    .path = "nat addr-port-assignment-alg",
-    .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
-    .function = nat44_set_alloc_addr_and_port_alg_command_fn,
-};
-
-/*?
- * @cliexpar
- * @cliexstart{show nat addr-port-assignment-alg}
- * Show address and port assignment algorithm
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat44_show_alloc_addr_and_port_alg_command, static) = {
-    .path = "show nat addr-port-assignment-alg",
-    .short_help = "show nat addr-port-assignment-alg",
-    .function = nat44_show_alloc_addr_and_port_alg_command_fn,
-};
-
 /*?
  * @cliexpar
  * @cliexstart{nat mss-clamping}
@@ -2199,66 +1719,6 @@ VLIB_CLI_COMMAND (nat_show_mss_clamping_command, static) = {
     .function = nat_show_mss_clamping_command_fn,
 };
 
-/*?
- * @cliexpar
- * @cliexstart{nat ha failover}
- * Set HA failover (remote settings)
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat_ha_failover_command, static) = {
-    .path = "nat ha failover",
-    .short_help = "nat ha failover <ip4-address>:<port> [refresh-interval <sec>]",
-    .function = nat_ha_failover_command_fn,
-};
-
-/*?
- * @cliexpar
- * @cliexstart{nat ha listener}
- * Set HA listener (local settings)
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat_ha_listener_command, static) = {
-    .path = "nat ha listener",
-    .short_help = "nat ha listener <ip4-address>:<port> [path-mtu <path-mtu>]",
-    .function = nat_ha_listener_command_fn,
-};
-
-/*?
- * @cliexpar
- * @cliexstart{show nat ha}
- * Show HA configuration/status
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat_show_ha_command, static) = {
-    .path = "show nat ha",
-    .short_help = "show nat ha",
-    .function = nat_show_ha_command_fn,
-};
-
-/*?
- * @cliexpar
- * @cliexstart{nat ha flush}
- * Flush the current HA data (for testing)
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat_ha_flush_command, static) = {
-    .path = "nat ha flush",
-    .short_help = "nat ha flush",
-    .function = nat_ha_flush_command_fn,
-};
-
-/*?
- * @cliexpar
- * @cliexstart{nat ha resync}
- * Resync HA (resend existing sessions to new failover)
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat_ha_resync_command, static) = {
-    .path = "nat ha resync",
-    .short_help = "nat ha resync",
-    .function = nat_ha_resync_command_fn,
-};
-
 /*?
  * @cliexpar
  * @cliexstart{show nat44 hash tables}
@@ -2527,32 +1987,6 @@ VLIB_CLI_COMMAND (nat44_set_session_limit_command, static) = {
   .function = nat44_set_session_limit_command_fn,
 };
 
-/*?
- * @cliexpar
- * @cliexstart{nat44 del user}
- * To delete all NAT44 user sessions:
- *  vpp# nat44 del user 10.0.0.3
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat44_del_user_command, static) = {
-    .path = "nat44 del user",
-    .short_help = "nat44 del user <addr> [fib <index>]",
-    .function = nat44_del_user_command_fn,
-};
-
-/*?
- * @cliexpar
- * @cliexstart{clear nat44 sessions}
- * To clear all NAT44 sessions
- *  vpp# clear nat44 sessions
- * @cliexend
-?*/
-VLIB_CLI_COMMAND (nat44_clear_sessions_command, static) = {
-    .path = "clear nat44 sessions",
-    .short_help = "clear nat44 sessions",
-    .function = nat44_clear_sessions_command_fn,
-};
-
 /*?
  * @cliexpar
  * @cliexstart{nat44 del session}
@@ -2586,8 +2020,6 @@ VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
   .function = snat_forwarding_set_command_fn,
 };
 
-/* *INDENT-ON* */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *
similarity index 87%
rename from src/plugins/nat/nat_format.c
rename to src/plugins/nat/nat44-ed/nat44_ed_format.c
index 2fbd749..29fd112 100644 (file)
@@ -17,8 +17,8 @@
  * @brief NAT formatting
  */
 
-#include <nat/nat.h>
-#include <nat/nat_inlines.h>
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
 
 uword
 unformat_nat_protocol (unformat_input_t * input, va_list * args)
@@ -171,49 +171,6 @@ format_snat_session (u8 * s, va_list * args)
     s = format (s, "       load-balancing\n");
   if (is_twice_nat_session (sess))
     s = format (s, "       twice-nat\n");
-
-  return s;
-}
-
-u8 *
-format_snat_user (u8 * s, va_list * args)
-{
-  snat_main_per_thread_data_t *tsm =
-    va_arg (*args, snat_main_per_thread_data_t *);
-  snat_user_t *u = va_arg (*args, snat_user_t *);
-  int verbose = va_arg (*args, int);
-  dlist_elt_t *head, *elt;
-  u32 elt_index, head_index;
-  u32 session_index;
-  snat_session_t *sess;
-
-  s = format (s, "%U: %d dynamic translations, %d static translations\n",
-             format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
-
-  if (verbose == 0)
-    return s;
-
-  if (u->nsessions || u->nstaticsessions)
-    {
-      head_index = u->sessions_per_user_list_head_index;
-      head = pool_elt_at_index (tsm->list_pool, head_index);
-
-      elt_index = head->next;
-      elt = pool_elt_at_index (tsm->list_pool, elt_index);
-      session_index = elt->value;
-
-      while (session_index != ~0)
-       {
-         sess = pool_elt_at_index (tsm->sessions, session_index);
-
-         s = format (s, "  %U\n", format_snat_session, tsm, sess);
-
-         elt_index = elt->next;
-         elt = pool_elt_at_index (tsm->list_pool, elt_index);
-         session_index = elt->value;
-       }
-    }
-
   return s;
 }
 
similarity index 99%
rename from src/plugins/nat/nat44_handoff.c
rename to src/plugins/nat/nat44-ed/nat44_ed_handoff.c
index 8c1b967..6715ce2 100644 (file)
@@ -22,8 +22,9 @@
 #include <vnet/handoff.h>
 #include <vnet/fib/ip4_fib.h>
 #include <vppinfra/error.h>
-#include <nat/nat.h>
-#include <nat/nat_inlines.h>
+
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
 
 typedef struct
 {
similarity index 92%
rename from src/plugins/nat/in2out_ed.c
rename to src/plugins/nat/nat44-ed/nat44_ed_in2out.c
index 9dc6857..784dea0 100644 (file)
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/udp/udp_local.h>
 #include <vppinfra/error.h>
-#include <nat/nat.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44/inlines.h>
+
 #include <nat/lib/nat_syslog.h>
-#include <nat/nat44/ed_inlines.h>
 #include <nat/lib/nat_inlines.h>
+#include <nat/lib/ipfix_logging.h>
+
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
 
 /* number of attempts to get a port for ED overloading algorithm, if rolling
  * a dice this many times doesn't produce a free port, it's treated
@@ -95,6 +95,75 @@ format_nat_in2out_ed_trace (u8 * s, va_list * args)
   return s;
 }
 
+/**
+ * @brief Check if packet should be translated
+ *
+ * Packets aimed at outside interface and external address with active session
+ * should be translated.
+ *
+ * @param sm            NAT main
+ * @param rt            NAT runtime data
+ * @param sw_if_index0  index of the inside interface
+ * @param ip0           IPv4 header
+ * @param proto0        NAT protocol
+ * @param rx_fib_index0 RX FIB index
+ *
+ * @returns 0 if packet should be translated otherwise 1
+ */
+static inline int
+snat_not_translate_fast (snat_main_t *sm, vlib_node_runtime_t *node,
+                        u32 sw_if_index0, ip4_header_t *ip0, u32 proto0,
+                        u32 rx_fib_index0)
+{
+  fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+  nat_outside_fib_t *outside_fib;
+  fib_prefix_t pfx = {
+    .fp_proto = FIB_PROTOCOL_IP4,
+    .fp_len = 32,
+    .fp_addr = {
+               .ip4.as_u32 = ip0->dst_address.as_u32,
+               }
+    ,
+  };
+
+  /* Don't NAT packet aimed at the intfc address */
+  if (PREDICT_FALSE (
+       is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32)))
+    return 1;
+
+  fei = fib_table_lookup (rx_fib_index0, &pfx);
+  if (FIB_NODE_INDEX_INVALID != fei)
+    {
+      u32 sw_if_index = fib_entry_get_resolving_interface (fei);
+      if (sw_if_index == ~0)
+       {
+         vec_foreach (outside_fib, sm->outside_fibs)
+           {
+             fei = fib_table_lookup (outside_fib->fib_index, &pfx);
+             if (FIB_NODE_INDEX_INVALID != fei)
+               {
+                 sw_if_index = fib_entry_get_resolving_interface (fei);
+                 if (sw_if_index != ~0)
+                   break;
+               }
+           }
+       }
+      if (sw_if_index == ~0)
+       return 1;
+
+      snat_interface_t *i;
+      pool_foreach (i, sm->interfaces)
+       {
+         /* NAT packet aimed at outside interface */
+         if ((nat_interface_is_outside (i)) &&
+             (sw_if_index == i->sw_if_index))
+           return 0;
+       }
+    }
+
+  return 1;
+}
+
 static int
 nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto,
                            u32 thread_index, ip4_address_t r_addr, u16 r_port,
@@ -160,7 +229,7 @@ nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto,
 
          foreach_nat_protocol;
        default:
-         nat_elog_info ("unknown protocol");
+         nat_elog_info (sm, "unknown protocol");
          return 1;
        }
     }
@@ -174,7 +243,7 @@ nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto,
        {
          foreach_nat_protocol;
        default:
-         nat_elog_info ("unknown protocol");
+         nat_elog_info (sm, "unknown protocol");
          return 1;
        }
     }
@@ -198,7 +267,6 @@ nat_outside_fib_index_lookup (snat_main_t * sm, ip4_address_t addr)
     ,
   };
   // TODO: multiple vrfs none can resolve addr
-  /* *INDENT-OFF* */
   vec_foreach (outside_fib, sm->outside_fibs)
     {
       fei = fib_table_lookup (outside_fib->fib_index, &pfx);
@@ -210,7 +278,6 @@ nat_outside_fib_index_lookup (snat_main_t * sm, ip4_address_t addr)
             }
         }
     }
-  /* *INDENT-ON* */
   return ~0;
 }
 
@@ -279,7 +346,7 @@ slow_path_ed (snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr,
          b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
          nat_ipfix_logging_max_sessions (thread_index,
                                          sm->max_translations_per_thread);
-         nat_elog_notice ("maximum sessions exceeded");
+         nat_elog_notice (sm, "maximum sessions exceeded");
          return NAT_NEXT_DROP;
        }
     }
@@ -360,7 +427,7 @@ slow_path_ed (snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr,
            sm->port_per_thread, tsm->snat_thread_index, s, &outside_addr,
            &outside_port))
        {
-         nat_elog_notice ("addresses exhausted");
+         nat_elog_notice (sm, "addresses exhausted");
          b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS];
          nat_ed_session_delete (sm, s, thread_index, 1);
          return NAT_NEXT_DROP;
@@ -401,7 +468,7 @@ slow_path_ed (snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr,
       nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index);
       if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2))
        {
-         nat_elog_notice ("out2in key add failed");
+         nat_elog_notice (sm, "out2in key add failed");
          goto error;
        }
     }
@@ -429,7 +496,7 @@ slow_path_ed (snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr,
 
   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     {
-      nat_elog_notice ("in2out key add failed");
+      nat_elog_notice (sm, "in2out key add failed");
       goto error;
     }
 
@@ -441,12 +508,10 @@ slow_path_ed (snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr,
                                      s->in2out.port,
                                      s->out2in.port, s->in2out.fib_index);
 
-  nat_syslog_nat44_sadd (s->user_index, s->in2out.fib_index,
-                        &s->in2out.addr, s->in2out.port,
-                        &s->ext_host_nat_addr, s->ext_host_nat_port,
-                        &s->out2in.addr, s->out2in.port,
-                        &s->ext_host_addr, s->ext_host_port, s->nat_proto,
-                        0);
+  nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
+                        s->in2out.port, &s->ext_host_nat_addr,
+                        s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
+                        &s->ext_host_addr, s->ext_host_port, s->nat_proto, 0);
 
   per_vrf_sessions_register_session (s, thread_index);
 
@@ -610,13 +675,11 @@ nat44_ed_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip,
        return 0;
 
       /* hairpinning */
-      /* *INDENT-OFF* */
       pool_foreach (i, sm->output_feature_interfaces)
        {
         if ((nat_interface_is_inside (i)) && (rx_sw_if_index == i->sw_if_index))
            return 0;
       }
-      /* *INDENT-ON* */
       return 1;
     }
 
@@ -729,7 +792,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
       b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
       nat_ipfix_logging_max_sessions (thread_index,
                                      sm->max_translations_per_thread);
-      nat_elog_notice ("maximum sessions exceeded");
+      nat_elog_notice (sm, "maximum sessions exceeded");
       return 0;
     }
 
@@ -794,7 +857,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
   if (!s)
     {
       b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED];
-      nat_elog_warn ("create NAT session failed");
+      nat_elog_warn (sm, "create NAT session failed");
       return 0;
     }
 
@@ -831,14 +894,14 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
 
   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     {
-      nat_elog_notice ("in2out flow hash add failed");
+      nat_elog_notice (sm, "in2out flow hash add failed");
       nat_ed_session_delete (sm, s, thread_index, 1);
       return NULL;
     }
 
   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
     {
-      nat_elog_notice ("out2in flow hash add failed");
+      nat_elog_notice (sm, "out2in flow hash add failed");
       nat_ed_session_delete (sm, s, thread_index, 1);
       return NULL;
     }
@@ -1089,22 +1152,21 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
       switch (proto0)
        {
        case NAT_PROTOCOL_TCP:
-         vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.tcp,
+         vlib_increment_simple_counter (&sm->counters.fastpath.in2out.tcp,
                                         thread_index, sw_if_index0, 1);
          nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index);
          break;
        case NAT_PROTOCOL_UDP:
-         vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.udp,
+         vlib_increment_simple_counter (&sm->counters.fastpath.in2out.udp,
                                         thread_index, sw_if_index0, 1);
          break;
        case NAT_PROTOCOL_ICMP:
-         vlib_increment_simple_counter (&sm->counters.fastpath.in2out_ed.icmp,
+         vlib_increment_simple_counter (&sm->counters.fastpath.in2out.icmp,
                                         thread_index, sw_if_index0, 1);
          break;
        case NAT_PROTOCOL_OTHER:
-         vlib_increment_simple_counter (
-           &sm->counters.fastpath.in2out_ed.other, thread_index, sw_if_index0,
-           1);
+         vlib_increment_simple_counter (&sm->counters.fastpath.in2out.other,
+                                        thread_index, sw_if_index0, 1);
          break;
        }
 
@@ -1144,9 +1206,8 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm,
 
       if (next[0] == NAT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.fastpath.
-                                        in2out_ed.drops, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.fastpath.in2out.drops,
+                                        thread_index, sw_if_index0, 1);
        }
 
       n_left_from--;
@@ -1231,9 +1292,8 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         vlib_increment_simple_counter (&sm->counters.slowpath.
-                                        in2out_ed.other, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.slowpath.in2out.other,
+                                        thread_index, sw_if_index0, 1);
          goto trace0;
        }
 
@@ -1250,9 +1310,8 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         vlib_increment_simple_counter (&sm->counters.slowpath.
-                                        in2out_ed.icmp, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.slowpath.in2out.icmp,
+                                        thread_index, sw_if_index0, 1);
          goto trace0;
        }
 
@@ -1336,13 +1395,13 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
 
       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.in2out_ed.tcp,
+         vlib_increment_simple_counter (&sm->counters.slowpath.in2out.tcp,
                                         thread_index, sw_if_index0, 1);
          nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index);
        }
       else
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.in2out_ed.udp,
+         vlib_increment_simple_counter (&sm->counters.slowpath.in2out.udp,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -1381,9 +1440,8 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm,
 
       if (next[0] == NAT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.
-                                        in2out_ed.drops, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.slowpath.in2out.drops,
+                                        thread_index, sw_if_index0, 1);
        }
 
       n_left_from--;
@@ -1404,7 +1462,6 @@ VLIB_NODE_FN (nat44_ed_in2out_node) (vlib_main_t * vm,
   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 0);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
   .name = "nat44-ed-in2out",
   .vector_size = sizeof (u32),
@@ -1415,7 +1472,6 @@ VLIB_REGISTER_NODE (nat44_ed_in2out_node) = {
   .error_strings = nat_in2out_ed_error_strings,
   .runtime_data_bytes = sizeof (snat_runtime_t),
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
                                            vlib_node_runtime_t * node,
@@ -1424,7 +1480,6 @@ VLIB_NODE_FN (nat44_ed_in2out_output_node) (vlib_main_t * vm,
   return nat44_ed_in2out_fast_path_node_fn_inline (vm, node, frame, 1);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
   .name = "nat44-ed-in2out-output",
   .vector_size = sizeof (u32),
@@ -1435,7 +1490,6 @@ VLIB_REGISTER_NODE (nat44_ed_in2out_output_node) = {
   .error_strings = nat_in2out_ed_error_strings,
   .runtime_data_bytes = sizeof (snat_runtime_t),
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
                                              vlib_node_runtime_t *
@@ -1444,7 +1498,6 @@ VLIB_NODE_FN (nat44_ed_in2out_slowpath_node) (vlib_main_t * vm,
   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 0);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
   .name = "nat44-ed-in2out-slowpath",
   .vector_size = sizeof (u32),
@@ -1455,7 +1508,6 @@ VLIB_REGISTER_NODE (nat44_ed_in2out_slowpath_node) = {
   .error_strings = nat_in2out_ed_error_strings,
   .runtime_data_bytes = sizeof (snat_runtime_t),
 };
-/* *INDENT-ON* */
 
 VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
                                                     vlib_node_runtime_t
@@ -1465,7 +1517,6 @@ VLIB_NODE_FN (nat44_ed_in2out_output_slowpath_node) (vlib_main_t * vm,
   return nat44_ed_in2out_slow_path_node_fn_inline (vm, node, frame, 1);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
   .name = "nat44-ed-in2out-output-slowpath",
   .vector_size = sizeof (u32),
@@ -1476,7 +1527,6 @@ VLIB_REGISTER_NODE (nat44_ed_in2out_output_slowpath_node) = {
   .error_strings = nat_in2out_ed_error_strings,
   .runtime_data_bytes = sizeof (snat_runtime_t),
 };
-/* *INDENT-ON* */
 
 static u8 *
 format_nat_pre_trace (u8 * s, va_list * args)
@@ -1502,7 +1552,6 @@ VLIB_NODE_FN (nat_pre_in2out_output_node)
                                 NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH);
 }
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat_pre_in2out_node) = {
   .name = "nat-pre-in2out",
   .vector_size = sizeof (u32),
@@ -1520,7 +1569,6 @@ VLIB_REGISTER_NODE (nat_pre_in2out_output_node) = {
   .type = VLIB_NODE_TYPE_INTERNAL,
   .n_errors = 0,
 };
-/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h
new file mode 100644 (file)
index 0000000..0623940
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @brief The NAT inline functions
+ */
+
+#ifndef __included_nat44_ed_inlines_h__
+#define __included_nat44_ed_inlines_h__
+
+#include <float.h>
+#include <vppinfra/clib.h>
+#include <vnet/fib/ip4_fib.h>
+
+#include <nat/lib/log.h>
+#include <nat/nat44-ed/nat44_ed.h>
+
+always_inline u64
+calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto)
+{
+  ASSERT (fib_index <= (1 << 14) - 1);
+  ASSERT (proto <= (1 << 3) - 1);
+  return (u64) addr.as_u32 << 32 | (u64) port << 16 | fib_index << 3 |
+        (proto & 0x7);
+}
+
+always_inline void
+split_nat_key (u64 key, ip4_address_t *addr, u16 *port, u32 *fib_index,
+              nat_protocol_t *proto)
+{
+  if (addr)
+    {
+      addr->as_u32 = key >> 32;
+    }
+  if (port)
+    {
+      *port = (key >> 16) & (u16) ~0;
+    }
+  if (fib_index)
+    {
+      *fib_index = key >> 3 & ((1 << 13) - 1);
+    }
+  if (proto)
+    {
+      *proto = key & 0x7;
+    }
+}
+
+always_inline void
+init_nat_k (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port,
+           u32 fib_index, nat_protocol_t proto)
+{
+  kv->key = calc_nat_key (addr, port, fib_index, proto);
+  kv->value = ~0ULL;
+}
+
+always_inline void
+init_nat_kv (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port,
+            u32 fib_index, nat_protocol_t proto, u32 thread_index,
+            u32 session_index)
+{
+  init_nat_k (kv, addr, port, fib_index, proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline void
+init_nat_i2o_k (clib_bihash_kv_8_8_t *kv, snat_session_t *s)
+{
+  return init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
+                    s->nat_proto);
+}
+
+always_inline void
+init_nat_i2o_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index,
+                u32 session_index)
+{
+  init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
+             s->nat_proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline void
+init_nat_o2i_k (clib_bihash_kv_8_8_t *kv, snat_session_t *s)
+{
+  return init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
+                    s->nat_proto);
+}
+
+always_inline void
+init_nat_o2i_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index,
+                u32 session_index)
+{
+  init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
+             s->nat_proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline u32
+nat_value_get_thread_index (clib_bihash_kv_8_8_t *value)
+{
+  return value->value >> 32;
+}
+
+always_inline u32
+nat_value_get_session_index (clib_bihash_kv_8_8_t *value)
+{
+  return value->value & ~(u32) 0;
+}
+
+always_inline void
+init_ed_k (clib_bihash_kv_16_8_t *kv, ip4_address_t l_addr, u16 l_port,
+          ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto)
+{
+  kv->key[0] = (u64) r_addr.as_u32 << 32 | l_addr.as_u32;
+  kv->key[1] =
+    (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
+}
+
+always_inline void
+init_ed_kv (clib_bihash_kv_16_8_t *kv, ip4_address_t l_addr, u16 l_port,
+           ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto,
+           u32 thread_index, u32 session_index)
+{
+  init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline u32
+ed_value_get_thread_index (clib_bihash_kv_16_8_t *value)
+{
+  return value->value >> 32;
+}
+
+always_inline u32
+ed_value_get_session_index (clib_bihash_kv_16_8_t *value)
+{
+  return value->value & ~(u32) 0;
+}
+
+always_inline void
+split_ed_kv (clib_bihash_kv_16_8_t *kv, ip4_address_t *l_addr,
+            ip4_address_t *r_addr, u8 *proto, u32 *fib_index, u16 *l_port,
+            u16 *r_port)
+{
+  if (l_addr)
+    {
+      l_addr->as_u32 = kv->key[0] & (u32) ~0;
+    }
+  if (r_addr)
+    {
+      r_addr->as_u32 = kv->key[0] >> 32;
+    }
+  if (r_port)
+    {
+      *r_port = kv->key[1] >> 48;
+    }
+  if (l_port)
+    {
+      *l_port = (kv->key[1] >> 32) & (u16) ~0;
+    }
+  if (fib_index)
+    {
+      *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
+    }
+  if (proto)
+    {
+      *proto = kv->key[1] & (u8) ~0;
+    }
+}
+
+static_always_inline int
+nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0,
+                                   ip4_address_t *lookup_saddr,
+                                   u16 *lookup_sport,
+                                   ip4_address_t *lookup_daddr,
+                                   u16 *lookup_dport, u8 *lookup_protocol)
+{
+  icmp46_header_t *icmp0;
+  icmp_echo_header_t *echo0, *inner_echo0 = 0;
+  ip4_header_t *inner_ip0 = 0;
+  void *l4_header = 0;
+  icmp46_header_t *inner_icmp0;
+
+  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
+  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
+
+  // avoid warning about unused variables in caller by setting to bogus values
+  *lookup_sport = 0;
+  *lookup_dport = 0;
+
+  if (!icmp_type_is_error_message (
+       vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
+    {
+      *lookup_protocol = IP_PROTOCOL_ICMP;
+      lookup_saddr->as_u32 = ip0->src_address.as_u32;
+      *lookup_sport = vnet_buffer (b)->ip.reass.l4_src_port;
+      lookup_daddr->as_u32 = ip0->dst_address.as_u32;
+      *lookup_dport = vnet_buffer (b)->ip.reass.l4_dst_port;
+    }
+  else
+    {
+      inner_ip0 = (ip4_header_t *) (echo0 + 1);
+      l4_header = ip4_next_header (inner_ip0);
+      *lookup_protocol = inner_ip0->protocol;
+      lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32;
+      lookup_daddr->as_u32 = inner_ip0->src_address.as_u32;
+      switch (ip_proto_to_nat_proto (inner_ip0->protocol))
+       {
+       case NAT_PROTOCOL_ICMP:
+         inner_icmp0 = (icmp46_header_t *) l4_header;
+         inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
+         *lookup_sport = inner_echo0->identifier;
+         *lookup_dport = inner_echo0->identifier;
+         break;
+       case NAT_PROTOCOL_UDP:
+       case NAT_PROTOCOL_TCP:
+         *lookup_sport = ((tcp_udp_header_t *) l4_header)->dst_port;
+         *lookup_dport = ((tcp_udp_header_t *) l4_header)->src_port;
+         break;
+       default:
+         return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
+       }
+    }
+  return 0;
+}
+
+always_inline u32
+nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s)
+{
+  switch (s->nat_proto)
+    {
+    case NAT_PROTOCOL_ICMP:
+      return sm->timeouts.icmp;
+    case NAT_PROTOCOL_UDP:
+      return sm->timeouts.udp;
+    case NAT_PROTOCOL_TCP:
+      {
+       if (s->state)
+         return sm->timeouts.tcp.transitory;
+       else
+         return sm->timeouts.tcp.established;
+      }
+    default:
+      return sm->timeouts.udp;
+    }
+
+  return 0;
+}
+
+static_always_inline u8
+nat44_ed_maximum_sessions_exceeded (snat_main_t *sm, u32 fib_index,
+                                   u32 thread_index)
+{
+  u32 translations;
+  translations = pool_elts (sm->per_thread_data[thread_index].sessions);
+  if (vec_len (sm->max_translations_per_fib) <= fib_index)
+    fib_index = 0;
+  return translations >= sm->max_translations_per_fib[fib_index];
+}
+
+static_always_inline int
+nat_ed_lru_insert (snat_main_per_thread_data_t *tsm, snat_session_t *s,
+                  f64 now, u8 proto)
+{
+  dlist_elt_t *lru_list_elt;
+  pool_get (tsm->lru_pool, lru_list_elt);
+  s->lru_index = lru_list_elt - tsm->lru_pool;
+  switch (proto)
+    {
+    case IP_PROTOCOL_UDP:
+      s->lru_head_index = tsm->udp_lru_head_index;
+      break;
+    case IP_PROTOCOL_TCP:
+      s->lru_head_index = tsm->tcp_trans_lru_head_index;
+      break;
+    case IP_PROTOCOL_ICMP:
+      s->lru_head_index = tsm->icmp_lru_head_index;
+      break;
+    default:
+      s->lru_head_index = tsm->unk_proto_lru_head_index;
+      break;
+    }
+  clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
+  lru_list_elt->value = s - tsm->sessions;
+  s->last_lru_update = now;
+  return 1;
+}
+
+static_always_inline void
+nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
+{
+  init_ed_k (kv, f->match.saddr, f->match.sport, f->match.daddr,
+            f->match.dport, f->match.fib_index, f->match.proto);
+}
+
+static_always_inline void
+nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f,
+                     u32 thread_idx, u32 session_idx)
+{
+  init_ed_kv (kv, f->match.saddr, f->match.sport, f->match.daddr,
+             f->match.dport, f->match.fib_index, f->match.proto, thread_idx,
+             session_idx);
+}
+
+static_always_inline int
+nat_ed_ses_i2o_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
+                                 snat_session_t *s, int is_add)
+{
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_idx);
+  clib_bihash_kv_16_8_t kv;
+  if (0 == is_add)
+    {
+      nat_6t_flow_to_ed_k (&kv, &s->i2o);
+    }
+  else
+    {
+      nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
+      nat_6t_l3_l4_csum_calc (&s->i2o);
+    }
+  return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
+}
+
+static_always_inline int
+nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
+                                 snat_session_t *s, int is_add)
+{
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_idx);
+  clib_bihash_kv_16_8_t kv;
+  if (0 == is_add)
+    {
+      nat_6t_flow_to_ed_k (&kv, &s->o2i);
+    }
+  else
+    {
+      nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
+      nat_6t_l3_l4_csum_calc (&s->o2i);
+    }
+  return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
+}
+
+always_inline void
+nat_ed_session_delete (snat_main_t *sm, snat_session_t *ses, u32 thread_index,
+                      int lru_delete
+                      /* delete from global LRU list */)
+{
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_index);
+
+  if (lru_delete)
+    {
+      clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+    }
+  pool_put_index (tsm->lru_pool, ses->lru_index);
+  if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, ses, 0))
+    nat_elog_warn (sm, "flow hash del failed");
+  if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, ses, 0))
+    nat_elog_warn (sm, "flow hash del failed");
+  pool_put (tsm->sessions, ses);
+  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
+                          pool_elts (tsm->sessions));
+}
+
+static_always_inline int
+nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now,
+                           u32 head_index)
+{
+  snat_session_t *s = NULL;
+  dlist_elt_t *oldest_elt;
+  f64 sess_timeout_time;
+  u32 oldest_index;
+  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
+  if (~0 != oldest_index)
+    {
+      oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
+      s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
+
+      sess_timeout_time =
+       s->last_heard + (f64) nat44_session_get_timeout (sm, s);
+      if (now >= sess_timeout_time ||
+         (s->tcp_closed_timestamp && now >= s->tcp_closed_timestamp))
+       {
+         nat_free_session_data (sm, s, thread_index, 0);
+         nat_ed_session_delete (sm, s, thread_index, 0);
+         return 1;
+       }
+      else
+       {
+         clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
+       }
+    }
+  return 0;
+}
+
+static_always_inline int
+nat_lru_free_one (snat_main_t *sm, int thread_index, f64 now)
+{
+  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  int rc = 0;
+#define _(p)                                                                  \
+  if ((rc = nat_lru_free_one_with_head (sm, thread_index, now,                \
+                                       tsm->p##_lru_head_index)))            \
+    {                                                                         \
+      return rc;                                                              \
+    }
+  _ (tcp_trans);
+  _ (udp);
+  _ (unk_proto);
+  _ (icmp);
+  _ (tcp_estab);
+#undef _
+  return 0;
+}
+
+static_always_inline snat_session_t *
+nat_ed_session_alloc (snat_main_t *sm, u32 thread_index, f64 now, u8 proto)
+{
+  snat_session_t *s;
+  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+
+  nat_lru_free_one (sm, thread_index, now);
+
+  pool_get (tsm->sessions, s);
+  clib_memset (s, 0, sizeof (*s));
+
+  nat_ed_lru_insert (tsm, s, now, proto);
+
+  s->ha_last_refreshed = now;
+  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
+                          pool_elts (tsm->sessions));
+  return s;
+}
+
+// slow path
+static_always_inline void
+per_vrf_sessions_cleanup (u32 thread_index)
+{
+  snat_main_t *sm = &snat_main;
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_index);
+  per_vrf_sessions_t *per_vrf_sessions;
+  u32 *to_free = 0, *i;
+
+  vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
+    {
+      if (per_vrf_sessions->expired)
+       {
+         if (per_vrf_sessions->ses_count == 0)
+           {
+             vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec);
+           }
+       }
+    }
+
+  if (vec_len (to_free))
+    {
+      vec_foreach (i, to_free)
+       {
+         vec_del1 (tsm->per_vrf_sessions_vec, *i);
+       }
+    }
+
+  vec_free (to_free);
+}
+
+// slow path
+static_always_inline void
+per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index)
+{
+  snat_main_t *sm = &snat_main;
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_index);
+  per_vrf_sessions_t *per_vrf_sessions;
+
+  per_vrf_sessions_cleanup (thread_index);
+
+  // s->per_vrf_sessions_index == ~0 ... reuse of old session
+
+  vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
+    {
+      // ignore already expired registrations
+      if (per_vrf_sessions->expired)
+       continue;
+
+      if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
+         (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
+       {
+         goto done;
+       }
+      if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
+         (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
+       {
+         goto done;
+       }
+    }
+
+  // create a new registration
+  vec_add2 (tsm->per_vrf_sessions_vec, per_vrf_sessions, 1);
+  clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions));
+
+  per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
+  per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
+
+done:
+  s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec;
+  per_vrf_sessions->ses_count++;
+}
+
+// fast path
+static_always_inline void
+per_vrf_sessions_unregister_session (snat_session_t *s, u32 thread_index)
+{
+  snat_main_t *sm = &snat_main;
+  snat_main_per_thread_data_t *tsm;
+  per_vrf_sessions_t *per_vrf_sessions;
+
+  ASSERT (s->per_vrf_sessions_index != ~0);
+
+  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+  per_vrf_sessions =
+    vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
+
+  ASSERT (per_vrf_sessions->ses_count != 0);
+
+  per_vrf_sessions->ses_count--;
+  s->per_vrf_sessions_index = ~0;
+}
+
+// fast path
+static_always_inline u8
+per_vrf_sessions_is_expired (snat_session_t *s, u32 thread_index)
+{
+  snat_main_t *sm = &snat_main;
+  snat_main_per_thread_data_t *tsm;
+  per_vrf_sessions_t *per_vrf_sessions;
+
+  ASSERT (s->per_vrf_sessions_index != ~0);
+
+  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+  per_vrf_sessions =
+    vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
+  return per_vrf_sessions->expired;
+}
+
+static_always_inline void
+nat_6t_flow_init (nat_6t_flow_t *f, u32 thread_idx, ip4_address_t saddr,
+                 u16 sport, ip4_address_t daddr, u16 dport, u32 fib_index,
+                 u8 proto, u32 session_idx)
+{
+  clib_memset (f, 0, sizeof (*f));
+  f->match.saddr = saddr;
+  f->match.sport = sport;
+  f->match.daddr = daddr;
+  f->match.dport = dport;
+  f->match.proto = proto;
+  f->match.fib_index = fib_index;
+}
+
+static_always_inline void
+nat_6t_i2o_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
+                     ip4_address_t saddr, u16 sport, ip4_address_t daddr,
+                     u16 dport, u32 fib_index, u8 proto)
+{
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_idx);
+  nat_6t_flow_init (&s->i2o, thread_idx, saddr, sport, daddr, dport, fib_index,
+                   proto, s - tsm->sessions);
+}
+
+static_always_inline void
+nat_6t_o2i_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
+                     ip4_address_t saddr, u16 sport, ip4_address_t daddr,
+                     u16 dport, u32 fib_index, u8 proto)
+{
+  snat_main_per_thread_data_t *tsm =
+    vec_elt_at_index (sm->per_thread_data, thread_idx);
+  nat_6t_flow_init (&s->o2i, thread_idx, saddr, sport, daddr, dport, fib_index,
+                   proto, s - tsm->sessions);
+}
+
+static_always_inline int
+nat_6t_flow_match (nat_6t_flow_t *f, vlib_buffer_t *b, ip4_address_t saddr,
+                  u16 sport, ip4_address_t daddr, u16 dport, u8 protocol,
+                  u32 fib_index)
+{
+  return f->match.daddr.as_u32 == daddr.as_u32 &&
+        f->match.dport == vnet_buffer (b)->ip.reass.l4_dst_port &&
+        f->match.proto == protocol && f->match.fib_index == fib_index &&
+        f->match.saddr.as_u32 == saddr.as_u32 &&
+        f->match.sport == vnet_buffer (b)->ip.reass.l4_src_port;
+}
+
+static inline uword
+nat_pre_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                       vlib_frame_t *frame, u32 def_next)
+{
+  u32 n_left_from, *from;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+
+  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
+  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
+  vlib_get_buffers (vm, from, b, n_left_from);
+
+  while (n_left_from >= 2)
+    {
+      u32 next0, next1;
+      u32 arc_next0, arc_next1;
+      vlib_buffer_t *b0, *b1;
+
+      b0 = *b;
+      b++;
+      b1 = *b;
+      b++;
+
+      /* Prefetch next iteration. */
+      if (PREDICT_TRUE (n_left_from >= 4))
+       {
+         vlib_buffer_t *p2, *p3;
+
+         p2 = *b;
+         p3 = *(b + 1);
+
+         vlib_prefetch_buffer_header (p2, LOAD);
+         vlib_prefetch_buffer_header (p3, LOAD);
+
+         CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
+       }
+
+      next0 = def_next;
+      next1 = def_next;
+
+      vnet_feature_next (&arc_next0, b0);
+      vnet_feature_next (&arc_next1, b1);
+
+      vnet_buffer2 (b0)->nat.arc_next = arc_next0;
+      vnet_buffer2 (b1)->nat.arc_next = arc_next1;
+
+      if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+       {
+         if (b0->flags & VLIB_BUFFER_IS_TRACED)
+           {
+             nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->next_index = next0;
+             t->arc_next_index = arc_next0;
+           }
+         if (b1->flags & VLIB_BUFFER_IS_TRACED)
+           {
+             nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->next_index = next1;
+             t->arc_next_index = arc_next1;
+           }
+       }
+
+      n_left_from -= 2;
+      next[0] = next0;
+      next[1] = next1;
+      next += 2;
+    }
+
+  while (n_left_from > 0)
+    {
+      u32 next0;
+      u32 arc_next0;
+      vlib_buffer_t *b0;
+
+      b0 = *b;
+      b++;
+
+      next0 = def_next;
+      vnet_feature_next (&arc_next0, b0);
+      vnet_buffer2 (b0)->nat.arc_next = arc_next0;
+
+      if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                        (b0->flags & VLIB_BUFFER_IS_TRACED)))
+       {
+         nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+         t->next_index = next0;
+         t->arc_next_index = arc_next0;
+       }
+
+      n_left_from--;
+      next[0] = next0;
+      next++;
+    }
+  vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
+                              frame->n_vectors);
+
+  return frame->n_vectors;
+}
+
+static_always_inline u16
+snat_random_port (u16 min, u16 max)
+{
+  snat_main_t *sm = &snat_main;
+  u32 rwide;
+  u16 r;
+
+  rwide = random_u32 (&sm->random_seed);
+  r = rwide & 0xFFFF;
+  if (r >= min && r <= max)
+    return r;
+
+  return min + (rwide % (max - min + 1));
+}
+
+always_inline u8
+is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node,
+                  u32 sw_if_index0, u32 ip4_addr)
+{
+  snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
+  ip4_address_t *first_int_addr;
+
+  if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
+    {
+      first_int_addr = ip4_interface_first_address (
+       sm->ip4_main, sw_if_index0, 0 /* just want the address */);
+      rt->cached_sw_if_index = sw_if_index0;
+      if (first_int_addr)
+       rt->cached_ip4_address = first_int_addr->as_u32;
+      else
+       rt->cached_ip4_address = 0;
+    }
+
+  if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
+    return 1;
+  else
+    return 0;
+}
+
+always_inline void
+nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses,
+                                vlib_buffer_t *b, u32 thread_index)
+{
+  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags;
+  u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number;
+  u32 tcp_seq_number = vnet_buffer (b)->ip.reass.tcp_seq_number;
+  if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
+    ses->state = NAT44_SES_RST;
+  if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
+    ses->state = 0;
+  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
+      (ses->state & NAT44_SES_O2I_SYN))
+    ses->state = 0;
+  if (tcp_flags & TCP_FLAG_SYN)
+    ses->state |= NAT44_SES_I2O_SYN;
+  if (tcp_flags & TCP_FLAG_FIN)
+    {
+      ses->i2o_fin_seq = clib_net_to_host_u32 (tcp_seq_number);
+      ses->state |= NAT44_SES_I2O_FIN;
+    }
+  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN))
+    {
+      if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq)
+       {
+         ses->state |= NAT44_SES_O2I_FIN_ACK;
+         if (nat44_is_ses_closed (ses))
+           { // if session is now closed, save the timestamp
+             ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory;
+             ses->last_lru_update = now;
+           }
+       }
+    }
+
+  // move the session to proper LRU
+  if (ses->state)
+    {
+      ses->lru_head_index = tsm->tcp_trans_lru_head_index;
+    }
+  else
+    {
+      ses->lru_head_index = tsm->tcp_estab_lru_head_index;
+    }
+  clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+  clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
+}
+
+always_inline void
+nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses,
+                                u8 tcp_flags, u32 tcp_ack_number,
+                                u32 tcp_seq_number, u32 thread_index)
+{
+  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
+    ses->state = NAT44_SES_RST;
+  if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
+    ses->state = 0;
+  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
+      (ses->state & NAT44_SES_O2I_SYN))
+    ses->state = 0;
+  if (tcp_flags & TCP_FLAG_SYN)
+    ses->state |= NAT44_SES_O2I_SYN;
+  if (tcp_flags & TCP_FLAG_FIN)
+    {
+      ses->o2i_fin_seq = clib_net_to_host_u32 (tcp_seq_number);
+      ses->state |= NAT44_SES_O2I_FIN;
+    }
+  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN))
+    {
+      if (clib_net_to_host_u32 (tcp_ack_number) > ses->i2o_fin_seq)
+       ses->state |= NAT44_SES_I2O_FIN_ACK;
+      if (nat44_is_ses_closed (ses))
+       { // if session is now closed, save the timestamp
+         ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory;
+         ses->last_lru_update = now;
+       }
+    }
+  // move the session to proper LRU
+  if (ses->state)
+    {
+      ses->lru_head_index = tsm->tcp_trans_lru_head_index;
+    }
+  else
+    {
+      ses->lru_head_index = tsm->tcp_estab_lru_head_index;
+    }
+  clib_dlist_remove (tsm->lru_pool, ses->lru_index);
+  clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
+}
+
+always_inline void
+nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes,
+                              u32 thread_index)
+{
+  s->last_heard = now;
+  s->total_pkts++;
+  s->total_bytes += bytes;
+}
+
+/** \brief Per-user LRU list maintenance */
+always_inline void
+nat44_session_update_lru (snat_main_t *sm, snat_session_t *s, u32 thread_index)
+{
+  /* don't update too often - timeout is in magnitude of seconds anyway */
+  if (s->last_heard > s->last_lru_update + 1)
+    {
+      clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
+                        s->lru_index);
+      clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
+                         s->lru_head_index, s->lru_index);
+      s->last_lru_update = s->last_heard;
+    }
+}
+
+#endif /* __included_nat44_ed_inlines_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
similarity index 94%
rename from src/plugins/nat/out2in_ed.c
rename to src/plugins/nat/nat44-ed/nat44_ed_out2in.c
index d6beadc..4d354d3 100644 (file)
 #include <vnet/fib/ip4_fib.h>
 #include <vnet/udp/udp_local.h>
 #include <vppinfra/error.h>
-#include <nat/nat.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44/inlines.h>
+
 #include <nat/lib/nat_syslog.h>
-#include <nat/nat44/ed_inlines.h>
+#include <nat/lib/ipfix_logging.h>
+
+#include <nat/nat44-ed/nat44_ed.h>
+#include <nat/nat44-ed/nat44_ed_inlines.h>
 
 static char *nat_out2in_ed_error_strings[] = {
 #define _(sym,string) string,
@@ -243,6 +243,7 @@ nat_alloc_addr_and_port_exact (snat_address_t * a,
                               u16 * port,
                               u16 port_per_thread, u32 snat_thread_index)
 {
+  snat_main_t *sm = &snat_main;
   u32 portnum;
 
   switch (proto)
@@ -269,8 +270,7 @@ nat_alloc_addr_and_port_exact (snat_address_t * a,
       break;
       foreach_nat_protocol
 #undef _
-    default:
-      nat_elog_info ("unknown protocol");
+       default : nat_elog_info (sm, "unknown protocol");
       return 1;
     }
 
@@ -286,9 +286,10 @@ nat44_ed_alloc_outside_addr_and_port (snat_address_t *addresses, u32 fib_index,
                                      u16 port_per_thread,
                                      u32 snat_thread_index)
 {
-  int i;
+  snat_main_t *sm = &snat_main;
   snat_address_t *a, *ga = 0;
   u32 portnum;
+  int i;
 
   for (i = 0; i < vec_len (addresses); i++)
     {
@@ -323,7 +324,7 @@ nat44_ed_alloc_outside_addr_and_port (snat_address_t *addresses, u32 fib_index,
     break;
          foreach_nat_protocol
 #undef _
-           default : nat_elog_info ("unknown protocol");
+           default : nat_elog_info (sm, "unknown protocol");
          return 1;
        }
     }
@@ -351,7 +352,7 @@ nat44_ed_alloc_outside_addr_and_port (snat_address_t *addresses, u32 fib_index,
          break;
          foreach_nat_protocol
 #undef _
-           default : nat_elog_info ("unknown protocol");
+           default : nat_elog_info (sm, "unknown protocol");
          return 1;
        }
     }
@@ -378,15 +379,15 @@ create_session_for_static_mapping_ed (
       (nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
     {
       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
-      nat_elog_notice ("maximum sessions exceeded");
+      nat_elog_notice (sm, "maximum sessions exceeded");
       return 0;
     }
 
   s = nat_ed_session_alloc (sm, thread_index, now, nat_proto);
   if (!s)
     {
-      b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
-      nat_elog_warn ("create NAT session failed");
+      b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
+      nat_elog_warn (sm, "create NAT session failed");
       return 0;
     }
 
@@ -429,7 +430,7 @@ create_session_for_static_mapping_ed (
     {
       b->error = node->errors[NAT_OUT2IN_ED_ERROR_HASH_ADD_FAILED];
       nat_ed_session_delete (sm, s, thread_index, 1);
-      nat_elog_warn ("out2in flow hash add failed");
+      nat_elog_warn (sm, "out2in flow hash add failed");
       return 0;
     }
 
@@ -477,7 +478,7 @@ create_session_for_static_mapping_ed (
          b->error = node->errors[NAT_OUT2IN_ED_ERROR_OUT_OF_PORTS];
          if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
            {
-             nat_elog_warn ("out2in flow hash del failed");
+             nat_elog_warn (sm, "out2in flow hash del failed");
            }
          snat_free_outside_address_and_port (
            sm->twice_nat_addresses, thread_index, &s->ext_host_nat_addr,
@@ -541,10 +542,10 @@ create_session_for_static_mapping_ed (
 
   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     {
-      nat_elog_notice ("in2out flow hash add failed");
+      nat_elog_notice (sm, "in2out flow hash add failed");
       if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
        {
-         nat_elog_warn ("out2in flow hash del failed");
+         nat_elog_warn (sm, "out2in flow hash del failed");
        }
       nat_ed_session_delete (sm, s, thread_index, 1);
       return 0;
@@ -557,12 +558,11 @@ create_session_for_static_mapping_ed (
                                      s->in2out.port,
                                      s->out2in.port, s->in2out.fib_index);
 
-  nat_syslog_nat44_sadd (s->user_index, s->in2out.fib_index,
-                        &s->in2out.addr, s->in2out.port,
-                        &s->ext_host_nat_addr, s->ext_host_nat_port,
-                        &s->out2in.addr, s->out2in.port,
-                        &s->ext_host_addr, s->ext_host_port,
-                        s->nat_proto, is_twice_nat_session (s));
+  nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr,
+                        s->in2out.port, &s->ext_host_nat_addr,
+                        s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
+                        &s->ext_host_addr, s->ext_host_port, s->nat_proto,
+                        is_twice_nat_session (s));
 
   per_vrf_sessions_register_session (s, thread_index);
 
@@ -635,7 +635,7 @@ create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s,
       s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
       if (!s)
        {
-         nat_elog_warn ("create NAT session failed");
+         nat_elog_warn (sm, "create NAT session failed");
          return;
        }
 
@@ -663,7 +663,7 @@ create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s,
       nat_6t_flow_txfib_rewrite_set (&s->i2o, rx_fib_index);
       if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
        {
-         nat_elog_notice ("in2out flow add failed");
+         nat_elog_notice (sm, "in2out flow add failed");
          nat_ed_session_delete (sm, s, thread_index, 1);
          return;
        }
@@ -700,7 +700,7 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
        nat44_ed_maximum_sessions_exceeded (sm, rx_fib_index, thread_index)))
     {
       b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
-      nat_elog_notice ("maximum sessions exceeded");
+      nat_elog_notice (sm, "maximum sessions exceeded");
       return 0;
     }
 
@@ -717,8 +717,8 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
   s = nat_ed_session_alloc (sm, thread_index, now, ip->protocol);
   if (!s)
     {
-      b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_USER_SESS_EXCEEDED];
-      nat_elog_warn ("create NAT session failed");
+      b->error = node->errors[NAT_OUT2IN_ED_ERROR_MAX_SESSIONS_EXCEEDED];
+      nat_elog_warn (sm, "create NAT session failed");
       return 0;
     }
 
@@ -737,7 +737,7 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
   nat_6t_flow_saddr_rewrite_set (&s->i2o, ip->dst_address.as_u32);
   if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1))
     {
-      nat_elog_notice ("in2out key add failed");
+      nat_elog_notice (sm, "in2out key add failed");
       nat_ed_session_delete (sm, s, thread_index, 1);
       return NULL;
     }
@@ -748,7 +748,7 @@ nat44_ed_out2in_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b,
   nat_6t_flow_txfib_rewrite_set (&s->o2i, m->fib_index);
   if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 1))
     {
-      nat_elog_notice ("out2in flow hash add failed");
+      nat_elog_notice (sm, "out2in flow hash add failed");
       nat_ed_session_delete (sm, s, thread_index, 1);
       return NULL;
     }
@@ -1010,7 +1010,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
       switch (proto0)
        {
        case NAT_PROTOCOL_TCP:
-         vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.tcp,
+         vlib_increment_simple_counter (&sm->counters.fastpath.out2in.tcp,
                                         thread_index, sw_if_index0, 1);
          nat44_set_tcp_session_state_o2i (sm, now, s0,
                                           vnet_buffer (b0)->ip.
@@ -1022,17 +1022,16 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
                                           thread_index);
          break;
        case NAT_PROTOCOL_UDP:
-         vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.udp,
+         vlib_increment_simple_counter (&sm->counters.fastpath.out2in.udp,
                                         thread_index, sw_if_index0, 1);
          break;
        case NAT_PROTOCOL_ICMP:
-         vlib_increment_simple_counter (&sm->counters.fastpath.out2in_ed.icmp,
+         vlib_increment_simple_counter (&sm->counters.fastpath.out2in.icmp,
                                         thread_index, sw_if_index0, 1);
          break;
        case NAT_PROTOCOL_OTHER:
-         vlib_increment_simple_counter (
-           &sm->counters.fastpath.out2in_ed.other, thread_index, sw_if_index0,
-           1);
+         vlib_increment_simple_counter (&sm->counters.fastpath.out2in.other,
+                                        thread_index, sw_if_index0, 1);
          break;
        }
 
@@ -1071,9 +1070,8 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm,
 
       if (next[0] == NAT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.fastpath.
-                                        out2in_ed.drops, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.fastpath.out2in.drops,
+                                        thread_index, sw_if_index0, 1);
        }
 
       n_left_from--;
@@ -1163,9 +1161,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         vlib_increment_simple_counter (&sm->counters.slowpath.
-                                        out2in_ed.other, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.other,
+                                        thread_index, sw_if_index0, 1);
          goto trace0;
        }
 
@@ -1183,9 +1180,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
              goto trace0;
            }
 
-         vlib_increment_simple_counter (&sm->counters.slowpath.
-                                        out2in_ed.icmp, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.icmp,
+                                        thread_index, sw_if_index0, 1);
          goto trace0;
        }
 
@@ -1297,7 +1293,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
 
       if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in_ed.tcp,
+         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.tcp,
                                         thread_index, sw_if_index0, 1);
          nat44_set_tcp_session_state_o2i (sm, now, s0,
                                           vnet_buffer (b0)->ip.
@@ -1310,7 +1306,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
        }
       else
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in_ed.udp,
+         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.udp,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -1347,9 +1343,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm,
 
       if (next[0] == NAT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.
-                                        out2in_ed.drops, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
+                                        thread_index, sw_if_index0, 1);
        }
 
       n_left_from--;
diff --git a/src/plugins/nat/nat44-ei/nat44_ei.api b/src/plugins/nat/nat44-ei/nat44_ei.api
new file mode 100644 (file)
index 0000000..708c20a
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+option version = "1.0.0";
+import "vnet/ip/ip_types.api";
+import "vnet/interface_types.api";
+import "plugins/nat/lib/nat_types.api";
+
+enum nat44_ei_config_flags : u8
+{
+  NAT44_EI_NONE = 0x00,
+  NAT44_EI_STATIC_MAPPING_ONLY = 0x01,
+  NAT44_EI_CONNECTION_TRACKING = 0x02,
+  NAT44_EI_OUT2IN_DPO = 0x04,
+  NAT44_EI_ADDR_ONLY_MAPPING = 0x08,
+  NAT44_EI_IF_INSIDE = 0x10,
+  NAT44_EI_IF_OUTSIDE = 0x20,
+  NAT44_EI_STATIC_MAPPING = 0x40,
+};
+
+/** \brief Enable/disable NAT44 plugin
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param inside_vrf - inside vrf id
+    @param outside_vrf - outside vrf id
+    @param users - maximum number of users per thread
+    @param user_memory - overwrite hash allocation parameter
+    @param sessions - maximum number of sessions per thread
+    @param session_memory - overwrite hash allocation parameter
+    @param user_sessions - maximum number of sessions per user
+    @param enable - true if enable, false if disable
+    @param flags - flag NAT44_EI_IS_STATIC_MAPPING_ONLY,
+                        NAT44_EI_IS_CONNECTION_TRACKING,
+                        NAT44_EI_IS_OUT2IN_DPO
+*/
+autoreply define nat44_ei_plugin_enable_disable {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u32 inside_vrf;
+  u32 outside_vrf;
+  u32 users;
+  u32 user_memory;
+  u32 sessions;
+  u32 session_memory;
+  u32 user_sessions;
+  bool enable;
+  vl_api_nat44_ei_config_flags_t flags;
+};
+
+/** \brief Show NAT44 plugin running config
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_show_running_config
+{
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Show NAT44 plugin running config reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code for the request
+    @param inside_vrf - default inside VRF id
+    @param outside_vrf - outside VRF id
+    @param users - maximum number of users per worker thread
+    @param sessions - maximum number of sessions per worker thread
+    @param user_sessions - maximum number of sessions per user
+    @param user_buckets - number of user hash buckets
+    @param translation_buckets - number of translation hash buckets
+    @param flags - flag NAT44_EI_IS_STATIC_MAPPING_ONLY,
+                        NAT44_EI_IS_CONNECTION_TRACKING,
+                        NAT44_EI_IS_OUT2IN_DPO
+*/
+define nat44_ei_show_running_config_reply
+{
+  option in_progress;
+  u32 context;
+  i32 retval;
+  u32 inside_vrf;
+  u32 outside_vrf;
+  u32 users;
+  u32 sessions;
+  u32 user_sessions;
+  u32 user_buckets;
+  u32 translation_buckets;
+  bool forwarding_enabled;
+  bool ipfix_logging_enabled;
+  vl_api_nat_timeouts_t timeouts;
+  vl_api_nat_log_level_t log_level;
+  vl_api_nat44_ei_config_flags_t flags;
+};
+
+/** \brief Set NAT44 logging level
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param log_level - logging level
+*/
+autoreply define nat44_ei_set_log_level {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+  vl_api_nat_log_level_t log_level;
+};
+
+/** \brief Set NAT workers
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param worker_mask - NAT workers mask
+*/
+autoreply define nat44_ei_set_workers {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u64 worker_mask;
+};
+
+/** \brief Dump NAT workers
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_worker_dump {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT workers details response
+    @param context - sender context, to match reply w/ request
+    @param worker_index - worker index
+    @param lcore_id - lcore ID
+    @param name - worker name
+*/
+define nat44_ei_worker_details {
+  option in_progress;
+  u32 context;
+  u32 worker_index;
+  u32 lcore_id;
+  string name[64];
+};
+
+/** \brief Enable/disable NAT IPFIX logging
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param domain_id - observation domain ID
+    @param src_port - source port number
+    @param enable - true if enable, false if disable
+*/
+autoreply define nat44_ei_ipfix_enable_disable {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u32 domain_id;
+  u16 src_port;
+  bool enable;
+};
+
+/** \brief Set values of timeouts for NAT sessions (seconds)
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param udp - UDP timeout (default 300sec)
+    @param tcp_established - TCP established timeout (default 7440sec)
+    @param tcp_transitory - TCP transitory timeout (default 240sec)
+    @param icmp - ICMP timeout (default 60sec)
+*/
+autoreply define nat44_ei_set_timeouts {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u32 udp;
+  u32 tcp_established;
+  u32 tcp_transitory;
+  u32 icmp;
+};
+
+/** \brief Set address and port assignment algorithm
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param alg - address and port assignment algorithm:
+                 0 - default, 1 - MAP-E, 2 - port range
+                 (see nat44_ei_addr_and_port_alloc_alg_t in nat.h)
+    @param psid_offset - number of offset bits (valid only for MAP-E alg)
+    @param psid_length - length of PSID (valid only for MAP-E alg)
+    @param psid - Port Set Identifier (PSID) value (valid only for MAP-E alg)
+    @param start_port - beginning of the port range
+    @param end_port - end of the port range
+*/
+autoreply define nat44_ei_set_addr_and_port_alloc_alg {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u8 alg;
+  u8 psid_offset;
+  u8 psid_length;
+  u16 psid;
+  u16 start_port;
+  u16 end_port;
+};
+
+/** \brief Get address and port assignment algorithm
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_get_addr_and_port_alloc_alg {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Get address and port assignment algorithm reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code
+    @param alg - address and port assignment algorithm:
+                 0 - default, 1 - MAP-E, 2 - port range
+                 (see nat44_ei_addr_and_port_alloc_alg_t in nat.h)
+    @param psid_offset - number of offset bits (valid only for MAP-E alg)
+    @param psid_length - length of PSID (valid only for MAP-E alg)
+    @param psid - Port Set Identifier (PSID) value (valid only for MAP-E alg)
+    @param start_port - beginning of the port range
+    @param end_port - end of the port range
+*/
+define nat44_ei_get_addr_and_port_alloc_alg_reply {
+  option deprecated;
+  u32 context;
+  i32 retval;
+  u8 alg;
+  u8 psid_offset;
+  u8 psid_length;
+  u16 psid;
+  u16 start_port;
+  u16 end_port;
+};
+
+/** \brief Set TCP MSS rewriting configuration
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param mss_value - MSS value to be used for MSS rewriting
+    @param enable - if true enable MSS rewriting feature else disable
+*/
+autoreply define nat44_ei_set_mss_clamping {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u16 mss_value;
+  bool enable;
+};
+
+/** \brief Get TCP MSS rewriting configuration
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_get_mss_clamping {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Get TCP MSS rewriting configuration reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code
+    @param mss_value - MSS value to be used for MSS rewriting
+    @param enable - if true enable MSS rewriting feature else disable
+*/
+define nat44_ei_get_mss_clamping_reply {
+  option deprecated;
+  u32 context;
+  i32 retval;
+  u16 mss_value;
+  bool enable;
+};
+
+/** \brief Set HA listener (local settings)
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param ip_address - local IP4 address
+    @param port - local UDP port number
+    @param path_mtu - path MTU between local and failover
+*/
+autoreply define nat44_ei_ha_set_listener {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  vl_api_ip4_address_t ip_address;
+  u16 port;
+  u32 path_mtu;
+};
+
+/** \brief Set HA failover (remote settings)
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param ip_address - failover IP4 address
+    @param port - failvoer UDP port number
+    @param session_refresh_interval - number of seconds after which to send
+                                      session counters refresh
+*/
+autoreply define nat44_ei_ha_set_failover {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  vl_api_ip4_address_t ip_address;
+  u16 port;
+  u32 session_refresh_interval;
+};
+
+/** \brief Get HA listener/local configuration
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_ha_get_listener {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Get HA listener/local configuration reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code
+    @param ip_address - local IP4 address
+    @param port - local UDP port number
+    @param path_mtu - Path MTU between local and failover
+*/
+define nat44_ei_ha_get_listener_reply {
+  option deprecated;
+  u32 context;
+  i32 retval;
+  vl_api_ip4_address_t ip_address;
+  u16 port;
+  u32 path_mtu;
+};
+
+/** \brief Get HA failover/remote settings
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_ha_get_failover {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Get HA failover/remote settings reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code
+    @param ip_address - failover IP4 address
+    @param port - failvoer UDP port number
+    @param session_refresh_interval - number of seconds after which to send
+                                      session counters refresh
+*/
+define nat44_ei_ha_get_failover_reply {
+  option deprecated;
+  u32 context;
+  i32 retval;
+  vl_api_ip4_address_t ip_address;
+  u16 port;
+  u32 session_refresh_interval;
+};
+
+/** \brief Flush the current HA data (for testing)
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+autoreply define nat44_ei_ha_flush {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Resync HA (resend existing sessions to new failover)
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param want_resync_event - resync completed event sent to the sender via
+                               nat44_ei_ha_resync_completed_event API message if
+                               non-zero
+    @param pid - sender's pid
+*/
+autoreply define nat44_ei_ha_resync
+{
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u8 want_resync_event;
+  u32 pid;
+};
+
+/** \brief Tell client about a HA resync completion event
+    @param client_index - opaque cookie to identify the sender
+    @param pid - client pid registered to receive notification
+    @param missed_count - number of missed (not ACKed) messages
+*/
+define nat44_ei_ha_resync_completed_event
+{
+  option in_progress;
+  u32 client_index;
+  u32 pid;
+  u32 missed_count;
+};
+
+service {
+  rpc nat44_ei_ha_resync returns nat44_ei_ha_resync_reply events nat44_ei_ha_resync_completed_event;
+};
+
+/** \brief Del NAT44 user
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param ip_address - IPv4 address
+    @param fib_index - FIB index
+*/
+autoreply define nat44_ei_del_user {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  vl_api_ip4_address_t ip_address;
+  u32 fib_index;
+};
+
+/** \brief Add/del NAT44 address range
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param first_ip_address - first IPv4 address
+    @param last_ip_address - last IPv4 address
+    @param vrf_id - VRF id of tenant, ~0 means independent of VRF
+    @param is_add - true if add, false if delete
+
+*/
+autoreply define nat44_ei_add_del_address_range {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  vl_api_ip4_address_t first_ip_address;
+  vl_api_ip4_address_t last_ip_address;
+  u32 vrf_id;
+  bool is_add;
+};
+
+/** \brief Dump NAT44 addresses
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_address_dump {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 address details response
+    @param context - sender context, to match reply w/ request
+    @param ip_address - IPv4 address
+    @param vrf_id - VRF id of tenant, ~0 means independent of VRF
+*/
+define nat44_ei_address_details {
+  option in_progress;
+  u32 context;
+  vl_api_ip4_address_t ip_address;
+  u32 vrf_id;
+};
+
+/** \brief Enable/disable NAT44 feature on the interface
+    @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 flags - flag NAT_IS_INSIDE if interface is inside else
+                   interface is outside
+    @param sw_if_index - software index of the interface
+*/
+autoreply define nat44_ei_interface_add_del_feature {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief Dump interfaces with NAT44 feature
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_interface_dump {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 interface details response
+    @param context - sender context, to match reply w/ request
+    @param sw_if_index - software index of the interface
+    @param flags - flag NAT_IS_INSIDE if interface is inside,
+                   flag NAT_IS_OUTSIDE if interface is outside
+                   and if both flags are set the interface is
+                   both inside and outside
+*/
+define nat44_ei_interface_details {
+  option in_progress;
+  u32 context;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief Enable/disbale NAT44 as an interface output feature (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 flags - flag NAT_IS_INSIDE if interface is inside else
+                   interface is outside
+    @param sw_if_index - software index of the interface
+*/
+autoreply define nat44_ei_interface_add_del_output_feature {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief Dump interfaces with NAT44 output feature
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_interface_output_feature_dump {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 interface with output feature details response
+    @param context - sender context, to match reply w/ request
+    @param flags - flag NAT_IS_INSIDE if interface is inside else
+                   interface is outside
+    @param sw_if_index - software index of the interface
+*/
+define nat44_ei_interface_output_feature_details {
+  option deprecated;
+  u32 context;
+  vl_api_nat44_ei_config_flags_t flags;
+  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
+    @param is_add - true if add, false if delete
+    @param flags - flag NAT44_EI_IS_ADDR_ONLY if address only mapping
+    @param local_ip_address - local IPv4 address
+    @param external_ip_address - external IPv4 address
+    @param protocol - IP protocol, used only if addr_only=0
+    @param local_port - local port number, used only if addr_only=0
+    @param external_port - external port number, used only if addr_only=0
+    @param external_sw_if_index - external interface (if set
+                                  external_ip_address is ignored, ~0 means not
+                                  used)
+    @param vfr_id - VRF ID
+    @param tag - opaque string tag
+*/
+autoreply define nat44_ei_add_del_static_mapping {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_ip4_address_t local_ip_address;
+  vl_api_ip4_address_t external_ip_address;
+  u8 protocol;
+  u16 local_port;
+  u16 external_port;
+  vl_api_interface_index_t external_sw_if_index;
+  u32 vrf_id;
+  string tag[64];
+};
+
+/** \brief Dump NAT44 static mappings
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_static_mapping_dump {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 static mapping details response
+    @param context - sender context, to match reply w/ request
+    @param flags - flag NAT44_EI_IS_ADDR_ONLY if address only mapping,
+    @param local_ip_address - local IPv4 address
+    @param external_ip_address - external IPv4 address
+    @param protocol - IP protocol, valid only if no NAT_ADDR_ONLY flag
+    @param local_port - local port number, valid only if no NAT_ADDR_ONLY flag
+    @param external_port - external port number, valid only if no NAT_ADDR_ONLY flag
+    @param external_sw_if_index - external interface
+    @param vfr_id - VRF ID
+    @param tag - opaque string tag
+*/
+define nat44_ei_static_mapping_details {
+  option in_progress;
+  u32 context;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_ip4_address_t local_ip_address;
+  vl_api_ip4_address_t external_ip_address;
+  u8 protocol;
+  u16 local_port;
+  u16 external_port;
+  vl_api_interface_index_t external_sw_if_index;
+  u32 vrf_id;
+  string tag[64];
+};
+
+/** \brief Add/delete NAT44 identity mapping
+    @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 flags - flag NAT44_EI_IS_ADDR_ONLY if address only mapping
+    @param ip_address - IPv4 address
+    @param protocol - IP protocol
+    @param port - port number
+    @param sw_if_index - interface (if set ip_address is ignored, ~0 means not
+                                    used)
+    @param vfr_id - VRF ID (if ~0 use default VRF)
+    @param tag - opaque string tag
+*/
+autoreply define nat44_ei_add_del_identity_mapping {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_ip4_address_t ip_address;
+  u8 protocol;
+  u16 port;
+  vl_api_interface_index_t sw_if_index;
+  u32 vrf_id;
+  string tag[64];
+};
+
+/** \brief Dump NAT44 identity mappings
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_identity_mapping_dump {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 identity mapping details response
+    @param context - sender context, to match reply w/ request
+    @param flags - flag NAT44_EI_ADDR_ONLY if address only mapping
+    @param ip_address - IPv4 address
+    @param protocol - IP protocol
+    @param port - port number
+    @param sw_if_index - interface
+    @param vfr_id - VRF ID
+    @param tag - opaque string tag
+*/
+define nat44_ei_identity_mapping_details {
+  option deprecated;
+  u32 context;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_ip4_address_t ip_address;
+  u8 protocol;
+  u16 port;
+  vl_api_interface_index_t sw_if_index;
+  u32 vrf_id;
+  string tag[64];
+};
+
+/** \brief Add/delete NAT44 pool address from specific interfce
+    @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
+    @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts
+*/
+autoreply define nat44_ei_add_del_interface_addr {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+  bool is_add;
+  vl_api_interface_index_t sw_if_index;
+  vl_api_nat44_ei_config_flags_t flags;
+};
+
+/** \brief Dump NAT44 pool addresses interfaces
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_interface_addr_dump {
+  option deprecated;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 pool addresses interfaces details response
+    @param context - sender context, to match reply w/ request
+    @param sw_if_index - software index of the interface
+
+*/
+define nat44_ei_interface_addr_details {
+  option deprecated;
+  u32 context;
+  vl_api_interface_index_t sw_if_index;
+};
+
+/** \brief Dump NAT44 users
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_user_dump {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief NAT44 users response
+    @param context - sender context, to match reply w/ request
+    @vrf_id - VRF ID
+    @param ip_address - IPv4 address
+    @param nsessions - number of dynamic sessions
+    @param nstaticsessions - number of static sessions
+*/
+define nat44_ei_user_details {
+  option in_progress;
+  u32 context;
+  u32 vrf_id;
+  vl_api_ip4_address_t ip_address;
+  u32 nsessions;
+  u32 nstaticsessions;
+};
+
+/** \brief NAT44 user's sessions
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param ip_address - IPv4 address of the user to dump
+    @param vrf_id - VRF_ID
+*/
+define nat44_ei_user_session_dump {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  vl_api_ip4_address_t ip_address;
+  u32 vrf_id;
+};
+
+/** \brief NAT44 user's sessions response
+    @param context - sender context, to match reply w/ request
+    @param outside_ip_address - outside IPv4 address
+    @param outside_port - outside port
+    @param inside_ip_address - inside IPv4 address
+    @param inside_port - inside port
+    @param protocol - protocol
+    @param flags - flag NAT_IS_STATIC if session is static
+    @param last_heard - last heard timer
+    @param total_bytes - count of bytes sent through session
+    @param total_pkts - count of pakets sent through session
+    @param ext_host_address - external host IPv4 address
+    @param ext_host_port - external host port
+*/
+define nat44_ei_user_session_details {
+  option in_progress;
+  u32 context;
+  vl_api_ip4_address_t outside_ip_address;
+  u16 outside_port;
+  vl_api_ip4_address_t inside_ip_address;
+  u16 inside_port;
+  u16 protocol;
+  vl_api_nat44_ei_config_flags_t flags;
+  u64 last_heard;
+  u64 total_bytes;
+  u32 total_pkts;
+  vl_api_ip4_address_t ext_host_address;
+  u16 ext_host_port;
+};
+
+/** \brief Delete NAT44 session
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param ip_address - IPv4 address
+    @param protocol - IP protocol
+    @param port - port number
+    @param vfr_id - VRF ID
+    @param flags - flag NAT_IS_INSIDE if interface is inside or
+                   interface is outside,
+                   flag NAT_IS_EXT_HOST_VALID if external host address and
+                   port are valid
+    @param ext_host_address - external host IPv4 address
+    @param ext_host_port - external host port
+*/
+autoreply define nat44_ei_del_session {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  vl_api_ip4_address_t address;
+  u8 protocol;
+  u16 port;
+  u32 vrf_id;
+  vl_api_nat44_ei_config_flags_t flags;
+  vl_api_ip4_address_t ext_host_address;
+  u16 ext_host_port;
+};
+
+/** \brief Enable/disable forwarding for NAT44
+    Forward packets which don't match existing translation
+    or static mapping instead of dropping them.
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param enable - true for enable, false for disable
+*/
+autoreply define nat44_ei_forwarding_enable_disable {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  bool enable;
+};
+
+/** \brief Set NAT handoff frame queue options
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param frame_queue_nelts - number of worker handoff frame queue elements
+*/
+autoreply define nat44_ei_set_fq_options {
+  option in_progress;
+  u32 client_index;
+  u32 context;
+  u32 frame_queue_nelts;
+};
+
+/** \brief Show NAT handoff frame queue options
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define nat44_ei_show_fq_options
+{
+  option in_progress;
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Show NAT handoff frame queue options reply
+    @param context - sender context, to match reply w/ request
+    @param retval - return code for the request
+    @param frame_queue_nelts - number of worker handoff frame queue elements
+*/
+define nat44_ei_show_fq_options_reply
+{
+  option in_progress;
+  u32 context;
+  i32 retval;
+  u32 frame_queue_nelts;
+};
index 02403d0..fdf9070 100644 (file)
  * under the License.
  */
 
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ip/ip4.h>
-#include <vnet/plugin/plugin.h>
-#include <nat/nat.h>
-#include <nat/nat_dpo.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/lib/nat_syslog.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44/inlines.h>
-#include <nat/nat_affinity.h>
+#include <vnet/ip/ip_table.h>
+#include <vnet/ip/reass/ip4_sv_reass.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/ip4_fib.h>
-#include <vnet/ip/reass/ip4_sv_reass.h>
-#include <vppinfra/bihash_16_8.h>
-#include <nat/nat44/ed_inlines.h>
-#include <vnet/ip/ip_table.h>
+#include <vnet/plugin/plugin.h>
+
+// nat lib
+#include <nat/lib/log.h>
+#include <nat/lib/nat_syslog.h>
+#include <nat/lib/nat_inlines.h>
+#include <nat/lib/ipfix_logging.h>
 
+#include <nat/nat44-ei/nat44_ei_dpo.h>
 #include <nat/nat44-ei/nat44_ei_inlines.h>
 #include <nat/nat44-ei/nat44_ei.h>
 
 nat44_ei_main_t nat44_ei_main;
 
-static void nat44_ei_db_free ();
+extern vlib_node_registration_t nat44_ei_hairpinning_node;
+extern vlib_node_registration_t nat44_ei_hairpin_dst_node;
+extern vlib_node_registration_t
+  nat44_ei_in2out_hairpinning_finish_ip4_lookup_node;
+extern vlib_node_registration_t
+  nat44_ei_in2out_hairpinning_finish_interface_output_node;
+
+#define skip_if_disabled()                                                    \
+  do                                                                          \
+    {                                                                         \
+      nat44_ei_main_t *nm = &nat44_ei_main;                                   \
+      if (PREDICT_FALSE (!nm->enabled))                                       \
+       return;                                                               \
+    }                                                                         \
+  while (0)
+
+#define fail_if_enabled()                                                     \
+  do                                                                          \
+    {                                                                         \
+      nat44_ei_main_t *nm = &nat44_ei_main;                                   \
+      if (PREDICT_FALSE (nm->enabled))                                        \
+       {                                                                     \
+         nat44_ei_log_err ("plugin enabled");                                \
+         return 1;                                                           \
+       }                                                                     \
+    }                                                                         \
+  while (0)
+
+#define fail_if_disabled()                                                    \
+  do                                                                          \
+    {                                                                         \
+      nat44_ei_main_t *nm = &nat44_ei_main;                                   \
+      if (PREDICT_FALSE (!nm->enabled))                                       \
+       {                                                                     \
+         nat44_ei_log_err ("plugin disabled");                               \
+         return 1;                                                           \
+       }                                                                     \
+    }                                                                         \
+  while (0)
+
+/* Hook up input features */
+VNET_FEATURE_INIT (ip4_nat_classify, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-classify",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_in2out, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-in2out",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_out2in, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-out2in",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature",
+                              "ip4-dhcp-client-detect"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_in2out_output, static) = {
+  .arc_name = "ip4-output",
+  .node_name = "nat44-ei-in2out-output",
+  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
+                              "ip4-sv-reassembly-output-feature"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_in2out_fast, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-in2out-fast",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_out2in_fast, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-out2in-fast",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature",
+                              "ip4-dhcp-client-detect"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_hairpin_dst, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-hairpin-dst",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-sv-reassembly-feature"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_hairpin_src, static) = {
+  .arc_name = "ip4-output",
+  .node_name = "nat44-ei-hairpin-src",
+  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
+                              "ip4-sv-reassembly-output-feature"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_hairpinning, static) = {
+  .arc_name = "ip4-local",
+  .node_name = "nat44-ei-hairpinning",
+  .runs_before = VNET_FEATURES ("ip4-local-end-of-arc"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_in2out_worker_handoff, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-in2out-worker-handoff",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_out2in_worker_handoff, static) = {
+  .arc_name = "ip4-unicast",
+  .node_name = "nat44-ei-out2in-worker-handoff",
+  .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
+                              "ip4-dhcp-client-detect"),
+};
+VNET_FEATURE_INIT (ip4_nat44_ei_in2out_output_worker_handoff, static) = {
+  .arc_name = "ip4-output",
+  .node_name = "nat44-ei-in2out-output-worker-handoff",
+  .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
+                              "ip4-sv-reassembly-output-feature"),
+};
+
+VLIB_PLUGIN_REGISTER () = {
+  .version = VPP_BUILD_VER,
+  .description = "IPv4 Endpoint-Independent NAT (NAT44 EI)",
+};
+
+#define foreach_nat44_ei_classify_error                                       \
+  _ (NEXT_IN2OUT, "next in2out")                                              \
+  _ (NEXT_OUT2IN, "next out2in")                                              \
+  _ (FRAG_CACHED, "fragment cached")
+
+typedef enum
+{
+#define _(sym, str) NAT44_EI_CLASSIFY_ERROR_##sym,
+  foreach_nat44_ei_classify_error
+#undef _
+    NAT44_EI_CLASSIFY_N_ERROR,
+} nat44_ei_classify_error_t;
 
-static void nat44_ei_db_init (u32 translations, u32 translation_buckets,
-                             u32 user_buckets);
+static char *nat44_ei_classify_error_strings[] = {
+#define _(sym, string) string,
+  foreach_nat44_ei_classify_error
+#undef _
+};
 
-int
-nat44_ei_plugin_enable (nat44_ei_config_t c)
+typedef enum
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
-  snat_main_t *sm = &snat_main;
+  NAT44_EI_CLASSIFY_NEXT_IN2OUT,
+  NAT44_EI_CLASSIFY_NEXT_OUT2IN,
+  NAT44_EI_CLASSIFY_NEXT_DROP,
+  NAT44_EI_CLASSIFY_N_NEXT,
+} nat44_ei_classify_next_t;
 
-  clib_memset (nm, 0, sizeof (*nm));
+typedef struct
+{
+  u8 next_in2out;
+  u8 cached;
+} nat44_ei_classify_trace_t;
 
-  if (!c.users)
-    c.users = 1024;
+void nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len,
+                                  u32 sw_if_index, int is_add);
 
-  if (!c.sessions)
-    c.sessions = 10 * 1024;
+static u8 *
+format_nat44_ei_classify_trace (u8 *s, va_list *args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  nat44_ei_classify_trace_t *t = va_arg (*args, nat44_ei_classify_trace_t *);
+  char *next;
 
-  nm->rconfig = c;
+  if (t->cached)
+    s = format (s, "nat44-ei-classify: fragment cached");
+  else
+    {
+      next = t->next_in2out ? "nat44-ei-in2out" : "nat44-ei-out2in";
+      s = format (s, "nat44-ei-classify: next %s", next);
+    }
 
-  nm->translations = c.sessions;
-  nm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
-  nm->user_buckets = nat_calc_bihash_buckets (c.users);
+  return s;
+}
 
-  // OBSOLETE
+static void nat44_ei_db_free ();
 
-  sm->static_mapping_only = c.static_mapping_only;
-  sm->static_mapping_connection_tracking = c.connection_tracking;
-  sm->out2in_dpo = c.out2in_dpo;
-  sm->forwarding_enabled = 0;
-  sm->mss_clamping = 0;
-  sm->pat = (!c.static_mapping_only ||
-            (c.static_mapping_only && c.connection_tracking));
+static void nat44_ei_db_init (u32 translations, u32 translation_buckets,
+                             u32 user_buckets);
 
-  sm->max_users_per_thread = c.users;
-  sm->max_translations_per_thread = c.sessions;
-  sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
-  sm->max_translations_per_user =
-    c.user_sessions ? c.user_sessions : sm->max_translations_per_thread;
+static void nat44_ei_ip4_add_del_interface_address_cb (
+  ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address,
+  u32 address_length, u32 if_address_index, u32 is_delete);
 
-  sm->inside_vrf_id = c.inside_vrf;
-  sm->inside_fib_index = fib_table_find_or_create_and_lock (
-    FIB_PROTOCOL_IP4, c.inside_vrf, sm->fib_src_hi);
+static void nat44_ei_ip4_add_del_addr_only_sm_cb (
+  ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address,
+  u32 address_length, u32 if_address_index, u32 is_delete);
 
-  sm->outside_vrf_id = c.outside_vrf;
-  sm->outside_fib_index = fib_table_find_or_create_and_lock (
-    FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi);
+static void nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque,
+                                        u32 sw_if_index, u32 new_fib_index,
+                                        u32 old_fib_index);
 
-  sm->worker_in2out_cb = nat44_ei_get_in2out_worker_index;
-  sm->worker_out2in_cb = nat44_ei_get_out2in_worker_index;
+void
+nat44_ei_set_node_indexes (nat44_ei_main_t *nm, vlib_main_t *vm)
+{
+  vlib_node_t *node;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-out2in");
+  nm->out2in_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-in2out");
+  nm->in2out_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-in2out-output");
+  nm->in2out_output_node_index = node->index;
+}
 
-  sm->in2out_node_index = sm->ei_in2out_node_index;
-  sm->out2in_node_index = sm->ei_out2in_node_index;
+int
+nat44_ei_set_workers (uword *bitmap)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  int i, j = 0;
 
-  sm->in2out_output_node_index = sm->ei_in2out_output_node_index;
+  if (nm->num_workers < 2)
+    return VNET_API_ERROR_FEATURE_DISABLED;
 
-  if (sm->pat)
-    {
-      sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
-      sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
-    }
-  else
+  if (clib_bitmap_last_set (bitmap) >= nm->num_workers)
+    return VNET_API_ERROR_INVALID_WORKER;
+
+  vec_free (nm->workers);
+  clib_bitmap_foreach (i, bitmap)
     {
-      sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
-      sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
+      vec_add1 (nm->workers, i);
+      nm->per_thread_data[nm->first_worker_index + i].snat_thread_index = j;
+      nm->per_thread_data[nm->first_worker_index + i].thread_index = i;
+      j++;
     }
 
-  nat_reset_timeouts (&sm->timeouts);
-  nat44_ei_db_init (nm->translations, nm->translation_buckets,
-                   nm->user_buckets);
-  nat44_ei_set_alloc_default ();
-  nat_ha_enable ();
-
-  // TODO: function for reset counters
-  vlib_zero_simple_counter (&sm->total_users, 0);
-  vlib_zero_simple_counter (&sm->total_sessions, 0);
-  vlib_zero_simple_counter (&sm->user_limit_reached, 0);
+  nm->port_per_thread = (0xffff - 1024) / _vec_len (nm->workers);
 
-  if (!sm->frame_queue_nelts)
-    sm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
+  return 0;
+}
 
-  sm->enabled = 1;
+#define nat_validate_simple_counter(c, i)                                     \
+  do                                                                          \
+    {                                                                         \
+      vlib_validate_simple_counter (&c, i);                                   \
+      vlib_zero_simple_counter (&c, i);                                       \
+    }                                                                         \
+  while (0);
+
+#define nat_init_simple_counter(c, n, sn)                                     \
+  do                                                                          \
+    {                                                                         \
+      c.name = n;                                                             \
+      c.stat_segment_name = sn;                                               \
+      nat_validate_simple_counter (c, 0);                                     \
+    }                                                                         \
+  while (0);
 
-  return 0;
+static_always_inline void
+nat_validate_interface_counters (nat44_ei_main_t *nm, u32 sw_if_index)
+{
+#define _(x)                                                                  \
+  nat_validate_simple_counter (nm->counters.fastpath.in2out.x, sw_if_index);  \
+  nat_validate_simple_counter (nm->counters.fastpath.out2in.x, sw_if_index);  \
+  nat_validate_simple_counter (nm->counters.slowpath.in2out.x, sw_if_index);  \
+  nat_validate_simple_counter (nm->counters.slowpath.out2in.x, sw_if_index);
+  foreach_nat_counter;
+#undef _
+  nat_validate_simple_counter (nm->counters.hairpinning, sw_if_index);
 }
 
-int
-nat44_ei_plugin_disable ()
+clib_error_t *
+nat44_ei_init (vlib_main_t *vm)
 {
   nat44_ei_main_t *nm = &nat44_ei_main;
-  snat_main_t *sm = &snat_main;
-  snat_interface_t *i, *vec;
-  int error = 0;
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
+  vlib_thread_registration_t *tr;
+  ip4_add_del_interface_address_callback_t cbi = { 0 };
+  ip4_table_bind_callback_t cbt = { 0 };
+  u32 i, num_threads = 0;
+  uword *p, *bitmap = 0;
 
-  // first unregister all nodes from interfaces
-  vec = vec_dup (sm->interfaces);
-  vec_foreach (i, vec)
-    {
-      if (nat_interface_is_inside (i))
-       error = snat_interface_add_del (i->sw_if_index, 1, 1);
-      if (nat_interface_is_outside (i))
-       error = snat_interface_add_del (i->sw_if_index, 0, 1);
+  clib_memset (nm, 0, sizeof (*nm));
 
-      if (error)
+  // required
+  nm->vnet_main = vnet_get_main ();
+  // convenience
+  nm->ip4_main = &ip4_main;
+  nm->api_main = vlibapi_get_main ();
+  nm->ip4_lookup_main = &ip4_main.lookup_main;
+
+  // handoff stuff
+  nm->fq_out2in_index = ~0;
+  nm->fq_in2out_index = ~0;
+  nm->fq_in2out_output_index = ~0;
+  nm->worker_in2out_cb = nat44_ei_get_in2out_worker_index;
+  nm->worker_out2in_cb = nat44_ei_get_out2in_worker_index;
+
+  nm->log_level = NAT_LOG_ERROR;
+
+  nat44_ei_set_node_indexes (nm, vm);
+  nm->log_class = vlib_log_register_class ("nat44-ei", 0);
+
+  nat_init_simple_counter (nm->total_users, "total-users",
+                          "/nat44-ei/total-users");
+  nat_init_simple_counter (nm->total_sessions, "total-sessions",
+                          "/nat44-ei/total-sessions");
+  nat_init_simple_counter (nm->user_limit_reached, "user-limit-reached",
+                          "/nat44-ei/user-limit-reached");
+
+#define _(x)                                                                  \
+  nat_init_simple_counter (nm->counters.fastpath.in2out.x, #x,                \
+                          "/nat44-ei/in2out/fastpath/" #x);                  \
+  nat_init_simple_counter (nm->counters.fastpath.out2in.x, #x,                \
+                          "/nat44-ei/out2in/fastpath/" #x);                  \
+  nat_init_simple_counter (nm->counters.slowpath.in2out.x, #x,                \
+                          "/nat44-ei/in2out/slowpath/" #x);                  \
+  nat_init_simple_counter (nm->counters.slowpath.out2in.x, #x,                \
+                          "/nat44-ei/out2in/slowpath/" #x);
+  foreach_nat_counter;
+#undef _
+  nat_init_simple_counter (nm->counters.hairpinning, "hairpinning",
+                          "/nat44-ei/hairpinning");
+
+  p = hash_get_mem (tm->thread_registrations_by_name, "workers");
+  if (p)
+    {
+      tr = (vlib_thread_registration_t *) p[0];
+      if (tr)
        {
-         nat_log_err ("error occurred while removing interface %u",
-                      i->sw_if_index);
+         nm->num_workers = tr->count;
+         nm->first_worker_index = tr->first_index;
        }
     }
-  vec_free (vec);
-  sm->interfaces = 0;
+  num_threads = tm->n_vlib_mains - 1;
+  nm->port_per_thread = 0xffff - 1024;
+  vec_validate (nm->per_thread_data, num_threads);
 
-  vec = vec_dup (sm->output_feature_interfaces);
-  vec_foreach (i, vec)
+  /* Use all available workers by default */
+  if (nm->num_workers > 1)
     {
-      if (nat_interface_is_inside (i))
-       error = snat_interface_add_del_output_feature (i->sw_if_index, 1, 1);
-      if (nat_interface_is_outside (i))
-       error = snat_interface_add_del_output_feature (i->sw_if_index, 0, 1);
 
-      if (error)
-       {
-         nat_log_err ("error occurred while removing interface %u",
-                      i->sw_if_index);
-       }
+      for (i = 0; i < nm->num_workers; i++)
+       bitmap = clib_bitmap_set (bitmap, i, 1);
+      nat44_ei_set_workers (bitmap);
+      clib_bitmap_free (bitmap);
     }
-  vec_free (vec);
-  sm->output_feature_interfaces = 0;
+  else
+    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;
+  vec_add1 (nm->ip4_main->add_del_interface_address_callbacks, cbi);
+  cbi.function = nat44_ei_ip4_add_del_addr_only_sm_cb;
+  vec_add1 (nm->ip4_main->add_del_interface_address_callbacks, cbi);
+
+  /* callbacks to call when interface to table biding changes */
+  cbt.function = nat44_ei_update_outside_fib;
+  vec_add1 (nm->ip4_main->table_bind_callbacks, cbt);
+
+  nm->fib_src_low = fib_source_allocate (
+    "nat44-ei-low", FIB_SOURCE_PRIORITY_LOW, FIB_SOURCE_BH_SIMPLE);
+  nm->fib_src_hi = fib_source_allocate ("nat44-ei-hi", FIB_SOURCE_PRIORITY_HI,
+                                       FIB_SOURCE_BH_SIMPLE);
+
+  // used only by out2in-dpo feature
+  nat_dpo_module_init ();
+  nat_ha_init (vm, nm->num_workers, num_threads);
+
+  nm->hairpinning_fq_index =
+    vlib_frame_queue_main_init (nat44_ei_hairpinning_node.index, 0);
+  nm->hairpin_dst_fq_index =
+    vlib_frame_queue_main_init (nat44_ei_hairpin_dst_node.index, 0);
+  nm->in2out_hairpinning_finish_ip4_lookup_node_fq_index =
+    vlib_frame_queue_main_init (
+      nat44_ei_in2out_hairpinning_finish_ip4_lookup_node.index, 0);
+  nm->in2out_hairpinning_finish_interface_output_node_fq_index =
+    vlib_frame_queue_main_init (
+      nat44_ei_in2out_hairpinning_finish_interface_output_node.index, 0);
+  return nat44_ei_api_hookup (vm);
+}
 
-  nat_ha_disable ();
-  nat44_ei_db_free ();
+VLIB_INIT_FUNCTION (nat44_ei_init);
 
-  nat44_addresses_free (&sm->addresses);
-  nat44_addresses_free (&sm->twice_nat_addresses);
+int
+nat44_ei_plugin_enable (nat44_ei_config_t c)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
-  vec_free (sm->to_resolve);
-  vec_free (sm->auto_add_sw_if_indices);
-  vec_free (sm->auto_add_sw_if_indices_twice_nat);
+  fail_if_enabled ();
 
-  sm->to_resolve = 0;
-  sm->auto_add_sw_if_indices = 0;
-  sm->auto_add_sw_if_indices_twice_nat = 0;
+  if (!c.users)
+    c.users = 1024;
 
-  sm->forwarding_enabled = 0;
+  if (!c.sessions)
+    c.sessions = 10 * 1024;
 
-  sm->enabled = 0;
-  clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
-  clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig));
+  nm->rconfig = c;
 
-  return error;
-}
+  if (!nm->frame_queue_nelts)
+    nm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
 
-void
-nat44_ei_free_session_data (snat_main_t *sm, snat_session_t *s,
-                           u32 thread_index, u8 is_ha)
-{
-  clib_bihash_kv_8_8_t kv;
+  nm->translations = c.sessions;
+  nm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
+  nm->user_buckets = nat_calc_bihash_buckets (c.users);
 
-  init_nat_i2o_k (&kv, s);
-  if (clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0))
-    nat_elog_warn ("in2out key del failed");
+  nm->pat = (!c.static_mapping_only ||
+            (c.static_mapping_only && c.connection_tracking));
 
-  init_nat_o2i_k (&kv, s);
-  if (clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0))
-    nat_elog_warn ("out2in key del failed");
+  nm->static_mapping_only = c.static_mapping_only;
+  nm->static_mapping_connection_tracking = c.connection_tracking;
+  nm->out2in_dpo = c.out2in_dpo;
+  nm->forwarding_enabled = 0;
+  nm->mss_clamping = 0;
 
-  if (!is_ha)
-    {
-      nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
-                              &s->in2out.addr, s->in2out.port,
-                              &s->out2in.addr, s->out2in.port, s->nat_proto);
+  nm->max_users_per_thread = c.users;
+  nm->max_translations_per_thread = c.sessions;
+  nm->max_translations_per_user =
+    c.user_sessions ? c.user_sessions : nm->max_translations_per_thread;
 
-      nat_ipfix_logging_nat44_ses_delete (
-       thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
-       s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+  nm->inside_vrf_id = c.inside_vrf;
+  nm->inside_fib_index = fib_table_find_or_create_and_lock (
+    FIB_PROTOCOL_IP4, c.inside_vrf, nm->fib_src_hi);
 
-      nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
-                  s->ext_host_port, s->nat_proto, s->out2in.fib_index,
-                  thread_index);
-    }
+  nm->outside_vrf_id = c.outside_vrf;
+  nm->outside_fib_index = fib_table_find_or_create_and_lock (
+    FIB_PROTOCOL_IP4, c.outside_vrf, nm->fib_src_hi);
 
-  if (snat_is_session_static (s))
-    return;
+  nat_reset_timeouts (&nm->timeouts);
+  nat44_ei_db_init (nm->translations, nm->translation_buckets,
+                   nm->user_buckets);
+  nat44_ei_set_alloc_default ();
 
-  snat_free_outside_address_and_port (sm->addresses, thread_index,
-                                     &s->out2in.addr, s->out2in.port,
-                                     s->nat_proto);
-}
+  // TODO: zero simple counter for all counters missing
 
-static_always_inline void
-nat44_ei_user_del_sessions (snat_user_t *u, u32 thread_index)
-{
-  dlist_elt_t *elt;
-  snat_session_t *s;
+  vlib_zero_simple_counter (&nm->total_users, 0);
+  vlib_zero_simple_counter (&nm->total_sessions, 0);
+  vlib_zero_simple_counter (&nm->user_limit_reached, 0);
 
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  nat_ha_enable ();
+  nm->enabled = 1;
 
-  // get head
-  elt =
-    pool_elt_at_index (tsm->list_pool, u->sessions_per_user_list_head_index);
-  // get first element
-  elt = pool_elt_at_index (tsm->list_pool, elt->next);
+  return 0;
+}
 
-  while (elt->value != ~0)
+void
+nat44_ei_addresses_free (nat44_ei_address_t **addresses)
+{
+  nat44_ei_address_t *ap;
+  vec_foreach (ap, *addresses)
     {
-      s = pool_elt_at_index (tsm->sessions, elt->value);
-      elt = pool_elt_at_index (tsm->list_pool, elt->next);
-
-      nat44_ei_free_session_data (sm, s, thread_index, 0);
-      nat44_delete_session (sm, s, thread_index);
+#define _(N, i, n, s) vec_free (ap->busy_##n##_ports_per_thread);
+      foreach_nat_protocol
+#undef _
     }
+  vec_free (*addresses);
+  *addresses = 0;
 }
 
 int
-nat44_ei_user_del (ip4_address_t *addr, u32 fib_index)
+nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
 {
-  int rv = 1;
+  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);
 
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
+  fail_if_disabled ();
 
-  snat_user_key_t user_key;
-  clib_bihash_kv_8_8_t kv, value;
+  if (nm->out2in_dpo && !is_inside)
+    {
+      nat44_ei_log_err ("error unsupported");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
 
-  if (sm->endpoint_dependent)
-    return rv;
+  pool_foreach (i, nm->output_feature_interfaces)
+    {
+      if (i->sw_if_index == sw_if_index)
+       {
+         nat44_ei_log_err ("error interface already configured");
+         return VNET_API_ERROR_VALUE_EXIST;
+       }
+    }
 
-  user_key.addr.as_u32 = addr->as_u32;
-  user_key.fib_index = fib_index;
-  kv.key = user_key.as_u64;
+  if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking))
+    feature_name = is_inside ? "nat44-ei-in2out-fast" : "nat44-ei-out2in-fast";
+  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";
+    }
 
-  if (sm->num_workers > 1)
+  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);
+
+  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);
+
+  if (!is_inside)
     {
-      vec_foreach (tsm, sm->per_thread_data)
+      vec_foreach (outside_fib, nm->outside_fibs)
        {
-         if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+         if (outside_fib->fib_index == fib_index)
            {
-             nat44_ei_user_del_sessions (
-               pool_elt_at_index (tsm->users, value.value),
-               tsm->thread_index);
-             rv = 0;
-             break;
+             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;
            }
        }
-    }
-  else
-    {
-      tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
-      if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+      if (!is_del)
        {
-         nat44_ei_user_del_sessions (
-           pool_elt_at_index (tsm->users, value.value), tsm->thread_index);
-         rv = 0;
+         vec_add2 (nm->outside_fibs, outside_fib, 1);
+         outside_fib->refcount = 1;
+         outside_fib->fib_index = fib_index;
        }
     }
-  return rv;
-}
-
-void
-nat44_ei_static_mapping_del_sessions (snat_main_t *sm,
-                                     snat_main_per_thread_data_t *tsm,
-                                     snat_user_key_t u_key, int addr_only,
-                                     ip4_address_t e_addr, u16 e_port)
-{
-  clib_bihash_kv_8_8_t kv, value;
-  kv.key = u_key.as_u64;
-  u64 user_index;
-  dlist_elt_t *head, *elt;
-  snat_user_t *u;
-  snat_session_t *s;
-  u32 elt_index, head_index, ses_index;
 
-  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+feature_set:
+  pool_foreach (i, nm->interfaces)
     {
-      user_index = value.value;
-      u = pool_elt_at_index (tsm->users, user_index);
-      if (u->nstaticsessions)
+      if (i->sw_if_index == sw_if_index)
        {
-         head_index = u->sessions_per_user_list_head_index;
-         head = pool_elt_at_index (tsm->list_pool, head_index);
-         elt_index = head->next;
-         elt = pool_elt_at_index (tsm->list_pool, elt_index);
-         ses_index = elt->value;
-         while (ses_index != ~0)
+         if (is_del)
            {
-             s = pool_elt_at_index (tsm->sessions, ses_index);
-             elt = pool_elt_at_index (tsm->list_pool, elt->next);
-             ses_index = elt->value;
-
-             if (!addr_only)
+             if (nat44_ei_interface_is_inside (i) &&
+                 nat44_ei_interface_is_outside (i))
                {
-                 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
-                     (s->out2in.port != e_port))
-                   continue;
-               }
+                 if (is_inside)
+                   i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+                 else
+                   i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
 
-             if (is_lb_session (s))
-               continue;
+                 if (nm->num_workers > 1)
+                   {
+                     del_feature_name = "nat44-handoff-classify";
+                     feature_name = !is_inside ?
+                                      "nat44-ei-in2out-worker-handoff" :
+                                      "nat44-ei-out2in-worker-handoff";
+                   }
+                 else
+                   {
+                     del_feature_name = "nat44-ei-classify";
+                     feature_name =
+                       !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+                   }
 
-             if (!snat_is_session_static (s))
-               continue;
+                 int rv =
+                   ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+                 if (rv)
+                   return rv;
+                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
+                                              sw_if_index, 0, 0, 0);
+                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                              sw_if_index, 1, 0, 0);
+                 if (!is_inside)
+                   {
+                     vnet_feature_enable_disable ("ip4-local",
+                                                  "nat44-ei-hairpinning",
+                                                  sw_if_index, 1, 0, 0);
+                   }
+               }
+             else
+               {
+                 int rv =
+                   ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+                 if (rv)
+                   return rv;
+                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                              sw_if_index, 0, 0, 0);
+                 pool_put (nm->interfaces, i);
+                 if (is_inside)
+                   {
+                     vnet_feature_enable_disable ("ip4-local",
+                                                  "nat44-ei-hairpinning",
+                                                  sw_if_index, 0, 0, 0);
+                   }
+               }
+           }
+         else
+           {
+             if ((nat44_ei_interface_is_inside (i) && is_inside) ||
+                 (nat44_ei_interface_is_outside (i) && !is_inside))
+               return 0;
 
-             nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
-             nat44_delete_session (sm, s, tsm - sm->per_thread_data);
+             if (nm->num_workers > 1)
+               {
+                 del_feature_name = !is_inside ?
+                                      "nat44-ei-in2out-worker-handoff" :
+                                      "nat44-ei-out2in-worker-handoff";
+                 feature_name = "nat44-handoff-classify";
+               }
+             else
+               {
+                 del_feature_name =
+                   !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+                 feature_name = "nat44-ei-classify";
+               }
 
-             if (!addr_only)
-               break;
+             int rv =
+               ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+             if (rv)
+               return rv;
+             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
+                                          sw_if_index, 0, 0, 0);
+             vnet_feature_enable_disable ("ip4-unicast", feature_name,
+                                          sw_if_index, 1, 0, 0);
+             if (!is_inside)
+               {
+                 vnet_feature_enable_disable (
+                   "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
+               }
+             goto set_flags;
            }
+
+         goto fib;
        }
     }
-}
 
-u32
-nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
-                                 u8 is_output)
-{
-  snat_main_t *sm = &snat_main;
-  u32 next_worker_index = 0;
-  u32 hash;
+  if (is_del)
+    {
+      nat44_ei_log_err ("error interface couldn't be found");
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
 
-  next_worker_index = sm->first_worker_index;
-  hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
-        (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
+  pool_get (nm->interfaces, i);
+  i->sw_if_index = sw_if_index;
+  i->flags = 0;
+  nat_validate_interface_counters (nm, sw_if_index);
 
-  if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
-    next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
-  else
-    next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
+  vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
+                              0);
 
-  return next_worker_index;
-}
+  int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+  if (rv)
+    return rv;
 
-u32
-nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
-                                 u32 rx_fib_index0, u8 is_output)
-{
-  snat_main_t *sm = &snat_main;
-  udp_header_t *udp;
-  u16 port;
-  clib_bihash_kv_8_8_t kv, value;
-  snat_static_mapping_t *m;
-  u32 proto;
-  u32 next_worker_index = 0;
+  if (is_inside && !nm->out2in_dpo)
+    {
+      vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning",
+                                  sw_if_index, 1, 0, 0);
+    }
 
-  /* first try static mappings without port */
-  if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
+set_flags:
+  if (is_inside)
     {
-      init_nat_k (&kv, ip0->dst_address, 0, rx_fib_index0, 0);
-      if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
-                                  &value))
-       {
-         m = pool_elt_at_index (sm->static_mappings, value.value);
-         return m->workers[0];
-       }
+      i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+      return 0;
     }
+  else
+    i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
 
-  proto = ip_proto_to_nat_proto (ip0->protocol);
-  udp = ip4_next_header (ip0);
-  port = udp->dst_port;
+  /* 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);
 
-  /* unknown protocol */
-  if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
+  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);
+    }
+
+  return 0;
+}
+
+int
+nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside,
+                                          int is_del)
+{
+  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);
+
+  fail_if_disabled ();
+
+  if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking))
+    {
+      nat44_ei_log_err ("error unsupported");
+      return VNET_API_ERROR_UNSUPPORTED;
+    }
+
+  pool_foreach (i, nm->interfaces)
+    {
+      if (i->sw_if_index == sw_if_index)
+       {
+         nat44_ei_log_err ("error interface already configured");
+         return VNET_API_ERROR_VALUE_EXIST;
+       }
+    }
+
+  if (!is_inside)
+    {
+      vec_foreach (outside_fib, nm->outside_fibs)
+       {
+         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;
+           }
+       }
+      if (!is_del)
+       {
+         vec_add2 (nm->outside_fibs, outside_fib, 1);
+         outside_fib->refcount = 1;
+         outside_fib->fib_index = fib_index;
+       }
+    }
+
+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);
+      if (rv)
+       return rv;
+      vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-hairpin-dst",
+                                  sw_if_index, !is_del, 0, 0);
+      vnet_feature_enable_disable ("ip4-output", "nat44-ei-hairpin-src",
+                                  sw_if_index, !is_del, 0, 0);
+      goto fq;
+    }
+
+  if (nm->num_workers > 1)
+    {
+      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);
+      if (rv)
+       return rv;
+      vnet_feature_enable_disable ("ip4-unicast",
+                                  "nat44-ei-out2in-worker-handoff",
+                                  sw_if_index, !is_del, 0, 0);
+      vnet_feature_enable_disable ("ip4-output",
+                                  "nat44-ei-in2out-output-worker-handoff",
+                                  sw_if_index, !is_del, 0, 0);
+    }
+  else
+    {
+      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);
+      if (rv)
+       return rv;
+      vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
+                                  sw_if_index, !is_del, 0, 0);
+      vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
+                                  sw_if_index, !is_del, 0, 0);
+    }
+
+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);
+
+  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_foreach (i, nm->output_feature_interfaces)
+    {
+      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;
+       }
+    }
+
+  if (is_del)
+    {
+      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;
+  else
+    i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+
+  /* Add/delete external addresses to FIB */
+fib:
+  if (is_inside)
+    return 0;
+
+  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);
+    }
+
+  return 0;
+}
+
+int
+nat44_ei_plugin_disable ()
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i, *vec;
+  int error = 0;
+
+  // first unregister all nodes from interfaces
+  vec = vec_dup (nm->interfaces);
+  vec_foreach (i, vec)
+    {
+      if (nat44_ei_interface_is_inside (i))
+       error = nat44_ei_interface_add_del (i->sw_if_index, 1, 1);
+      if (nat44_ei_interface_is_outside (i))
+       error = nat44_ei_interface_add_del (i->sw_if_index, 0, 1);
+
+      if (error)
+       {
+         nat44_ei_log_err ("error occurred while removing interface %u",
+                           i->sw_if_index);
+       }
+    }
+  vec_free (vec);
+  nm->interfaces = 0;
+
+  vec = vec_dup (nm->output_feature_interfaces);
+  vec_foreach (i, vec)
+    {
+      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);
+
+      if (error)
+       {
+         nat44_ei_log_err ("error occurred while removing interface %u",
+                           i->sw_if_index);
+       }
+    }
+  vec_free (vec);
+  nm->output_feature_interfaces = 0;
+
+  nat_ha_disable ();
+  nat44_ei_db_free ();
+
+  nat44_ei_addresses_free (&nm->addresses);
+
+  vec_free (nm->to_resolve);
+  vec_free (nm->auto_add_sw_if_indices);
+
+  nm->to_resolve = 0;
+  nm->auto_add_sw_if_indices = 0;
+
+  nm->forwarding_enabled = 0;
+
+  nm->enabled = 0;
+  clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
+
+  return error;
+}
+
+int
+nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
+                                      u32 thread_index, ip4_address_t addr,
+                                      u16 port, nat_protocol_t protocol)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a = 0;
+  u32 address_index;
+  u16 port_host_byte_order = clib_net_to_host_u16 (port);
+
+  for (address_index = 0; address_index < vec_len (addresses); address_index++)
+    {
+      if (addresses[address_index].addr.as_u32 != addr.as_u32)
+       continue;
+
+      a = addresses + address_index;
+      switch (protocol)
+       {
+#define _(N, j, n, s)                                                         \
+  case NAT_PROTOCOL_##N:                                                      \
+    if (a->busy_##n##_port_refcounts[port_host_byte_order])                   \
+      return VNET_API_ERROR_INSTANCE_IN_USE;                                  \
+    ++a->busy_##n##_port_refcounts[port_host_byte_order];                     \
+    a->busy_##n##_ports_per_thread[thread_index]++;                           \
+    a->busy_##n##_ports++;                                                    \
+    return 0;
+         foreach_nat_protocol
+#undef _
+           default : nat_elog_info (nm, "unknown protocol");
+         return 1;
+       }
+    }
+
+  return VNET_API_ERROR_NO_SUCH_ENTRY;
+}
+
+void
+nat44_ei_add_del_address_dpo (ip4_address_t addr, u8 is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  dpo_id_t dpo_v4 = DPO_INVALID;
+  fib_prefix_t pfx = {
+    .fp_proto = FIB_PROTOCOL_IP4,
+    .fp_len = 32,
+    .fp_addr.ip4.as_u32 = addr.as_u32,
+  };
+
+  if (is_add)
+    {
+      nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
+      fib_table_entry_special_dpo_add (0, &pfx, nm->fib_src_hi,
+                                      FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
+      dpo_reset (&dpo_v4);
+    }
+  else
+    {
+      fib_table_entry_special_remove (0, &pfx, nm->fib_src_hi);
+    }
+}
+
+void
+nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses,
+                                       u32 thread_index, ip4_address_t *addr,
+                                       u16 port, nat_protocol_t protocol)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a;
+  u32 address_index;
+  u16 port_host_byte_order = clib_net_to_host_u16 (port);
+
+  for (address_index = 0; address_index < vec_len (addresses); address_index++)
+    {
+      if (addresses[address_index].addr.as_u32 == addr->as_u32)
+       break;
+    }
+
+  ASSERT (address_index < vec_len (addresses));
+
+  a = addresses + address_index;
+
+  switch (protocol)
+    {
+#define _(N, i, n, s)                                                         \
+  case NAT_PROTOCOL_##N:                                                      \
+    ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1);         \
+    --a->busy_##n##_port_refcounts[port_host_byte_order];                     \
+    a->busy_##n##_ports--;                                                    \
+    a->busy_##n##_ports_per_thread[thread_index]--;                           \
+    break;
+      foreach_nat_protocol
+#undef _
+       default : nat_elog_info (nm, "unknown protocol");
+      return;
+    }
+}
+
+void
+nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s,
+                              u32 thread_index, u8 is_ha)
+{
+  clib_bihash_kv_8_8_t kv;
+
+  /* session lookup tables */
+  init_nat_i2o_k (&kv, s);
+  if (clib_bihash_add_del_8_8 (&nm->in2out, &kv, 0))
+    nat_elog_warn (nm, "in2out key del failed");
+  init_nat_o2i_k (&kv, s);
+  if (clib_bihash_add_del_8_8 (&nm->out2in, &kv, 0))
+    nat_elog_warn (nm, "out2in key del failed");
+
+  if (!is_ha)
+    nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
+                            &s->in2out.addr, s->in2out.port, &s->out2in.addr,
+                            s->out2in.port, s->nat_proto);
+
+  if (nat44_ei_is_unk_proto_session (s))
+    return;
+
+  if (!is_ha)
+    {
+      /* log NAT event */
+      nat_ipfix_logging_nat44_ses_delete (
+       thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
+       s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+
+      nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
+                  s->ext_host_port, s->nat_proto, s->out2in.fib_index,
+                  thread_index);
+    }
+
+  if (nat44_ei_is_session_static (s))
+    return;
+
+  nat44_ei_free_outside_address_and_port (nm->addresses, thread_index,
+                                         &s->out2in.addr, s->out2in.port,
+                                         s->nat_proto);
+}
+
+nat44_ei_user_t *
+nat44_ei_user_get_or_create (nat44_ei_main_t *nm, ip4_address_t *addr,
+                            u32 fib_index, u32 thread_index)
+{
+  nat44_ei_user_t *u = 0;
+  nat44_ei_user_key_t user_key;
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
+  dlist_elt_t *per_user_list_head_elt;
+
+  user_key.addr.as_u32 = addr->as_u32;
+  user_key.fib_index = fib_index;
+  kv.key = user_key.as_u64;
+
+  /* Ever heard of the "user" = src ip4 address before? */
+  if (clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
+    {
+      if (pool_elts (tnm->users) >= nm->max_users_per_thread)
+       {
+         vlib_increment_simple_counter (&nm->user_limit_reached, thread_index,
+                                        0, 1);
+         nat_elog_warn (nm, "maximum user limit reached");
+         return NULL;
+       }
+      /* no, make a new one */
+      pool_get (tnm->users, u);
+      clib_memset (u, 0, sizeof (*u));
+
+      u->addr.as_u32 = addr->as_u32;
+      u->fib_index = fib_index;
+
+      pool_get (tnm->list_pool, per_user_list_head_elt);
+
+      u->sessions_per_user_list_head_index =
+       per_user_list_head_elt - tnm->list_pool;
+
+      clib_dlist_init (tnm->list_pool, u->sessions_per_user_list_head_index);
+
+      kv.value = u - tnm->users;
+
+      /* add user */
+      if (clib_bihash_add_del_8_8 (&tnm->user_hash, &kv, 1))
+       {
+         nat_elog_warn (nm, "user_hash key add failed");
+         nat44_ei_delete_user_with_no_session (nm, u, thread_index);
+         return NULL;
+       }
+
+      vlib_set_simple_counter (&nm->total_users, thread_index, 0,
+                              pool_elts (tnm->users));
+    }
+  else
+    {
+      u = pool_elt_at_index (tnm->users, value.value);
+    }
+
+  return u;
+}
+
+nat44_ei_session_t *
+nat44_ei_session_alloc_or_recycle (nat44_ei_main_t *nm, nat44_ei_user_t *u,
+                                  u32 thread_index, f64 now)
+{
+  nat44_ei_session_t *s;
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
+  u32 oldest_per_user_translation_list_index, session_index;
+  dlist_elt_t *oldest_per_user_translation_list_elt;
+  dlist_elt_t *per_user_translation_list_elt;
+
+  /* Over quota? Recycle the least recently used translation */
+  if ((u->nsessions + u->nstaticsessions) >= nm->max_translations_per_user)
+    {
+      oldest_per_user_translation_list_index = clib_dlist_remove_head (
+       tnm->list_pool, u->sessions_per_user_list_head_index);
+
+      ASSERT (oldest_per_user_translation_list_index != ~0);
+
+      /* Add it back to the end of the LRU list */
+      clib_dlist_addtail (tnm->list_pool, u->sessions_per_user_list_head_index,
+                         oldest_per_user_translation_list_index);
+      /* Get the list element */
+      oldest_per_user_translation_list_elt = pool_elt_at_index (
+       tnm->list_pool, oldest_per_user_translation_list_index);
+
+      /* Get the session index from the list element */
+      session_index = oldest_per_user_translation_list_elt->value;
+
+      /* Get the session */
+      s = pool_elt_at_index (tnm->sessions, session_index);
+
+      nat44_ei_free_session_data_v2 (nm, s, thread_index, 0);
+      if (nat44_ei_is_session_static (s))
+       u->nstaticsessions--;
+      else
+       u->nsessions--;
+      s->flags = 0;
+      s->total_bytes = 0;
+      s->total_pkts = 0;
+      s->state = 0;
+      s->ext_host_addr.as_u32 = 0;
+      s->ext_host_port = 0;
+      s->ext_host_nat_addr.as_u32 = 0;
+      s->ext_host_nat_port = 0;
+    }
+  else
+    {
+      pool_get (tnm->sessions, s);
+      clib_memset (s, 0, sizeof (*s));
+
+      /* Create list elts */
+      pool_get (tnm->list_pool, per_user_translation_list_elt);
+      clib_dlist_init (tnm->list_pool,
+                      per_user_translation_list_elt - tnm->list_pool);
+
+      per_user_translation_list_elt->value = s - tnm->sessions;
+      s->per_user_index = per_user_translation_list_elt - tnm->list_pool;
+      s->per_user_list_head_index = u->sessions_per_user_list_head_index;
+
+      clib_dlist_addtail (tnm->list_pool, s->per_user_list_head_index,
+                         per_user_translation_list_elt - tnm->list_pool);
+
+      s->user_index = u - tnm->users;
+      vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
+                              pool_elts (tnm->sessions));
+    }
+
+  s->ha_last_refreshed = now;
+
+  return s;
+}
+
+void
+nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
+                           u32 thread_index, u8 is_ha)
+{
+  clib_bihash_kv_8_8_t kv;
+
+  init_nat_i2o_k (&kv, s);
+  if (clib_bihash_add_del_8_8 (&nm->in2out, &kv, 0))
+    nat_elog_warn (nm, "in2out key del failed");
+
+  init_nat_o2i_k (&kv, s);
+  if (clib_bihash_add_del_8_8 (&nm->out2in, &kv, 0))
+    nat_elog_warn (nm, "out2in key del failed");
+
+  if (!is_ha)
+    {
+      nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
+                              &s->in2out.addr, s->in2out.port,
+                              &s->out2in.addr, s->out2in.port, s->nat_proto);
+
+      nat_ipfix_logging_nat44_ses_delete (
+       thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
+       s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+
+      nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
+                  s->ext_host_port, s->nat_proto, s->out2in.fib_index,
+                  thread_index);
+    }
+
+  if (nat44_ei_is_session_static (s))
+    return;
+
+  nat44_ei_free_outside_address_and_port (nm->addresses, thread_index,
+                                         &s->out2in.addr, s->out2in.port,
+                                         s->nat_proto);
+}
+
+static_always_inline void
+nat44_ei_user_del_sessions (nat44_ei_user_t *u, u32 thread_index)
+{
+  dlist_elt_t *elt;
+  nat44_ei_session_t *s;
+
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
+
+  // get head
+  elt =
+    pool_elt_at_index (tnm->list_pool, u->sessions_per_user_list_head_index);
+  // get first element
+  elt = pool_elt_at_index (tnm->list_pool, elt->next);
+
+  while (elt->value != ~0)
+    {
+      s = pool_elt_at_index (tnm->sessions, elt->value);
+      elt = pool_elt_at_index (tnm->list_pool, elt->next);
+
+      nat44_ei_free_session_data (nm, s, thread_index, 0);
+      nat44_ei_delete_session (nm, s, thread_index);
+    }
+}
+
+int
+nat44_ei_user_del (ip4_address_t *addr, u32 fib_index)
+{
+  int rv = 1;
+
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+
+  nat44_ei_user_key_t user_key;
+  clib_bihash_kv_8_8_t kv, value;
+
+  user_key.addr.as_u32 = addr->as_u32;
+  user_key.fib_index = fib_index;
+  kv.key = user_key.as_u64;
+
+  if (nm->num_workers > 1)
+    {
+      vec_foreach (tnm, nm->per_thread_data)
+       {
+         if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
+           {
+             nat44_ei_user_del_sessions (
+               pool_elt_at_index (tnm->users, value.value),
+               tnm->thread_index);
+             rv = 0;
+             break;
+           }
+       }
+    }
+  else
+    {
+      tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
+      if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
+       {
+         nat44_ei_user_del_sessions (
+           pool_elt_at_index (tnm->users, value.value), tnm->thread_index);
+         rv = 0;
+       }
+    }
+  return rv;
+}
+
+void
+nat44_ei_static_mapping_del_sessions (nat44_ei_main_t *nm,
+                                     nat44_ei_main_per_thread_data_t *tnm,
+                                     nat44_ei_user_key_t u_key, int addr_only,
+                                     ip4_address_t e_addr, u16 e_port)
+{
+  clib_bihash_kv_8_8_t kv, value;
+  kv.key = u_key.as_u64;
+  u64 user_index;
+  dlist_elt_t *head, *elt;
+  nat44_ei_user_t *u;
+  nat44_ei_session_t *s;
+  u32 elt_index, head_index, ses_index;
+
+  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->nstaticsessions)
+       {
+         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 (!addr_only)
+               {
+                 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
+                     (s->out2in.port != e_port))
+                   continue;
+               }
+
+             if (!nat44_ei_is_session_static (s))
+               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 (!addr_only)
+               break;
+           }
+       }
+    }
+}
+
+u32
+nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
+                                 u8 is_output)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 next_worker_index = 0;
+  u32 hash;
+
+  next_worker_index = nm->first_worker_index;
+  hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
+        (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
+
+  if (PREDICT_TRUE (is_pow2 (_vec_len (nm->workers))))
+    next_worker_index += nm->workers[hash & (_vec_len (nm->workers) - 1)];
+  else
+    next_worker_index += nm->workers[hash % _vec_len (nm->workers)];
+
+  return next_worker_index;
+}
+
+u32
+nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
+                                 u32 rx_fib_index0, u8 is_output)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  udp_header_t *udp;
+  u16 port;
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_static_mapping_t *m;
+  u32 proto;
+  u32 next_worker_index = 0;
+
+  /* first try static mappings without port */
+  if (PREDICT_FALSE (pool_elts (nm->static_mappings)))
+    {
+      init_nat_k (&kv, ip0->dst_address, 0, rx_fib_index0, 0);
+      if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
+                                  &value))
+       {
+         m = pool_elt_at_index (nm->static_mappings, value.value);
+         return m->workers[0];
+       }
+    }
+
+  proto = ip_proto_to_nat_proto (ip0->protocol);
+  udp = ip4_next_header (ip0);
+  port = udp->dst_port;
+
+  /* unknown protocol */
+  if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
     {
       /* use current thread */
       return vlib_get_thread_index ();
@@ -438,33 +1447,34 @@ nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
     }
 
   /* try static mappings with port */
-  if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
+  if (PREDICT_FALSE (pool_elts (nm->static_mappings)))
     {
       init_nat_k (&kv, ip0->dst_address, port, rx_fib_index0, proto);
-      if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
+      if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
                                   &value))
        {
-         m = pool_elt_at_index (sm->static_mappings, value.value);
+         m = pool_elt_at_index (nm->static_mappings, value.value);
          return m->workers[0];
        }
     }
 
   /* worker by outside port */
-  next_worker_index = sm->first_worker_index;
+  next_worker_index = nm->first_worker_index;
   next_worker_index +=
-    sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
+    nm->workers[(clib_net_to_host_u16 (port) - 1024) / nm->port_per_thread];
   return next_worker_index;
 }
 
 static int
-nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
+nat44_ei_alloc_default_cb (nat44_ei_address_t *addresses, u32 fib_index,
                           u32 thread_index, nat_protocol_t proto,
                           ip4_address_t *addr, u16 *port, u16 port_per_thread,
                           u32 snat_thread_index)
 {
-  int i;
-  snat_address_t *a, *ga = 0;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a, *ga = 0;
   u32 portnum;
+  int i;
 
   for (i = 0; i < vec_len (addresses); i++)
     {
@@ -480,7 +1490,9 @@ nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
            while (1)                                                         \
              {                                                               \
                portnum = (port_per_thread * snat_thread_index) +             \
-                         snat_random_port (0, port_per_thread - 1) + 1024;   \
+                         nat_random_port (&nm->random_seed, 0,               \
+                                          port_per_thread - 1) +             \
+                         1024;                                               \
                if (a->busy_##n##_port_refcounts[portnum])                    \
                  continue;                                                   \
                --a->busy_##n##_port_refcounts[portnum];                      \
@@ -499,7 +1511,7 @@ nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
     break;
          foreach_nat_protocol
 #undef _
-           default : nat_elog_info ("unknown protocol");
+           default : nat_elog_info (nm, "unknown protocol");
          return 1;
        }
     }
@@ -513,8 +1525,9 @@ nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
   case NAT_PROTOCOL_##N:                                                      \
     while (1)                                                                 \
       {                                                                       \
-       portnum = (port_per_thread * snat_thread_index) +                     \
-                 snat_random_port (0, port_per_thread - 1) + 1024;           \
+       portnum =                                                             \
+         (port_per_thread * snat_thread_index) +                             \
+         nat_random_port (&nm->random_seed, 0, port_per_thread - 1) + 1024;  \
        if (a->busy_##n##_port_refcounts[portnum])                            \
          continue;                                                           \
        ++a->busy_##n##_port_refcounts[portnum];                              \
@@ -527,7 +1540,7 @@ nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
          break;
          foreach_nat_protocol
 #undef _
-           default : nat_elog_info ("unknown protocol");
+           default : nat_elog_info (nm, "unknown protocol");
          return 1;
        }
     }
@@ -538,16 +1551,16 @@ nat44_ei_alloc_default_cb (snat_address_t *addresses, u32 fib_index,
 }
 
 static int
-nat44_ei_alloc_range_cb (snat_address_t *addresses, u32 fib_index,
+nat44_ei_alloc_range_cb (nat44_ei_address_t *addresses, u32 fib_index,
                         u32 thread_index, nat_protocol_t proto,
                         ip4_address_t *addr, u16 *port, u16 port_per_thread,
                         u32 snat_thread_index)
 {
-  snat_main_t *sm = &snat_main;
-  snat_address_t *a = addresses;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a = addresses;
   u16 portnum, ports;
 
-  ports = sm->end_port - sm->start_port + 1;
+  ports = nm->end_port - nm->start_port + 1;
 
   if (!vec_len (addresses))
     goto exhausted;
@@ -560,7 +1573,8 @@ nat44_ei_alloc_range_cb (snat_address_t *addresses, u32 fib_index,
       {                                                                       \
        while (1)                                                             \
          {                                                                   \
-           portnum = snat_random_port (sm->start_port, sm->end_port);        \
+           portnum = nat_random_port (&nm->random_seed, nm->start_port,      \
+                                      nm->end_port);                         \
            if (a->busy_##n##_port_refcounts[portnum])                        \
              continue;                                                       \
            ++a->busy_##n##_port_refcounts[portnum];                          \
@@ -573,7 +1587,7 @@ nat44_ei_alloc_range_cb (snat_address_t *addresses, u32 fib_index,
     break;
       foreach_nat_protocol
 #undef _
-       default : nat_elog_info ("unknown protocol");
+       default : nat_elog_info (nm, "unknown protocol");
       return 1;
     }
 
@@ -584,16 +1598,16 @@ exhausted:
 }
 
 static int
-nat44_ei_alloc_mape_cb (snat_address_t *addresses, u32 fib_index,
+nat44_ei_alloc_mape_cb (nat44_ei_address_t *addresses, u32 fib_index,
                        u32 thread_index, nat_protocol_t proto,
                        ip4_address_t *addr, u16 *port, u16 port_per_thread,
                        u32 snat_thread_index)
 {
-  snat_main_t *sm = &snat_main;
-  snat_address_t *a = addresses;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a = addresses;
   u16 m, ports, portnum, A, j;
-  m = 16 - (sm->psid_offset + sm->psid_length);
-  ports = (1 << (16 - sm->psid_length)) - (1 << m);
+  m = 16 - (nm->psid_offset + nm->psid_length);
+  ports = (1 << (16 - nm->psid_length)) - (1 << m);
 
   if (!vec_len (addresses))
     goto exhausted;
@@ -606,9 +1620,10 @@ nat44_ei_alloc_mape_cb (snat_address_t *addresses, u32 fib_index,
       {                                                                       \
        while (1)                                                             \
          {                                                                   \
-           A = snat_random_port (1, pow2_mask (sm->psid_offset));            \
-           j = snat_random_port (0, pow2_mask (m));                          \
-           portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m));    \
+           A = nat_random_port (&nm->random_seed, 1,                         \
+                                pow2_mask (nm->psid_offset));                \
+           j = nat_random_port (&nm->random_seed, 0, pow2_mask (m));         \
+           portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m));    \
            if (a->busy_##n##_port_refcounts[portnum])                        \
              continue;                                                       \
            ++a->busy_##n##_port_refcounts[portnum];                          \
@@ -621,7 +1636,7 @@ nat44_ei_alloc_mape_cb (snat_address_t *addresses, u32 fib_index,
     break;
       foreach_nat_protocol
 #undef _
-       default : nat_elog_info ("unknown protocol");
+       default : nat_elog_info (nm, "unknown protocol");
       return 1;
     }
 
@@ -634,33 +1649,33 @@ exhausted:
 void
 nat44_ei_set_alloc_default ()
 {
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
-  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
-  sm->alloc_addr_and_port = nat44_ei_alloc_default_cb;
+  nm->addr_and_port_alloc_alg = NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
+  nm->alloc_addr_and_port = nat44_ei_alloc_default_cb;
 }
 
 void
 nat44_ei_set_alloc_range (u16 start_port, u16 end_port)
 {
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
-  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
-  sm->alloc_addr_and_port = nat44_ei_alloc_range_cb;
-  sm->start_port = start_port;
-  sm->end_port = end_port;
+  nm->addr_and_port_alloc_alg = NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_RANGE;
+  nm->alloc_addr_and_port = nat44_ei_alloc_range_cb;
+  nm->start_port = start_port;
+  nm->end_port = end_port;
 }
 
 void
 nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length)
 {
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
-  sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
-  sm->alloc_addr_and_port = nat44_ei_alloc_mape_cb;
-  sm->psid = psid;
-  sm->psid_offset = psid_offset;
-  sm->psid_length = psid_length;
+  nm->addr_and_port_alloc_alg = NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_MAPE;
+  nm->alloc_addr_and_port = nat44_ei_alloc_mape_cb;
+  nm->psid = psid;
+  nm->psid_offset = psid_offset;
+  nm->psid_length = psid_length;
 }
 
 static void
@@ -670,10 +1685,10 @@ nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port,
                                           int addr_only, int identity_nat,
                                           u8 *tag)
 {
-  snat_main_t *sm = &snat_main;
-  snat_static_map_resolve_t *rp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_map_resolve_t *rp;
 
-  vec_add2 (sm->to_resolve, rp, 1);
+  vec_add2 (nm->to_resolve, rp, 1);
   clib_memset (rp, 0, sizeof (*rp));
 
   rp->l_addr.as_u32 = l_addr.as_u32;
@@ -687,65 +1702,131 @@ nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port,
   rp->tag = vec_dup (tag);
 }
 
+void
+nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
+                        u32 thread_index)
+{
+  nat44_ei_main_per_thread_data_t *tnm =
+    vec_elt_at_index (nm->per_thread_data, thread_index);
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_user_t *u;
+  const nat44_ei_user_key_t u_key = { .addr = ses->in2out.addr,
+                                     .fib_index = ses->in2out.fib_index };
+  const u8 u_static = nat44_ei_is_session_static (ses);
+
+  clib_dlist_remove (tnm->list_pool, ses->per_user_index);
+  pool_put_index (tnm->list_pool, ses->per_user_index);
+
+  pool_put (tnm->sessions, ses);
+  vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
+                          pool_elts (tnm->sessions));
+
+  kv.key = u_key.as_u64;
+  if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
+    {
+      u = pool_elt_at_index (tnm->users, value.value);
+      if (u_static)
+       u->nstaticsessions--;
+      else
+       u->nsessions--;
+
+      nat44_ei_delete_user_with_no_session (nm, u, thread_index);
+    }
+}
+
 int
-nat44_ei_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
+nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
                      nat_protocol_t proto, u32 vrf_id, int is_in)
 {
-  snat_main_per_thread_data_t *tsm;
+  nat44_ei_main_per_thread_data_t *tnm;
   clib_bihash_kv_8_8_t kv, value;
   ip4_header_t ip;
   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
-  snat_session_t *s;
+  nat44_ei_session_t *s;
   clib_bihash_8_8_t *t;
 
-  if (sm->endpoint_dependent)
-    return VNET_API_ERROR_UNSUPPORTED;
-
   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
-  if (sm->num_workers > 1)
-    tsm = vec_elt_at_index (sm->per_thread_data,
-                           sm->worker_in2out_cb (&ip, fib_index, 0));
+  if (nm->num_workers > 1)
+    tnm = vec_elt_at_index (nm->per_thread_data,
+                           nm->worker_in2out_cb (&ip, fib_index, 0));
   else
-    tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
+    tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
 
   init_nat_k (&kv, *addr, port, fib_index, proto);
-  t = is_in ? &sm->in2out : &sm->out2in;
+  t = is_in ? &nm->in2out : &nm->out2in;
   if (!clib_bihash_search_8_8 (t, &kv, &value))
     {
-      if (pool_is_free_index (tsm->sessions, value.value))
+      if (pool_is_free_index (tnm->sessions, value.value))
        return VNET_API_ERROR_UNSPECIFIED;
 
-      s = pool_elt_at_index (tsm->sessions, value.value);
-      nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
-      nat44_delete_session (sm, s, tsm - sm->per_thread_data);
+      s = pool_elt_at_index (tnm->sessions, value.value);
+      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);
       return 0;
     }
 
   return VNET_API_ERROR_NO_SUCH_ENTRY;
 }
 
+u32
+nat44_ei_get_thread_idx_by_port (u16 e_port)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 thread_idx = nm->num_workers;
+  if (nm->num_workers > 1)
+    {
+      thread_idx = nm->first_worker_index +
+                  nm->workers[(e_port - 1024) / nm->port_per_thread];
+    }
+  return thread_idx;
+}
+
+void
+nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index,
+                             int is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  fib_prefix_t prefix = {
+    .fp_len = p_len,
+    .fp_proto = FIB_PROTOCOL_IP4,
+    .fp_addr = {
+               .ip4.as_u32 = addr->as_u32,
+               },
+  };
+  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);
+  else
+    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)
 {
-  snat_main_t *sm = &snat_main;
-  snat_static_mapping_t *m = 0;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m = 0;
   clib_bihash_kv_8_8_t kv, value;
-  snat_address_t *a = 0;
+  nat44_ei_address_t *a = 0;
   u32 fib_index = ~0;
-  snat_interface_t *interface;
-  snat_main_per_thread_data_t *tsm;
-  snat_user_key_t u_key;
-  snat_user_t *u;
+  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;
-  snat_session_t *s;
-  snat_static_map_resolve_t *rp, *rp_match = 0;
-  nat44_lb_addr_port_t *local;
+  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;
 
@@ -753,9 +1834,9 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
     {
       ip4_address_t *first_int_addr;
 
-      for (i = 0; i < vec_len (sm->to_resolve); i++)
+      for (i = 0; i < vec_len (nm->to_resolve); i++)
        {
-         rp = sm->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)
@@ -774,7 +1855,7 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
 
       /* Might be already set... */
       first_int_addr = ip4_interface_first_address (
-       sm->ip4_main, sw_if_index, 0 /* just want the address */);
+       nm->ip4_main, sw_if_index, 0 /* just want the address */);
 
       if (is_add)
        {
@@ -799,7 +1880,7 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
          if (!rp_match)
            return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-         vec_del1 (sm->to_resolve, i);
+         vec_del1 (nm->to_resolve, i);
 
          if (!first_int_addr)
            return 0;
@@ -812,15 +1893,15 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
     }
 
   init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto);
-  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
-    m = pool_elt_at_index (sm->static_mappings, value.value);
+  if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
+    m = pool_elt_at_index (nm->static_mappings, value.value);
 
   if (is_add)
     {
       if (m)
        {
          // identity mapping for second vrf
-         if (is_identity_static_mapping (m))
+         if (nat44_ei_is_identity_static_mapping (m))
            {
              pool_foreach (local, m->locals)
                {
@@ -830,10 +1911,10 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
              pool_get (m->locals, local);
              local->vrf_id = vrf_id;
              local->fib_index = fib_table_find_or_create_and_lock (
-               FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
+               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 - sm->static_mappings);
-             clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
+                          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;
@@ -843,34 +1924,34 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
       if (vrf_id != ~0)
        {
          fib_index = fib_table_find_or_create_and_lock (
-           FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
+           FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
        }
       /* If not specified use inside VRF id from NAT44 plugin config */
       else
        {
-         fib_index = sm->inside_fib_index;
-         vrf_id = sm->inside_vrf_id;
-         fib_table_lock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
+         fib_index = nm->inside_fib_index;
+         vrf_id = nm->inside_vrf_id;
+         fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
        }
 
       if (!identity_nat)
        {
          init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index,
                      addr_only ? 0 : proto);
-         if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv,
+         if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv,
                                       &value))
            return VNET_API_ERROR_VALUE_EXIST;
        }
 
       /* Find external address in allocated addresses and reserve port for
         address and port pair mapping when dynamic translations enabled */
-      if (!(addr_only || sm->static_mapping_only))
+      if (!(addr_only || nm->static_mapping_only))
        {
-         for (i = 0; i < vec_len (sm->addresses); i++)
+         for (i = 0; i < vec_len (nm->addresses); i++)
            {
-             if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
+             if (nm->addresses[i].addr.as_u32 == e_addr.as_u32)
                {
-                 a = sm->addresses + i;
+                 a = nm->addresses + i;
                  /* External port must be unused */
                  switch (proto)
                    {
@@ -882,12 +1963,13 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
     if (e_port > 1024)                                                        \
       {                                                                       \
        a->busy_##n##_ports++;                                                \
-       a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]++;    \
+       a->busy_##n##_ports_per_thread[nat44_ei_get_thread_idx_by_port (      \
+         e_port)]++;                                                         \
       }                                                                       \
     break;
                      foreach_nat_protocol
 #undef _
-                       default : nat_elog_info ("unknown protocol");
+                       default : nat_elog_info (nm, "unknown protocol");
                      return VNET_API_ERROR_INVALID_VALUE_2;
                    }
                  break;
@@ -898,9 +1980,9 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
            {
              if (sw_if_index != ~0)
                {
-                 for (i = 0; i < vec_len (sm->to_resolve); i++)
+                 for (i = 0; i < vec_len (nm->to_resolve); i++)
                    {
-                     rp = sm->to_resolve + i;
+                     rp = nm->to_resolve + i;
                      if (rp->addr_only)
                        continue;
                      if (rp->sw_if_index != sw_if_index &&
@@ -909,7 +1991,7 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
                          rp->e_port != e_port && rp->proto != proto)
                        continue;
 
-                     vec_del1 (sm->to_resolve, i);
+                     vec_del1 (nm->to_resolve, i);
                      break;
                    }
                }
@@ -917,14 +1999,14 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
            }
        }
 
-      pool_get (sm->static_mappings, m);
+      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;
 
       if (addr_only)
-       m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
+       m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY;
       else
        {
          m->local_port = l_port;
@@ -934,7 +2016,7 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
 
       if (identity_nat)
        {
-         m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
+         m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT;
          pool_get (m->locals, local);
          local->vrf_id = vrf_id;
          local->fib_index = fib_index;
@@ -945,58 +2027,59 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
          m->fib_index = fib_index;
        }
 
-      if (sm->num_workers > 1)
+      if (nm->num_workers > 1)
        {
          ip4_header_t ip = {
            .src_address = m->local_addr,
          };
-         vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
-         tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
+         vec_add1 (m->workers, nm->worker_in2out_cb (&ip, m->fib_index, 0));
+         tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
        }
       else
-       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
+       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 - sm->static_mappings);
-      clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
+                  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 - sm->static_mappings);
-      clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
+                  m - nm->static_mappings);
+      clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1);
 
       /* Delete dynamic sessions matching local address (+ local port) */
       // TODO: based on type of NAT EI/ED
-      if (!(sm->static_mapping_only))
+      if (!(nm->static_mapping_only))
        {
          u_key.addr = m->local_addr;
          u_key.fib_index = m->fib_index;
          kv.key = u_key.as_u64;
-         if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+         if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
            {
              user_index = value.value;
-             u = pool_elt_at_index (tsm->users, user_index);
+             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 (tsm->list_pool, head_index);
+                 head = pool_elt_at_index (tnm->list_pool, head_index);
                  elt_index = head->next;
-                 elt = pool_elt_at_index (tsm->list_pool, elt_index);
+                 elt = pool_elt_at_index (tnm->list_pool, elt_index);
                  ses_index = elt->value;
                  while (ses_index != ~0)
                    {
-                     s = pool_elt_at_index (tsm->sessions, ses_index);
-                     elt = pool_elt_at_index (tsm->list_pool, elt->next);
+                     s = pool_elt_at_index (tnm->sessions, ses_index);
+                     elt = pool_elt_at_index (tnm->list_pool, elt->next);
                      ses_index = elt->value;
 
-                     if (snat_is_session_static (s))
+                     if (nat44_ei_is_session_static (s))
                        continue;
 
                      if (!addr_only && s->in2out.port != m->local_port)
                        continue;
 
-                     nat_free_session_data (sm, s, tsm - sm->per_thread_data,
-                                            0);
-                     nat44_delete_session (sm, s, tsm - sm->per_thread_data);
+                     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 (!addr_only)
                        break;
@@ -1005,315 +2088,929 @@ nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
            }
        }
     }
-  else
+  else
+    {
+      if (!m)
+       {
+         if (sw_if_index != ~0)
+           return 0;
+         else
+           return VNET_API_ERROR_NO_SUCH_ENTRY;
+       }
+
+      if (identity_nat)
+       {
+         if (vrf_id == ~0)
+           vrf_id = nm->inside_vrf_id;
+
+         pool_foreach (local, m->locals)
+           {
+             if (local->vrf_id == vrf_id)
+               find = local - m->locals;
+           }
+         if (find == ~0)
+           return VNET_API_ERROR_NO_SUCH_ENTRY;
+
+         local = pool_elt_at_index (m->locals, find);
+         fib_index = local->fib_index;
+         pool_put (m->locals, local);
+       }
+      else
+       fib_index = m->fib_index;
+
+      /* Free external address port */
+      if (!(addr_only || nm->static_mapping_only))
+       {
+         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;
+               }
+           }
+       }
+
+      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);
+       }
+
+      fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
+      if (pool_elts (m->locals))
+       return 0;
+
+      init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
+      clib_bihash_add_del_8_8 (&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;
+    }
+  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;
+}
+
+int
+nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
+                              u32 match_fib_index,
+                              nat_protocol_t match_protocol,
+                              ip4_address_t *mapping_addr, u16 *mapping_port,
+                              u32 *mapping_fib_index, u8 by_external,
+                              u8 *is_addr_only, u8 *is_identity_nat)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_static_mapping_t *m;
+  u16 port;
+
+  if (by_external)
+    {
+      init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
+      if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
+                                 &value))
+       {
+         /* Try address only mapping */
+         init_nat_k (&kv, match_addr, 0, 0, 0);
+         if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
+                                     &value))
+           return 1;
+       }
+      m = pool_elt_at_index (nm->static_mappings, value.value);
+
+      *mapping_fib_index = m->fib_index;
+      *mapping_addr = m->local_addr;
+      port = m->local_port;
+    }
+  else
+    {
+      init_nat_k (&kv, match_addr, match_port, match_fib_index,
+                 match_protocol);
+      if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
+       {
+         /* Try address only mapping */
+         init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
+         if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv,
+                                     &value))
+           return 1;
+       }
+      m = pool_elt_at_index (nm->static_mappings, value.value);
+
+      *mapping_fib_index = nm->outside_fib_index;
+      *mapping_addr = m->external_addr;
+      port = m->external_port;
+    }
+
+  /* Address only mapping doesn't change port */
+  if (nat44_ei_is_addr_only_static_mapping (m))
+    *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);
+
+  if (PREDICT_FALSE (is_identity_nat != 0))
+    *is_identity_nat = nat44_ei_is_identity_static_mapping (m);
+
+  return 0;
+}
+
+static void
+nat44_ei_worker_db_free (nat44_ei_main_per_thread_data_t *tnm)
+{
+  pool_free (tnm->list_pool);
+  pool_free (tnm->lru_pool);
+  pool_free (tnm->sessions);
+  pool_free (tnm->users);
+
+  clib_bihash_free_8_8 (&tnm->user_hash);
+}
+
+u8 *
+format_nat44_ei_key (u8 *s, va_list *args)
+{
+  u64 key = va_arg (*args, u64);
+
+  ip4_address_t addr;
+  u16 port;
+  nat_protocol_t protocol;
+  u32 fib_index;
+
+  split_nat_key (key, &addr, &port, &fib_index, &protocol);
+
+  s = format (s, "%U proto %U port %d fib %d", format_ip4_address, &addr,
+             format_nat_protocol, protocol, clib_net_to_host_u16 (port),
+             fib_index);
+  return s;
+}
+
+u8 *
+format_nat44_ei_user_kvp (u8 *s, va_list *args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+  nat44_ei_user_key_t k;
+
+  k.as_u64 = v->key;
+
+  s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
+             k.fib_index, v->value);
+
+  return s;
+}
+
+u8 *
+format_nat44_ei_session_kvp (u8 *s, va_list *args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+
+  s =
+    format (s, "%U session-index %llu", format_nat44_ei_key, v->key, v->value);
+
+  return s;
+}
+
+u8 *
+format_nat44_ei_static_mapping_kvp (u8 *s, va_list *args)
+{
+  clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
+
+  s = format (s, "%U static-mapping-index %llu", format_nat44_ei_key, v->key,
+             v->value);
+
+  return s;
+}
+
+static void
+nat44_ei_worker_db_init (nat44_ei_main_per_thread_data_t *tnm,
+                        u32 translations, u32 translation_buckets,
+                        u32 user_buckets)
+{
+  dlist_elt_t *head;
+
+  pool_alloc (tnm->list_pool, translations);
+  pool_alloc (tnm->lru_pool, translations);
+  pool_alloc (tnm->sessions, translations);
+
+  clib_bihash_init_8_8 (&tnm->user_hash, "users", user_buckets, 0);
+
+  clib_bihash_set_kvp_format_fn_8_8 (&tnm->user_hash,
+                                    format_nat44_ei_user_kvp);
+
+  pool_get (tnm->lru_pool, head);
+  tnm->tcp_trans_lru_head_index = head - tnm->lru_pool;
+  clib_dlist_init (tnm->lru_pool, tnm->tcp_trans_lru_head_index);
+
+  pool_get (tnm->lru_pool, head);
+  tnm->tcp_estab_lru_head_index = head - tnm->lru_pool;
+  clib_dlist_init (tnm->lru_pool, tnm->tcp_estab_lru_head_index);
+
+  pool_get (tnm->lru_pool, head);
+  tnm->udp_lru_head_index = head - tnm->lru_pool;
+  clib_dlist_init (tnm->lru_pool, tnm->udp_lru_head_index);
+
+  pool_get (tnm->lru_pool, head);
+  tnm->icmp_lru_head_index = head - tnm->lru_pool;
+  clib_dlist_init (tnm->lru_pool, tnm->icmp_lru_head_index);
+
+  pool_get (tnm->lru_pool, head);
+  tnm->unk_proto_lru_head_index = head - tnm->lru_pool;
+  clib_dlist_init (tnm->lru_pool, tnm->unk_proto_lru_head_index);
+}
+
+static void
+nat44_ei_db_free ()
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+
+  pool_free (nm->static_mappings);
+  clib_bihash_free_8_8 (&nm->static_mapping_by_local);
+  clib_bihash_free_8_8 (&nm->static_mapping_by_external);
+
+  if (nm->pat)
+    {
+      clib_bihash_free_8_8 (&nm->in2out);
+      clib_bihash_free_8_8 (&nm->out2in);
+      vec_foreach (tnm, nm->per_thread_data)
+       {
+         nat44_ei_worker_db_free (tnm);
+       }
+    }
+}
+
+static void
+nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+
+  u32 static_mapping_buckets = 1024;
+  u32 static_mapping_memory_size = 64 << 20;
+
+  clib_bihash_init_8_8 (&nm->static_mapping_by_local,
+                       "static_mapping_by_local", static_mapping_buckets,
+                       static_mapping_memory_size);
+  clib_bihash_init_8_8 (&nm->static_mapping_by_external,
+                       "static_mapping_by_external", static_mapping_buckets,
+                       static_mapping_memory_size);
+  clib_bihash_set_kvp_format_fn_8_8 (&nm->static_mapping_by_local,
+                                    format_nat44_ei_static_mapping_kvp);
+  clib_bihash_set_kvp_format_fn_8_8 (&nm->static_mapping_by_external,
+                                    format_nat44_ei_static_mapping_kvp);
+
+  if (nm->pat)
+    {
+      clib_bihash_init_8_8 (&nm->in2out, "in2out", translation_buckets, 0);
+      clib_bihash_init_8_8 (&nm->out2in, "out2in", translation_buckets, 0);
+      clib_bihash_set_kvp_format_fn_8_8 (&nm->in2out,
+                                        format_nat44_ei_session_kvp);
+      clib_bihash_set_kvp_format_fn_8_8 (&nm->out2in,
+                                        format_nat44_ei_session_kvp);
+      vec_foreach (tnm, nm->per_thread_data)
+       {
+         nat44_ei_worker_db_init (tnm, translations, translation_buckets,
+                                  user_buckets);
+       }
+    }
+}
+
+void
+nat44_ei_sessions_clear ()
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+
+  if (nm->pat)
+    {
+      clib_bihash_free_8_8 (&nm->in2out);
+      clib_bihash_free_8_8 (&nm->out2in);
+      clib_bihash_init_8_8 (&nm->in2out, "in2out", nm->translation_buckets, 0);
+      clib_bihash_init_8_8 (&nm->out2in, "out2in", nm->translation_buckets, 0);
+      clib_bihash_set_kvp_format_fn_8_8 (&nm->in2out,
+                                        format_nat44_ei_session_kvp);
+      clib_bihash_set_kvp_format_fn_8_8 (&nm->out2in,
+                                        format_nat44_ei_session_kvp);
+      vec_foreach (tnm, nm->per_thread_data)
+       {
+         nat44_ei_worker_db_free (tnm);
+         nat44_ei_worker_db_init (tnm, nm->translations,
+                                  nm->translation_buckets, nm->user_buckets);
+       }
+    }
+
+  vlib_zero_simple_counter (&nm->total_users, 0);
+  vlib_zero_simple_counter (&nm->total_sessions, 0);
+  vlib_zero_simple_counter (&nm->user_limit_reached, 0);
+}
+
+static void
+nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque, u32 sw_if_index,
+                            u32 new_fib_index, u32 old_fib_index)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_outside_fib_t *outside_fib;
+  nat44_ei_interface_t *i;
+  u8 is_add = 1;
+  u8 match = 0;
+
+  if (!nm->enabled || (new_fib_index == old_fib_index) ||
+      (!vec_len (nm->outside_fibs)))
+    {
+      return;
+    }
+
+  pool_foreach (i, nm->interfaces)
     {
-      if (!m)
+      if (i->sw_if_index == sw_if_index)
        {
-         if (sw_if_index != ~0)
-           return 0;
-         else
-           return VNET_API_ERROR_NO_SUCH_ENTRY;
+         if (!(nat44_ei_interface_is_outside (i)))
+           return;
+         match = 1;
        }
+    }
 
-      if (identity_nat)
+  pool_foreach (i, nm->output_feature_interfaces)
+    {
+      if (i->sw_if_index == sw_if_index)
        {
-         if (vrf_id == ~0)
-           vrf_id = sm->inside_vrf_id;
+         if (!(nat44_ei_interface_is_outside (i)))
+           return;
+         match = 1;
+       }
+    }
 
-         pool_foreach (local, m->locals)
-           {
-             if (local->vrf_id == vrf_id)
-               find = local - m->locals;
-           }
-         if (find == ~0)
-           return VNET_API_ERROR_NO_SUCH_ENTRY;
+  if (!match)
+    return;
 
-         local = pool_elt_at_index (m->locals, find);
-         fib_index = local->fib_index;
-         pool_put (m->locals, local);
+  vec_foreach (outside_fib, nm->outside_fibs)
+    {
+      if (outside_fib->fib_index == old_fib_index)
+       {
+         outside_fib->refcount--;
+         if (!outside_fib->refcount)
+           vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
+         break;
        }
-      else
-       fib_index = m->fib_index;
+    }
 
-      /* Free external address port */
-      if (!(addr_only || sm->static_mapping_only))
+  vec_foreach (outside_fib, nm->outside_fibs)
+    {
+      if (outside_fib->fib_index == new_fib_index)
        {
-         for (i = 0; i < vec_len (sm->addresses); i++)
-           {
-             if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
-               {
-                 a = sm->addresses + i;
-                 switch (proto)
-                   {
-#define _(N, j, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    --a->busy_##n##_port_refcounts[e_port];                                   \
-    if (e_port > 1024)                                                        \
-      {                                                                       \
-       a->busy_##n##_ports--;                                                \
-       a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--;    \
-      }                                                                       \
-    break;
-                     foreach_nat_protocol
-#undef _
-                       default : return VNET_API_ERROR_INVALID_VALUE_2;
-                   }
-                 break;
-               }
-           }
+         outside_fib->refcount++;
+         is_add = 0;
+         break;
        }
+    }
 
-      if (sm->num_workers > 1)
-       tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
-      else
-       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
+  if (is_add)
+    {
+      vec_add2 (nm->outside_fibs, outside_fib, 1);
+      outside_fib->refcount = 1;
+      outside_fib->fib_index = new_fib_index;
+    }
+}
 
-      init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto);
-      clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
+int
+nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id)
+{
+  nat44_ei_address_t *ap;
+  nat44_ei_interface_t *i;
+  vlib_thread_main_t *tm = vlib_get_thread_main ();
 
-      /* Delete session(s) for static mapping if exist */
-      if (!(sm->static_mapping_only) ||
-         (sm->static_mapping_only && sm->static_mapping_connection_tracking))
+  /* Check if address already exists */
+  vec_foreach (ap, nm->addresses)
+    {
+      if (ap->addr.as_u32 == addr->as_u32)
        {
-         u_key.addr = m->local_addr;
-         u_key.fib_index = fib_index;
-         kv.key = u_key.as_u64;
-         nat44_ei_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
-                                               e_addr, e_port);
+         nat44_ei_log_err ("address exist");
+         return VNET_API_ERROR_VALUE_EXIST;
        }
+    }
 
-      fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
-      if (pool_elts (m->locals))
-       return 0;
+  vec_add2 (nm->addresses, ap, 1);
 
-      init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
-      clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
+  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;
 
-      vec_free (m->tag);
-      vec_free (m->workers);
-      /* Delete static mapping from pool */
-      pool_put (sm->static_mappings, m);
-    }
+#define _(N, i, n, s)                                                         \
+  clib_memset (ap->busy_##n##_port_refcounts, 0,                              \
+              sizeof (ap->busy_##n##_port_refcounts));                       \
+  ap->busy_##n##_ports = 0;                                                   \
+  ap->busy_##n##_ports_per_thread = 0;                                        \
+  vec_validate_init_empty (ap->busy_##n##_ports_per_thread,                   \
+                          tm->n_vlib_mains - 1, 0);
+  foreach_nat_protocol
+#undef _
 
-  if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
-    return 0;
+    /* Add external address to FIB */
+    pool_foreach (i, nm->interfaces)
+  {
+    if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo)
+      continue;
 
-  /* Add/delete external address to FIB */
-  pool_foreach (interface, sm->interfaces)
+    nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
+    break;
+  }
+  pool_foreach (i, nm->output_feature_interfaces)
     {
-      if (nat_interface_is_inside (interface) || sm->out2in_dpo)
+      if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo)
        continue;
 
-      snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
+      nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
       break;
     }
-  pool_foreach (interface, sm->output_feature_interfaces)
-    {
-      if (nat_interface_is_inside (interface) || sm->out2in_dpo)
-       continue;
 
-      snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, is_add);
-      break;
-    }
   return 0;
 }
 
 int
-nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
-                              u32 match_fib_index,
-                              nat_protocol_t match_protocol,
-                              ip4_address_t *mapping_addr, u16 *mapping_port,
-                              u32 *mapping_fib_index, u8 by_external,
-                              u8 *is_addr_only, u8 *is_identity_nat)
+nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index,
+                               int is_del)
 {
-  snat_main_t *sm = &snat_main;
-  clib_bihash_kv_8_8_t kv, value;
-  snat_static_mapping_t *m;
-  u16 port;
+  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;
 
-  if (by_external)
-    {
-      init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
-      if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
-                                 &value))
-       {
-         /* Try address only mapping */
-         init_nat_k (&kv, match_addr, 0, 0, 0);
-         if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv,
-                                     &value))
-           return 1;
-       }
-      m = pool_elt_at_index (sm->static_mappings, value.value);
+  first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
+                                               0 /* just want the address */);
 
-      *mapping_fib_index = m->fib_index;
-      *mapping_addr = m->local_addr;
-      port = m->local_port;
-    }
-  else
+  for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
     {
-      init_nat_k (&kv, match_addr, match_port, match_fib_index,
-                 match_protocol);
-      if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
+      if (auto_add_sw_if_indices[i] == sw_if_index)
        {
-         /* Try address only mapping */
-         init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
-         if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv,
-                                     &value))
-           return 1;
-       }
-      m = pool_elt_at_index (sm->static_mappings, value.value);
+         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;
 
-      *mapping_fib_index = sm->outside_fib_index;
-      *mapping_addr = m->external_addr;
-      port = m->external_port;
+         return 0;
+       }
     }
 
-  /* Address only mapping doesn't change port */
-  if (is_addr_only_static_mapping (m))
-    *mapping_port = match_port;
-  else
-    *mapping_port = port;
+  if (is_del)
+    return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-  if (PREDICT_FALSE (is_addr_only != 0))
-    *is_addr_only = is_addr_only_static_mapping (m);
+  /* add to the auto-address list */
+  vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
 
-  if (PREDICT_FALSE (is_identity_nat != 0))
-    *is_identity_nat = is_identity_static_mapping (m);
+  /* 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 void
-nat44_ei_worker_db_free (snat_main_per_thread_data_t *tsm)
+static int
+nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr)
 {
-  pool_free (tsm->list_pool);
-  pool_free (tsm->lru_pool);
-  pool_free (tsm->sessions);
-  pool_free (tsm->users);
-
-  clib_bihash_free_8_8 (&tsm->user_hash);
+  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;
 }
 
-static void
-nat44_ei_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
-                        u32 translation_buckets, u32 user_buckets)
+int
+nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
 {
-  dlist_elt_t *head;
+  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;
 
-  pool_alloc (tsm->list_pool, translations);
-  pool_alloc (tsm->lru_pool, translations);
-  pool_alloc (tsm->sessions, translations);
+  /* Find SNAT address */
+  for (i = 0; i < vec_len (nm->addresses); i++)
+    {
+      if (nm->addresses[i].addr.as_u32 == addr.as_u32)
+       {
+         a = nm->addresses + i;
+         break;
+       }
+    }
+  if (!a)
+    {
+      nat44_ei_log_err ("no such address");
+      return VNET_API_ERROR_NO_SUCH_ENTRY;
+    }
 
-  clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, 0);
+  if (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);
+       }
+    }
+  else
+    {
+      /* Check if address is used in some static mapping */
+      if (nat44_ei_is_address_used_in_static_mapping (addr))
+       {
+         nat44_ei_log_err ("address used in static mapping");
+         return VNET_API_ERROR_UNSPECIFIED;
+       }
+    }
 
-  clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
+  if (a->fib_index != ~0)
+    fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
 
-  pool_get (tsm->lru_pool, head);
-  tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
-  clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
+  /* Delete sessions using address */
+  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
+    {
+      vec_foreach (tnm, nm->per_thread_data)
+       {
+         pool_foreach (ses, tnm->sessions)
+           {
+             if (ses->out2in.addr.as_u32 == addr.as_u32)
+               {
+                 nat44_ei_free_session_data (nm, ses,
+                                             tnm - nm->per_thread_data, 0);
+                 vec_add1 (ses_to_be_removed, ses - tnm->sessions);
+               }
+           }
+         vec_foreach (ses_index, ses_to_be_removed)
+           {
+             ses = pool_elt_at_index (tnm->sessions, ses_index[0]);
+             nat44_ei_delete_session (nm, ses, tnm - nm->per_thread_data);
+           }
+         vec_free (ses_to_be_removed);
+       }
+    }
 
-  pool_get (tsm->lru_pool, head);
-  tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
-  clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
+#define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread);
+  foreach_nat_protocol
+#undef _
+    vec_del1 (nm->addresses, i);
 
-  pool_get (tsm->lru_pool, head);
-  tsm->udp_lru_head_index = head - tsm->lru_pool;
-  clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
+  /* Delete external address from FIB */
+  pool_foreach (interface, nm->interfaces)
+    {
+      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;
+    }
 
-  pool_get (tsm->lru_pool, head);
-  tsm->icmp_lru_head_index = head - tsm->lru_pool;
-  clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
+  pool_foreach (interface, nm->output_feature_interfaces)
+    {
+      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;
+    }
 
-  pool_get (tsm->lru_pool, head);
-  tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
-  clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
+  return 0;
 }
 
 static void
-nat44_ei_db_free ()
+nat44_ei_ip4_add_del_interface_address_cb (ip4_main_t *im, uword opaque,
+                                          u32 sw_if_index,
+                                          ip4_address_t *address,
+                                          u32 address_length,
+                                          u32 if_address_index, u32 is_delete)
 {
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
+  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;
+
+  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;
+    }
 
-  pool_free (sm->static_mappings);
-  clib_bihash_free_8_8 (&sm->static_mapping_by_local);
-  clib_bihash_free_8_8 (&sm->static_mapping_by_external);
+  return;
 
-  if (sm->pat)
+match:
+  if (!is_delete)
     {
-      clib_bihash_free_8_8 (&sm->in2out);
-      clib_bihash_free_8_8 (&sm->out2in);
-      vec_foreach (tsm, sm->per_thread_data)
+      /* 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;
+
+      (void) nat44_ei_add_address (nm, address, ~0);
+      /* Scan static map resolution vector */
+      for (j = 0; j < vec_len (nm->to_resolve); j++)
        {
-         nat44_ei_worker_db_free (tsm);
+         rp = nm->to_resolve + j;
+         if (rp->addr_only)
+           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);
+             if (rv)
+               nat_elog_notice_X1 (
+                 nm, "nat44_ei_add_del_static_mapping returned %d", "i4", rv);
+           }
        }
+      return;
     }
+  else
+    {
+      (void) nat44_ei_del_address (nm, address[0], 1);
+      return;
+    }
+}
+
+int
+nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts)
+{
+  fail_if_enabled ();
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nm->frame_queue_nelts = frame_queue_nelts;
+  return 0;
 }
 
 static void
-nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
+nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque,
+                                     u32 sw_if_index, ip4_address_t *address,
+                                     u32 address_length, u32 if_address_index,
+                                     u32 is_delete)
 {
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  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;
 
-  u32 static_mapping_buckets = 1024;
-  u32 static_mapping_memory_size = 64 << 20;
+  if (!nm->enabled)
+    return;
 
-  clib_bihash_init_8_8 (&sm->static_mapping_by_local,
-                       "static_mapping_by_local", static_mapping_buckets,
-                       static_mapping_memory_size);
-  clib_bihash_init_8_8 (&sm->static_mapping_by_external,
-                       "static_mapping_by_external", static_mapping_buckets,
-                       static_mapping_memory_size);
-  clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
-                                    format_static_mapping_kvp);
-  clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
-                                    format_static_mapping_kvp);
-
-  if (sm->pat)
-    {
-      clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets, 0);
-      clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets, 0);
-      clib_bihash_set_kvp_format_fn_8_8 (&sm->in2out, format_session_kvp);
-      clib_bihash_set_kvp_format_fn_8_8 (&sm->out2in, format_session_kvp);
-      vec_foreach (tsm, sm->per_thread_data)
-       {
-         nat44_ei_worker_db_init (tsm, translations, translation_buckets,
-                                  user_buckets);
-       }
+  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;
+    }
+
+  return;
+
+match:
+  init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port,
+             nm->outside_fib_index, rp->addr_only ? 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)
+    {
+      /* Don't trip over lease renewal, static config */
+      if (m)
+       return;
+    }
+  else
+    {
+      if (!m)
+       return;
     }
+
+  /* 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);
 }
 
-void
-nat44_ei_sessions_clear ()
+VLIB_NODE_FN (nat44_ei_classify_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
+  u32 n_left_from, *from, *to_next;
+  nat44_ei_classify_next_t next_index;
   nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m;
+  u32 next_in2out = 0, next_out2in = 0;
 
-  snat_main_per_thread_data_t *tsm;
-  snat_main_t *sm = &snat_main;
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
 
-  if (sm->pat)
+  while (n_left_from > 0)
     {
-      clib_bihash_free_8_8 (&sm->in2out);
-      clib_bihash_free_8_8 (&sm->out2in);
-      clib_bihash_init_8_8 (&sm->in2out, "in2out", nm->translation_buckets, 0);
-      clib_bihash_init_8_8 (&sm->out2in, "out2in", nm->translation_buckets, 0);
-      clib_bihash_set_kvp_format_fn_8_8 (&sm->in2out, format_session_kvp);
-      clib_bihash_set_kvp_format_fn_8_8 (&sm->out2in, format_session_kvp);
-      vec_foreach (tsm, sm->per_thread_data)
+      u32 n_left_to_next;
+
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      while (n_left_from > 0 && n_left_to_next > 0)
        {
-         nat44_ei_worker_db_free (tsm);
-         nat44_ei_worker_db_init (tsm, nm->translations,
-                                  nm->translation_buckets, nm->user_buckets);
+         u32 bi0;
+         vlib_buffer_t *b0;
+         u32 next0 = NAT44_EI_CLASSIFY_NEXT_IN2OUT;
+         ip4_header_t *ip0;
+         nat44_ei_address_t *ap;
+         clib_bihash_kv_8_8_t kv0, value0;
+
+         /* speculatively enqueue b0 to the current next frame */
+         bi0 = from[0];
+         to_next[0] = bi0;
+         from += 1;
+         to_next += 1;
+         n_left_from -= 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         ip0 = vlib_buffer_get_current (b0);
+
+         vec_foreach (ap, nm->addresses)
+           {
+             if (ip0->dst_address.as_u32 == ap->addr.as_u32)
+               {
+                 next0 = NAT44_EI_CLASSIFY_NEXT_OUT2IN;
+                 goto enqueue0;
+               }
+           }
+
+         if (PREDICT_FALSE (pool_elts (nm->static_mappings)))
+           {
+             init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
+             /* try to classify the fragment based on IP header alone */
+             if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external,
+                                          &kv0, &value0))
+               {
+                 m = pool_elt_at_index (nm->static_mappings, value0.value);
+                 if (m->local_addr.as_u32 != m->external_addr.as_u32)
+                   next0 = NAT44_EI_CLASSIFY_NEXT_OUT2IN;
+                 goto enqueue0;
+               }
+             init_nat_k (&kv0, ip0->dst_address,
+                         vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
+                         ip_proto_to_nat_proto (ip0->protocol));
+             if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external,
+                                          &kv0, &value0))
+               {
+                 m = pool_elt_at_index (nm->static_mappings, value0.value);
+                 if (m->local_addr.as_u32 != m->external_addr.as_u32)
+                   next0 = NAT44_EI_CLASSIFY_NEXT_OUT2IN;
+               }
+           }
+
+       enqueue0:
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             nat44_ei_classify_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->cached = 0;
+             t->next_in2out = next0 == NAT44_EI_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
+           }
+
+         next_in2out += next0 == NAT44_EI_CLASSIFY_NEXT_IN2OUT;
+         next_out2in += next0 == NAT44_EI_CLASSIFY_NEXT_OUT2IN;
+
+         /* verify speculative enqueue, maybe switch current next frame */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
        }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
 
-  // TODO: function for reset counters
-  vlib_zero_simple_counter (&sm->total_users, 0);
-  vlib_zero_simple_counter (&sm->total_sessions, 0);
-  vlib_zero_simple_counter (&sm->user_limit_reached, 0);
+  vlib_node_increment_counter (
+    vm, node->node_index, NAT44_EI_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
+  vlib_node_increment_counter (
+    vm, node->node_index, NAT44_EI_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
+  return frame->n_vectors;
 }
 
+VLIB_REGISTER_NODE (nat44_ei_classify_node) = {
+  .name = "nat44-ei-classify",
+  .vector_size = sizeof (u32),
+  .format_trace = format_nat44_ei_classify_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(nat44_ei_classify_error_strings),
+  .error_strings = nat44_ei_classify_error_strings,
+  .n_next_nodes = NAT44_EI_CLASSIFY_N_NEXT,
+  .next_nodes = {
+    [NAT44_EI_CLASSIFY_NEXT_IN2OUT] = "nat44-ei-in2out",
+    [NAT44_EI_CLASSIFY_NEXT_OUT2IN] = "nat44-ei-out2in",
+    [NAT44_EI_CLASSIFY_NEXT_DROP] = "error-drop",
+  },
+};
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 510e73d..b9212df 100644 (file)
 #ifndef __included_nat44_ei_h__
 #define __included_nat44_ei_h__
 
+#include <vlib/log.h>
+#include <vlibapi/api.h>
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/ip/icmp46_packet.h>
+#include <vnet/api_errno.h>
+#include <vnet/fib/fib_source.h>
+
+#include <vppinfra/dlist.h>
+#include <vppinfra/error.h>
+#include <vppinfra/bihash_8_8.h>
+
+#include <nat/lib/lib.h>
+#include <nat/lib/inlines.h>
+
+/* default number of worker handoff frame queue elements */
+#define NAT_FQ_NELTS_DEFAULT 64
+
+/* External address and port allocation modes */
+#define foreach_nat44_ei_addr_and_port_alloc_alg                              \
+  _ (0, DEFAULT, "default")                                                   \
+  _ (1, MAPE, "map-e")                                                        \
+  _ (2, RANGE, "port-range")
+
+typedef enum
+{
+#define _(v, N, s) NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_##N = v,
+  foreach_nat44_ei_addr_and_port_alloc_alg
+#undef _
+} nat44_ei_addr_and_port_alloc_alg_t;
+
+/* Interface flags */
+#define NAT44_EI_INTERFACE_FLAG_IS_INSIDE  (1 << 0)
+#define NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE (1 << 1)
+
+/* Session flags */
+#define NAT44_EI_SESSION_FLAG_STATIC_MAPPING (1 << 0)
+#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)
+
+typedef struct
+{
+  ip4_address_t addr;
+  u32 fib_index;
+#define _(N, i, n, s)                                                         \
+  u32 busy_##n##_ports;                                                       \
+  u32 *busy_##n##_ports_per_thread;                                           \
+  u32 busy_##n##_port_refcounts[65535];
+  foreach_nat_protocol
+#undef _
+} nat44_ei_address_t;
+
+clib_error_t *nat44_ei_api_hookup (vlib_main_t *vm);
+
+/* NAT address and port allocation function */
+typedef int (nat44_ei_alloc_out_addr_and_port_function_t) (
+  nat44_ei_address_t *addresses, u32 fib_index, u32 thread_index,
+  nat_protocol_t proto, ip4_address_t *addr, u16 *port, u16 port_per_thread,
+  u32 snat_thread_index);
+
+typedef struct
+{
+  u16 identifier;
+  u16 sequence;
+} icmp_echo_header_t;
+
+typedef struct
+{
+  u16 src_port, dst_port;
+} tcp_udp_header_t;
+
+typedef struct
+{
+  union
+  {
+    struct
+    {
+      ip4_address_t addr;
+      u32 fib_index;
+    };
+    u64 as_u64;
+  };
+} nat44_ei_user_key_t;
+
 typedef struct
 {
   /* maximum number of users */
@@ -39,15 +128,371 @@ typedef struct
 } nat44_ei_config_t;
 
 typedef struct
+{
+  ip4_address_t l_addr;
+  ip4_address_t pool_addr;
+  u16 l_port;
+  u16 e_port;
+  u32 sw_if_index;
+  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 */
+  ip4_address_t addr;
+  /* backend port number */
+  u16 port;
+  /* probability of the backend to be randomly matched */
+  u8 probability;
+  u8 prefix;
+  /* backend FIB table */
+  u32 vrf_id;
+  u32 fib_index;
+} nat44_ei_lb_addr_port_t;
+
+typedef struct
+{
+  /* prefered pool address */
+  ip4_address_t pool_addr;
+  /* local IP address */
+  ip4_address_t local_addr;
+  /* external IP address */
+  ip4_address_t external_addr;
+  /* local port */
+  u16 local_port;
+  /* external port */
+  u16 external_port;
+  /* local FIB table */
+  u32 vrf_id;
+  u32 fib_index;
+  /* protocol */
+  nat_protocol_t proto;
+  /* worker threads used by backends/local host */
+  u32 *workers;
+  /* opaque string tag */
+  u8 *tag;
+  /* backends for load-balancing mode */
+  nat44_ei_lb_addr_port_t *locals;
+  /* flags */
+  u32 flags;
+} nat44_ei_static_mapping_t;
+
+typedef struct
+{
+  u32 sw_if_index;
+  u8 flags;
+} nat44_ei_interface_t;
+
+typedef struct
+{
+  u32 fib_index;
+  u32 ref_count;
+} nat44_ei_fib_t;
+
+typedef struct
+{
+  u32 fib_index;
+  u32 refcount;
+} nat44_ei_outside_fib_t;
+
+typedef CLIB_PACKED (struct {
+  /* Outside network tuple */
+  struct
+  {
+    ip4_address_t addr;
+    u32 fib_index;
+    u16 port;
+  } out2in;
+
+  /* Inside network tuple */
+  struct
+  {
+    ip4_address_t addr;
+    u32 fib_index;
+    u16 port;
+  } in2out;
+
+  nat_protocol_t nat_proto;
+
+  /* Flags */
+  u32 flags;
+
+  /* Per-user translations */
+  u32 per_user_index;
+  u32 per_user_list_head_index;
+
+  /* head of LRU list in which this session is tracked */
+  u32 lru_head_index;
+  /* index in global LRU list */
+  u32 lru_index;
+  f64 last_lru_update;
+
+  /* Last heard timer */
+  f64 last_heard;
+
+  /* Last HA refresh */
+  f64 ha_last_refreshed;
+
+  /* Counters */
+  u64 total_bytes;
+  u32 total_pkts;
+
+  /* External host address and port */
+  ip4_address_t ext_host_addr;
+  u16 ext_host_port;
+
+  /* External host address and port after translation */
+  ip4_address_t ext_host_nat_addr;
+  u16 ext_host_nat_port;
+
+  /* TCP session state */
+  u8 state;
+  u32 i2o_fin_seq;
+  u32 o2i_fin_seq;
+  u64 tcp_closed_timestamp;
+
+  /* user index */
+  u32 user_index;
+}) nat44_ei_session_t;
+
+typedef CLIB_PACKED (struct {
+  ip4_address_t addr;
+  u32 fib_index;
+  u32 sessions_per_user_list_head_index;
+  u32 nsessions;
+  u32 nstaticsessions;
+}) nat44_ei_user_t;
+
+typedef struct
+{
+  /* Find-a-user => src address lookup */
+  clib_bihash_8_8_t user_hash;
+
+  /* User pool */
+  nat44_ei_user_t *users;
+
+  /* Session pool */
+  nat44_ei_session_t *sessions;
+
+  /* Pool of doubly-linked list elements */
+  dlist_elt_t *list_pool;
+
+  /* LRU session list - head is stale, tail is fresh */
+  dlist_elt_t *lru_pool;
+  u32 tcp_trans_lru_head_index;
+  u32 tcp_estab_lru_head_index;
+  u32 udp_lru_head_index;
+  u32 icmp_lru_head_index;
+  u32 unk_proto_lru_head_index;
+
+  /* NAT thread index */
+  u32 snat_thread_index;
+
+  /* real thread index */
+  u32 thread_index;
+
+} nat44_ei_main_per_thread_data_t;
+
+/* Return worker thread index for given packet */
+typedef u32 (nat44_ei_get_worker_in2out_function_t) (ip4_header_t *ip,
+                                                    u32 rx_fib_index,
+                                                    u8 is_output);
+
+typedef u32 (nat44_ei_get_worker_out2in_function_t) (vlib_buffer_t *b,
+                                                    ip4_header_t *ip,
+                                                    u32 rx_fib_index,
+                                                    u8 is_output);
+
+typedef struct
+{
+  u32 cached_sw_if_index;
+  u32 cached_ip4_address;
+} nat44_ei_runtime_t;
+
+typedef struct
+{
+  u32 thread_index;
+  f64 now;
+} nat44_ei_is_idle_session_ctx_t;
+
+typedef struct nat44_ei_main_s
 {
   u32 translations;
   u32 translation_buckets;
   u32 user_buckets;
 
+  u8 out2in_dpo;
+  u8 forwarding_enabled;
+  u8 static_mapping_only;
+  u8 static_mapping_connection_tracking;
+
+  u16 mss_clamping;
+
+  /* Find a static mapping by local */
+  clib_bihash_8_8_t static_mapping_by_local;
+
+  /* Find a static mapping by external */
+  clib_bihash_8_8_t static_mapping_by_external;
+
+  /* Static mapping pool */
+  nat44_ei_static_mapping_t *static_mappings;
+
+  /* Interface pool */
+  nat44_ei_interface_t *interfaces;
+  nat44_ei_interface_t *output_feature_interfaces;
+
+  /* Is translation memory size calculated or user defined */
+  u8 translation_memory_size_set;
+
+  u32 max_users_per_thread;
+  u32 max_translations_per_thread;
+  u32 max_translations_per_user;
+
+  u32 inside_vrf_id;
+  u32 inside_fib_index;
+
+  u32 outside_vrf_id;
+  u32 outside_fib_index;
+
+  /* Thread settings */
+  u32 num_workers;
+  u32 first_worker_index;
+  u32 *workers;
+  nat44_ei_get_worker_in2out_function_t *worker_in2out_cb;
+  nat44_ei_get_worker_out2in_function_t *worker_out2in_cb;
+  u16 port_per_thread;
+
+  /* Main lookup tables */
+  clib_bihash_8_8_t out2in;
+  clib_bihash_8_8_t in2out;
+
+  /* Per thread data */
+  nat44_ei_main_per_thread_data_t *per_thread_data;
+
+  /* Vector of outside addresses */
+  nat44_ei_address_t *addresses;
+
+  nat44_ei_alloc_out_addr_and_port_function_t *alloc_addr_and_port;
+  /* Address and port allocation type */
+  nat44_ei_addr_and_port_alloc_alg_t addr_and_port_alloc_alg;
+  /* Port set parameters (MAP-E) */
+  u8 psid_offset;
+  u8 psid_length;
+  u16 psid;
+  /* Port range parameters */
+  u16 start_port;
+  u16 end_port;
+
+  /* vector of fibs */
+  nat44_ei_fib_t *fibs;
+
+  /* vector of outside fibs */
+  nat44_ei_outside_fib_t *outside_fibs;
+
+  /* sw_if_indices whose intfc addresses should be auto-added */
+  u32 *auto_add_sw_if_indices;
+
+  /* vector of interface address static mappings to resolve. */
+  nat44_ei_static_map_resolve_t *to_resolve;
+
+  u32 in2out_node_index;
+  u32 out2in_node_index;
+  u32 in2out_output_node_index;
+
+  u32 fq_in2out_index;
+  u32 fq_in2out_output_index;
+  u32 fq_out2in_index;
+
+  /* Randomize port allocation order */
+  u32 random_seed;
+
+  nat_timeouts_t timeouts;
+
+  /* counters */
+  vlib_simple_counter_main_t total_users;
+  vlib_simple_counter_main_t total_sessions;
+  vlib_simple_counter_main_t user_limit_reached;
+
+#define _(x) vlib_simple_counter_main_t x;
+  struct
+  {
+    struct
+    {
+      struct
+      {
+       foreach_nat_counter;
+      } in2out;
+
+      struct
+      {
+       foreach_nat_counter;
+      } out2in;
+
+    } fastpath;
+
+    struct
+    {
+      struct
+      {
+       foreach_nat_counter;
+      } in2out;
+
+      struct
+      {
+       foreach_nat_counter;
+      } out2in;
+    } slowpath;
+
+    vlib_simple_counter_main_t hairpinning;
+  } counters;
+#undef _
+
+  /* API message ID base */
+  u16 msg_id_base;
+
+  /* log class */
+  vlib_log_class_t log_class;
+  /* logging level */
+  u8 log_level;
+
+  /* convenience */
+  api_main_t *api_main;
+  ip4_main_t *ip4_main;
+  ip_lookup_main_t *ip4_lookup_main;
+
+  fib_source_t fib_src_hi;
+  fib_source_t fib_src_low;
+
+  /* pat (port address translation)
+   * dynamic mapping enabled or conneciton tracking */
+  u8 pat;
+
+  /* number of worker handoff frame queue elements */
+  u32 frame_queue_nelts;
+
+  /* nat44 plugin enabled */
+  u8 enabled;
+
   nat44_ei_config_t rconfig;
 
+  u32 in2out_hairpinning_finish_ip4_lookup_node_fq_index;
+  u32 in2out_hairpinning_finish_interface_output_node_fq_index;
+  u32 hairpinning_fq_index;
+  u32 hairpin_dst_fq_index;
+
+  vnet_main_t *vnet_main;
 } nat44_ei_main_t;
 
+extern nat44_ei_main_t nat44_ei_main;
+
 int nat44_ei_plugin_enable (nat44_ei_config_t c);
 
 int nat44_ei_plugin_disable ();
@@ -66,11 +511,9 @@ int nat44_ei_user_del (ip4_address_t *addr, u32 fib_index);
  * @param addr         IPv4 address
  * @param fib_index    FIB table index
  */
-void nat44_ei_static_mapping_del_sessions (snat_main_t *sm,
-                                          snat_main_per_thread_data_t *tsm,
-                                          snat_user_key_t u_key,
-                                          int addr_only, ip4_address_t e_addr,
-                                          u16 e_port);
+void nat44_ei_static_mapping_del_sessions (
+  nat44_ei_main_t *nm, nat44_ei_main_per_thread_data_t *tnm,
+  nat44_ei_user_key_t u_key, int addr_only, ip4_address_t e_addr, u16 e_port);
 
 u32 nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
                                      u8 is_output);
@@ -135,7 +578,7 @@ int nat44_ei_add_del_static_mapping (ip4_address_t l_addr,
  *
  * @return 0 on success, non-zero value otherwise
  */
-int nat44_ei_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
+int nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
                          nat_protocol_t proto, u32 vrf_id, int is_in);
 
 /**
@@ -165,6 +608,100 @@ int nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
  */
 void nat44_ei_sessions_clear ();
 
+nat44_ei_user_t *nat44_ei_user_get_or_create (nat44_ei_main_t *nm,
+                                             ip4_address_t *addr,
+                                             u32 fib_index, u32 thread_index);
+
+nat44_ei_session_t *nat44_ei_session_alloc_or_recycle (nat44_ei_main_t *nm,
+                                                      nat44_ei_user_t *u,
+                                                      u32 thread_index,
+                                                      f64 now);
+
+void nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s,
+                                   u32 thread_index, u8 is_ha);
+
+void nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses,
+                                            u32 thread_index,
+                                            ip4_address_t *addr, u16 port,
+                                            nat_protocol_t protocol);
+
+int nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
+                                          u32 thread_index,
+                                          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);
+
+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);
+
+int nat44_ei_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node,
+                         nat44_ei_main_t *nm, u32 thread_index,
+                         vlib_buffer_t *b0, ip4_header_t *ip0,
+                         udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0,
+                         int do_trace, u32 *required_thread_index);
+
+void nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm,
+                                           vlib_buffer_t *b,
+                                           ip4_header_t *ip);
+
+u32 nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0,
+                              u32 thread_index, ip4_header_t *ip0,
+                              icmp46_header_t *icmp0,
+                              u32 *required_thread_index);
+
+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)
+
+#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)
+
+#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)
+
+/* logging */
+#define nat44_ei_log_err(...)                                                 \
+  vlib_log (VLIB_LOG_LEVEL_ERR, nat44_ei_main.log_class, __VA_ARGS__)
+#define nat44_ei_log_warn(...)                                                \
+  vlib_log (VLIB_LOG_LEVEL_WARNING, nat44_ei_main.log_class, __VA_ARGS__)
+#define nat44_ei_log_notice(...)                                              \
+  vlib_log (VLIB_LOG_LEVEL_NOTICE, nat44_ei_main.log_class, __VA_ARGS__)
+#define nat44_ei_log_info(...)                                                \
+  vlib_log (VLIB_LOG_LEVEL_INFO, nat44_ei_main.log_class, __VA_ARGS__)
+#define nat44_ei_log_debug(...)                                               \
+  vlib_log (VLIB_LOG_LEVEL_DEBUG, nat44_ei_main.log_class, __VA_ARGS__)
+
 #endif /* __included_nat44_ei_h__ */
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_api.c b/src/plugins/nat/nat44-ei/nat44_ei_api.c
new file mode 100644 (file)
index 0000000..74e0774
--- /dev/null
@@ -0,0 +1,1199 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ip/ip_types_api.h>
+#include <vlibmemory/api.h>
+
+#include <vnet/fib/fib_table.h>
+
+#include <nat/lib/nat_inlines.h>
+#include <nat/lib/ipfix_logging.h>
+
+#include <nat/nat44-ei/nat44_ei.api_enum.h>
+#include <nat/nat44-ei/nat44_ei.api_types.h>
+
+#include <nat/nat44-ei/nat44_ei_ha.h>
+#include <nat/nat44-ei/nat44_ei.h>
+
+#define REPLY_MSG_ID_BASE nm->msg_id_base
+#include <vlibapi/api_helper_macros.h>
+
+static void
+vl_api_nat44_ei_show_running_config_t_handler (
+  vl_api_nat44_ei_show_running_config_t *mp)
+{
+  vl_api_nat44_ei_show_running_config_reply_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_config_t *rc = &nm->rconfig;
+  int rv = 0;
+
+  REPLY_MACRO2_ZERO (
+    VL_API_NAT44_EI_SHOW_RUNNING_CONFIG_REPLY, ({
+      rmp->inside_vrf = htonl (rc->inside_vrf);
+      rmp->outside_vrf = htonl (rc->outside_vrf);
+      rmp->users = htonl (rc->users);
+      rmp->sessions = htonl (rc->sessions);
+      rmp->user_sessions = htonl (rc->user_sessions);
+
+      rmp->user_buckets = htonl (nm->user_buckets);
+      rmp->translation_buckets = htonl (nm->translation_buckets);
+
+      rmp->timeouts.udp = htonl (nm->timeouts.udp);
+      rmp->timeouts.tcp_established = htonl (nm->timeouts.tcp.established);
+      rmp->timeouts.tcp_transitory = htonl (nm->timeouts.tcp.transitory);
+      rmp->timeouts.icmp = htonl (nm->timeouts.icmp);
+
+      rmp->forwarding_enabled = nm->forwarding_enabled == 1;
+      // consider how to split functionality between subplugins
+      rmp->ipfix_logging_enabled = nat_ipfix_logging_enabled ();
+
+      if (rc->static_mapping_only)
+       rmp->flags |= NAT44_EI_STATIC_MAPPING_ONLY;
+      if (rc->connection_tracking)
+       rmp->flags |= NAT44_EI_CONNECTION_TRACKING;
+      if (rc->out2in_dpo)
+       rmp->flags |= NAT44_EI_OUT2IN_DPO;
+    }));
+}
+
+static void
+vl_api_nat44_ei_set_workers_t_handler (vl_api_nat44_ei_set_workers_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_set_workers_reply_t *rmp;
+  int rv = 0;
+  uword *bitmap = 0;
+  u64 mask;
+
+  mask = clib_net_to_host_u64 (mp->worker_mask);
+
+  if (nm->num_workers < 2)
+    {
+      rv = VNET_API_ERROR_FEATURE_DISABLED;
+      goto send_reply;
+    }
+
+  bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask));
+  rv = nat44_ei_set_workers (bitmap);
+  clib_bitmap_free (bitmap);
+
+send_reply:
+  REPLY_MACRO (VL_API_NAT44_EI_SET_WORKERS_REPLY);
+}
+
+static void
+send_nat_worker_details (u32 worker_index, vl_api_registration_t *reg,
+                        u32 context)
+{
+  vl_api_nat44_ei_worker_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vlib_worker_thread_t *w =
+    vlib_worker_threads + worker_index + nm->first_worker_index;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_NAT44_EI_WORKER_DETAILS + nm->msg_id_base);
+  rmp->context = context;
+  rmp->worker_index = htonl (worker_index);
+  rmp->lcore_id = htonl (w->cpu_id);
+  strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1);
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_worker_dump_t_handler (vl_api_nat44_ei_worker_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 *worker_index;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  vec_foreach (worker_index, nm->workers)
+    {
+      send_nat_worker_details (*worker_index, reg, mp->context);
+    }
+}
+
+static void
+vl_api_nat44_ei_set_log_level_t_handler (vl_api_nat44_ei_set_log_level_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_set_log_level_reply_t *rmp;
+  int rv = 0;
+
+  if (nm->log_level > NAT_LOG_DEBUG)
+    rv = VNET_API_ERROR_UNSUPPORTED;
+  else
+    nm->log_level = mp->log_level;
+
+  REPLY_MACRO (VL_API_NAT44_EI_SET_LOG_LEVEL_REPLY);
+}
+
+static void
+vl_api_nat44_ei_plugin_enable_disable_t_handler (
+  vl_api_nat44_ei_plugin_enable_disable_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_config_t c = { 0 };
+  vl_api_nat44_ei_plugin_enable_disable_reply_t *rmp;
+  int rv = 0;
+
+  if (mp->enable)
+    {
+      c.static_mapping_only = mp->flags & NAT44_EI_STATIC_MAPPING_ONLY;
+      c.connection_tracking = mp->flags & NAT44_EI_CONNECTION_TRACKING;
+      c.out2in_dpo = mp->flags & NAT44_EI_OUT2IN_DPO;
+
+      c.inside_vrf = ntohl (mp->inside_vrf);
+      c.outside_vrf = ntohl (mp->outside_vrf);
+
+      c.users = ntohl (mp->users);
+
+      c.sessions = ntohl (mp->sessions);
+
+      c.user_sessions = ntohl (mp->user_sessions);
+
+      rv = nat44_ei_plugin_enable (c);
+    }
+  else
+    rv = nat44_ei_plugin_disable ();
+
+  REPLY_MACRO (VL_API_NAT44_EI_PLUGIN_ENABLE_DISABLE_REPLY);
+}
+
+static void
+vl_api_nat44_ei_ipfix_enable_disable_t_handler (
+  vl_api_nat44_ei_ipfix_enable_disable_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ipfix_enable_disable_reply_t *rmp;
+  int rv = 0;
+
+  rv = nat_ipfix_logging_enable_disable (mp->enable,
+                                        clib_host_to_net_u32 (mp->domain_id),
+                                        clib_host_to_net_u16 (mp->src_port));
+
+  REPLY_MACRO (VL_API_NAT44_EI_IPFIX_ENABLE_DISABLE_REPLY);
+}
+
+static void
+vl_api_nat44_ei_set_timeouts_t_handler (vl_api_nat44_ei_set_timeouts_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_set_timeouts_reply_t *rmp;
+  int rv = 0;
+
+  nm->timeouts.udp = ntohl (mp->udp);
+  nm->timeouts.tcp.established = ntohl (mp->tcp_established);
+  nm->timeouts.tcp.transitory = ntohl (mp->tcp_transitory);
+  nm->timeouts.icmp = ntohl (mp->icmp);
+
+  REPLY_MACRO (VL_API_NAT44_EI_SET_TIMEOUTS_REPLY);
+}
+
+static void
+vl_api_nat44_ei_set_addr_and_port_alloc_alg_t_handler (
+  vl_api_nat44_ei_set_addr_and_port_alloc_alg_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_set_addr_and_port_alloc_alg_reply_t *rmp;
+  int rv = 0;
+  u16 port_start, port_end;
+
+  switch (mp->alg)
+    {
+    case NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_DEFAULT:
+      nat44_ei_set_alloc_default ();
+      break;
+    case NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_MAPE:
+      nat44_ei_set_alloc_mape (ntohs (mp->psid), mp->psid_offset,
+                              mp->psid_length);
+      break;
+    case NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_RANGE:
+      port_start = ntohs (mp->start_port);
+      port_end = ntohs (mp->end_port);
+      if (port_end <= port_start)
+       {
+         rv = VNET_API_ERROR_INVALID_VALUE;
+         goto send_reply;
+       }
+      nat44_ei_set_alloc_range (port_start, port_end);
+      break;
+    default:
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      break;
+    }
+
+send_reply:
+  REPLY_MACRO (VL_API_NAT44_EI_SET_ADDR_AND_PORT_ALLOC_ALG_REPLY);
+}
+
+static void
+vl_api_nat44_ei_get_addr_and_port_alloc_alg_t_handler (
+  vl_api_nat44_ei_get_addr_and_port_alloc_alg_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_get_addr_and_port_alloc_alg_reply_t *rmp;
+  int rv = 0;
+
+  REPLY_MACRO2 (VL_API_NAT44_EI_GET_ADDR_AND_PORT_ALLOC_ALG_REPLY, ({
+                 rmp->alg = nm->addr_and_port_alloc_alg;
+                 rmp->psid_offset = nm->psid_offset;
+                 rmp->psid_length = nm->psid_length;
+                 rmp->psid = htons (nm->psid);
+                 rmp->start_port = htons (nm->start_port);
+                 rmp->end_port = htons (nm->end_port);
+               }))
+}
+
+static void
+vl_api_nat44_ei_set_mss_clamping_t_handler (
+  vl_api_nat44_ei_set_mss_clamping_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_set_mss_clamping_reply_t *rmp;
+  int rv = 0;
+
+  if (mp->enable)
+    nm->mss_clamping = ntohs (mp->mss_value);
+  else
+    nm->mss_clamping = 0;
+
+  REPLY_MACRO (VL_API_NAT44_EI_SET_MSS_CLAMPING_REPLY);
+}
+
+static void
+vl_api_nat44_ei_get_mss_clamping_t_handler (
+  vl_api_nat44_ei_get_mss_clamping_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_get_mss_clamping_reply_t *rmp;
+  int rv = 0;
+
+  REPLY_MACRO2 (VL_API_NAT44_EI_GET_MSS_CLAMPING_REPLY, ({
+                 rmp->enable = nm->mss_clamping ? 1 : 0;
+                 rmp->mss_value = htons (nm->mss_clamping);
+               }))
+}
+
+static void
+vl_api_nat44_ei_ha_set_listener_t_handler (
+  vl_api_nat44_ei_ha_set_listener_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ha_set_listener_reply_t *rmp;
+  ip4_address_t addr;
+  int rv;
+
+  memcpy (&addr, &mp->ip_address, sizeof (addr));
+  rv = nat_ha_set_listener (&addr, clib_net_to_host_u16 (mp->port),
+                           clib_net_to_host_u32 (mp->path_mtu));
+
+  REPLY_MACRO (VL_API_NAT44_EI_HA_SET_LISTENER_REPLY);
+}
+
+static void
+vl_api_nat44_ei_ha_get_listener_t_handler (
+  vl_api_nat44_ei_ha_get_listener_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ha_get_listener_reply_t *rmp;
+  int rv = 0;
+  ip4_address_t addr;
+  u16 port;
+  u32 path_mtu;
+
+  nat_ha_get_listener (&addr, &port, &path_mtu);
+
+  REPLY_MACRO2 (VL_API_NAT44_EI_HA_GET_LISTENER_REPLY, ({
+                 clib_memcpy (rmp->ip_address, &addr, sizeof (ip4_address_t));
+                 rmp->port = clib_host_to_net_u16 (port);
+                 rmp->path_mtu = clib_host_to_net_u32 (path_mtu);
+               }))
+}
+
+static void
+vl_api_nat44_ei_ha_set_failover_t_handler (
+  vl_api_nat44_ei_ha_set_failover_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ha_set_failover_reply_t *rmp;
+  ip4_address_t addr;
+  int rv;
+
+  memcpy (&addr, &mp->ip_address, sizeof (addr));
+  rv =
+    nat_ha_set_failover (&addr, clib_net_to_host_u16 (mp->port),
+                        clib_net_to_host_u32 (mp->session_refresh_interval));
+
+  REPLY_MACRO (VL_API_NAT44_EI_HA_SET_FAILOVER_REPLY);
+}
+
+static void
+vl_api_nat44_ei_ha_get_failover_t_handler (
+  vl_api_nat44_ei_ha_get_failover_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ha_get_failover_reply_t *rmp;
+  int rv = 0;
+  ip4_address_t addr;
+  u16 port;
+  u32 session_refresh_interval;
+
+  nat_ha_get_failover (&addr, &port, &session_refresh_interval);
+
+  REPLY_MACRO2 (VL_API_NAT44_EI_HA_GET_FAILOVER_REPLY, ({
+                 clib_memcpy (rmp->ip_address, &addr, sizeof (ip4_address_t));
+                 rmp->port = clib_host_to_net_u16 (port);
+                 rmp->session_refresh_interval =
+                   clib_host_to_net_u32 (session_refresh_interval);
+               }))
+}
+
+static void
+vl_api_nat44_ei_ha_flush_t_handler (vl_api_nat44_ei_ha_flush_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ha_flush_reply_t *rmp;
+  int rv = 0;
+
+  nat_ha_flush (0);
+
+  REPLY_MACRO (VL_API_NAT44_EI_HA_FLUSH_REPLY);
+}
+
+static void
+nat_ha_resync_completed_event_cb (u32 client_index, u32 pid, u32 missed_count)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_registration_t *reg;
+  vl_api_nat44_ei_ha_resync_completed_event_t *mp;
+
+  reg = vl_api_client_index_to_registration (client_index);
+  if (!reg)
+    return;
+
+  mp = vl_msg_api_alloc (sizeof (*mp));
+  clib_memset (mp, 0, sizeof (*mp));
+  mp->client_index = client_index;
+  mp->pid = pid;
+  mp->missed_count = clib_host_to_net_u32 (missed_count);
+  mp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_HA_RESYNC_COMPLETED_EVENT + nm->msg_id_base);
+
+  vl_api_send_msg (reg, (u8 *) mp);
+}
+
+static void
+vl_api_nat44_ei_ha_resync_t_handler (vl_api_nat44_ei_ha_resync_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_ha_resync_reply_t *rmp;
+  int rv;
+
+  rv = nat_ha_resync (
+    mp->client_index, mp->pid,
+    mp->want_resync_event ? nat_ha_resync_completed_event_cb : NULL);
+
+  REPLY_MACRO (VL_API_NAT44_EI_HA_RESYNC_REPLY);
+}
+
+static void
+vl_api_nat44_ei_del_user_t_handler (vl_api_nat44_ei_del_user_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_del_user_reply_t *rmp;
+  ip4_address_t addr;
+  int rv;
+  memcpy (&addr.as_u8, mp->ip_address, 4);
+  rv = nat44_ei_user_del (&addr, ntohl (mp->fib_index));
+  REPLY_MACRO (VL_API_NAT44_EI_DEL_USER_REPLY);
+}
+
+static void
+vl_api_nat44_ei_add_del_address_range_t_handler (
+  vl_api_nat44_ei_add_del_address_range_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_add_del_address_range_reply_t *rmp;
+  ip4_address_t this_addr;
+  u8 is_add;
+  u32 start_host_order, end_host_order;
+  u32 vrf_id;
+  int i, count;
+  int rv = 0;
+  u32 *tmp;
+
+  if (nm->static_mapping_only)
+    {
+      rv = VNET_API_ERROR_FEATURE_DISABLED;
+      goto send_reply;
+    }
+
+  is_add = mp->is_add;
+
+  tmp = (u32 *) mp->first_ip_address;
+  start_host_order = clib_host_to_net_u32 (tmp[0]);
+  tmp = (u32 *) mp->last_ip_address;
+  end_host_order = clib_host_to_net_u32 (tmp[0]);
+
+  count = (end_host_order - start_host_order) + 1;
+
+  vrf_id = clib_host_to_net_u32 (mp->vrf_id);
+
+  if (count > 1024)
+    nat44_ei_log_info ("%U - %U, %d addresses...", format_ip4_address,
+                      mp->first_ip_address, format_ip4_address,
+                      mp->last_ip_address, count);
+
+  memcpy (&this_addr.as_u8, mp->first_ip_address, 4);
+
+  for (i = 0; i < count; i++)
+    {
+      if (is_add)
+       rv = nat44_ei_add_address (nm, &this_addr, vrf_id);
+      else
+       rv = nat44_ei_del_address (nm, this_addr, 0);
+
+      if (rv)
+       goto send_reply;
+
+      if (nm->out2in_dpo)
+       nat44_ei_add_del_address_dpo (this_addr, is_add);
+
+      increment_v4_address (&this_addr);
+    }
+
+send_reply:
+  REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_ADDRESS_RANGE_REPLY);
+}
+
+static void
+send_nat44_ei_address_details (nat44_ei_address_t *a,
+                              vl_api_registration_t *reg, u32 context)
+{
+  vl_api_nat44_ei_address_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_NAT44_EI_ADDRESS_DETAILS + nm->msg_id_base);
+  clib_memcpy (rmp->ip_address, &(a->addr), 4);
+  if (a->fib_index != ~0)
+    {
+      fib_table_t *fib = fib_table_get (a->fib_index, FIB_PROTOCOL_IP4);
+      rmp->vrf_id = ntohl (fib->ft_table_id);
+    }
+  else
+    rmp->vrf_id = ~0;
+  rmp->context = context;
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_address_dump_t_handler (vl_api_nat44_ei_address_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *a;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  vec_foreach (a, nm->addresses)
+    {
+      send_nat44_ei_address_details (a, reg, mp->context);
+    }
+}
+
+static void
+vl_api_nat44_ei_interface_add_del_feature_t_handler (
+  vl_api_nat44_ei_interface_add_del_feature_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_interface_add_del_feature_reply_t *rmp;
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  u8 is_del;
+  int rv = 0;
+
+  is_del = !mp->is_add;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  rv = nat44_ei_interface_add_del (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE,
+                                  is_del);
+
+  BAD_SW_IF_INDEX_LABEL;
+
+  REPLY_MACRO (VL_API_NAT44_EI_INTERFACE_ADD_DEL_FEATURE_REPLY);
+}
+
+static void
+send_nat44_ei_interface_details (nat44_ei_interface_t *i,
+                                vl_api_registration_t *reg, u32 context)
+{
+  vl_api_nat44_ei_interface_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_INTERFACE_DETAILS + nm->msg_id_base);
+  rmp->sw_if_index = ntohl (i->sw_if_index);
+
+  if (nat44_ei_interface_is_inside (i))
+    rmp->flags |= NAT44_EI_IF_INSIDE;
+  if (nat44_ei_interface_is_outside (i))
+    rmp->flags |= NAT44_EI_IF_OUTSIDE;
+
+  rmp->context = context;
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_interface_dump_t_handler (vl_api_nat44_ei_interface_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  pool_foreach (i, nm->interfaces)
+    {
+      send_nat44_ei_interface_details (i, reg, mp->context);
+    }
+}
+
+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);
+  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);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_NAT44_EI_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY);
+}
+
+static void
+send_nat44_ei_interface_output_feature_details (nat44_ei_interface_t *i,
+                                               vl_api_registration_t *reg,
+                                               u32 context)
+{
+  vl_api_nat44_ei_interface_output_feature_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_INTERFACE_OUTPUT_FEATURE_DETAILS + nm->msg_id_base);
+  rmp->sw_if_index = ntohl (i->sw_if_index);
+  rmp->context = context;
+
+  if (nat44_ei_interface_is_inside (i))
+    rmp->flags |= NAT44_EI_IF_INSIDE;
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_interface_output_feature_dump_t_handler (
+  vl_api_nat44_ei_interface_output_feature_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  pool_foreach (i, nm->output_feature_interfaces)
+    {
+      send_nat44_ei_interface_output_feature_details (i, reg, 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;
+  int rv = 0;
+  nat_protocol_t proto;
+  u8 *tag = 0;
+
+  memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
+  memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
+
+  if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING))
+    {
+      local_port = mp->local_port;
+      external_port = mp->external_port;
+    }
+
+  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);
+
+  vec_free (tag);
+
+  REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_STATIC_MAPPING_REPLY);
+}
+
+static void
+send_nat44_ei_static_mapping_details (nat44_ei_static_mapping_t *m,
+                                     vl_api_registration_t *reg, u32 context)
+{
+  vl_api_nat44_ei_static_mapping_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 len = sizeof (*rmp);
+
+  rmp = vl_msg_api_alloc (len);
+  clib_memset (rmp, 0, len);
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_STATIC_MAPPING_DETAILS + nm->msg_id_base);
+
+  clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4);
+  clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4);
+  rmp->external_sw_if_index = ~0;
+  rmp->vrf_id = htonl (m->vrf_id);
+  rmp->context = context;
+
+  if (nat44_ei_is_addr_only_static_mapping (m))
+    {
+      rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
+    }
+  else
+    {
+      rmp->protocol = nat_proto_to_ip_proto (m->proto);
+      rmp->external_port = m->external_port;
+      rmp->local_port = m->local_port;
+    }
+
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+send_nat44_ei_static_map_resolve_details (nat44_ei_static_map_resolve_t *m,
+                                         vl_api_registration_t *reg,
+                                         u32 context)
+{
+  vl_api_nat44_ei_static_mapping_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_STATIC_MAPPING_DETAILS + nm->msg_id_base);
+  clib_memcpy (rmp->local_ip_address, &(m->l_addr), 4);
+  rmp->external_sw_if_index = htonl (m->sw_if_index);
+  rmp->vrf_id = htonl (m->vrf_id);
+  rmp->context = context;
+
+  if (m->addr_only)
+    {
+      rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
+    }
+  else
+    {
+      rmp->protocol = nat_proto_to_ip_proto (m->proto);
+      rmp->external_port = m->e_port;
+      rmp->local_port = m->l_port;
+    }
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_static_mapping_dump_t_handler (
+  vl_api_nat44_ei_static_mapping_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m;
+  nat44_ei_static_map_resolve_t *rp;
+  int j;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  pool_foreach (m, nm->static_mappings)
+    {
+      if (!nat44_ei_is_identity_static_mapping (m))
+       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)
+       send_nat44_ei_static_map_resolve_details (rp, reg, mp->context);
+    }
+}
+
+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;
+  int rv = 0;
+  nat_protocol_t proto = NAT_PROTOCOL_OTHER;
+  u8 *tag = 0;
+
+  if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING))
+    {
+      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;
+  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);
+
+  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);
+
+  vec_free (tag);
+
+  REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_IDENTITY_MAPPING_REPLY);
+}
+
+static void
+send_nat44_ei_identity_mapping_details (nat44_ei_static_mapping_t *m,
+                                       int index, vl_api_registration_t *reg,
+                                       u32 context)
+{
+  vl_api_nat44_ei_identity_mapping_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_lb_addr_port_t *local = pool_elt_at_index (m->locals, index);
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  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))
+    rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
+
+  clib_memcpy (rmp->ip_address, &(m->local_addr), 4);
+  rmp->port = m->local_port;
+  rmp->sw_if_index = ~0;
+  rmp->vrf_id = htonl (local->vrf_id);
+  rmp->protocol = nat_proto_to_ip_proto (m->proto);
+  rmp->context = context;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+send_nat44_ei_identity_map_resolve_details (nat44_ei_static_map_resolve_t *m,
+                                           vl_api_registration_t *reg,
+                                           u32 context)
+{
+  vl_api_nat44_ei_identity_mapping_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base);
+
+  if (m->addr_only)
+    rmp->flags = (vl_api_nat44_ei_config_flags_t) NAT44_EI_ADDR_ONLY_MAPPING;
+
+  rmp->port = m->l_port;
+  rmp->sw_if_index = htonl (m->sw_if_index);
+  rmp->vrf_id = htonl (m->vrf_id);
+  rmp->protocol = nat_proto_to_ip_proto (m->proto);
+  rmp->context = context;
+  if (m->tag)
+    strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_identity_mapping_dump_t_handler (
+  vl_api_nat44_ei_identity_mapping_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m;
+  nat44_ei_static_map_resolve_t *rp;
+  int j;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  pool_foreach (m, nm->static_mappings)
+    {
+      if (nat44_ei_is_identity_static_mapping (m))
+       {
+         pool_foreach_index (j, m->locals)
+           {
+             send_nat44_ei_identity_mapping_details (m, j, reg, mp->context);
+           }
+       }
+    }
+
+  for (j = 0; j < vec_len (nm->to_resolve); j++)
+    {
+      rp = nm->to_resolve + j;
+      if (rp->identity_nat)
+       send_nat44_ei_identity_map_resolve_details (rp, reg, mp->context);
+    }
+}
+
+static void
+vl_api_nat44_ei_add_del_interface_addr_t_handler (
+  vl_api_nat44_ei_add_del_interface_addr_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  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);
+
+  BAD_SW_IF_INDEX_LABEL;
+  REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_INTERFACE_ADDR_REPLY);
+}
+
+static void
+send_nat44_ei_interface_addr_details (u32 sw_if_index,
+                                     vl_api_registration_t *reg, u32 context)
+{
+  vl_api_nat44_ei_interface_addr_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_INTERFACE_ADDR_DETAILS + nm->msg_id_base);
+  rmp->sw_if_index = ntohl (sw_if_index);
+  rmp->context = context;
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_interface_addr_dump_t_handler (
+  vl_api_nat44_ei_interface_addr_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 *i;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  vec_foreach (i, nm->auto_add_sw_if_indices)
+    send_nat44_ei_interface_addr_details (*i, reg, mp->context);
+}
+
+static void
+send_nat44_ei_user_details (nat44_ei_user_t *u, vl_api_registration_t *reg,
+                           u32 context)
+{
+  vl_api_nat44_ei_user_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  ip4_main_t *im = &ip4_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_NAT44_EI_USER_DETAILS + nm->msg_id_base);
+
+  if (!pool_is_free_index (im->fibs, u->fib_index))
+    {
+      fib_table_t *fib = fib_table_get (u->fib_index, FIB_PROTOCOL_IP4);
+      rmp->vrf_id = ntohl (fib->ft_table_id);
+    }
+
+  clib_memcpy (rmp->ip_address, &(u->addr), 4);
+  rmp->nsessions = ntohl (u->nsessions);
+  rmp->nstaticsessions = ntohl (u->nstaticsessions);
+  rmp->context = context;
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_user_dump_t_handler (vl_api_nat44_ei_user_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+  nat44_ei_user_t *u;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  vec_foreach (tnm, nm->per_thread_data)
+    {
+      pool_foreach (u, tnm->users)
+       {
+         send_nat44_ei_user_details (u, reg, mp->context);
+       }
+    }
+}
+
+static void
+send_nat44_ei_user_session_details (nat44_ei_session_t *s,
+                                   vl_api_registration_t *reg, u32 context)
+{
+  vl_api_nat44_ei_user_session_details_t *rmp;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (VL_API_NAT44_EI_USER_SESSION_DETAILS + nm->msg_id_base);
+  clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4);
+  clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4);
+
+  if (nat44_ei_is_session_static (s))
+    rmp->flags |= NAT44_EI_STATIC_MAPPING;
+
+  rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard);
+  rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes);
+  rmp->total_pkts = ntohl (s->total_pkts);
+  rmp->context = context;
+  if (nat44_ei_is_unk_proto_session (s))
+    {
+      rmp->outside_port = 0;
+      rmp->inside_port = 0;
+      rmp->protocol = ntohs (s->in2out.port);
+    }
+  else
+    {
+      rmp->outside_port = s->out2in.port;
+      rmp->inside_port = s->in2out.port;
+      rmp->protocol = ntohs (nat_proto_to_ip_proto (s->nat_proto));
+    }
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_nat44_ei_user_session_dump_t_handler (
+  vl_api_nat44_ei_user_session_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+  nat44_ei_session_t *s;
+  clib_bihash_kv_8_8_t key, value;
+  nat44_ei_user_key_t ukey;
+  nat44_ei_user_t *u;
+  u32 session_index, head_index, elt_index;
+  dlist_elt_t *head, *elt;
+  ip4_header_t ip;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  clib_memcpy (&ukey.addr, mp->ip_address, 4);
+  ip.src_address.as_u32 = ukey.addr.as_u32;
+  ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id));
+  key.key = ukey.as_u64;
+  if (nm->num_workers > 1)
+    tnm = vec_elt_at_index (nm->per_thread_data,
+                           nm->worker_in2out_cb (&ip, ukey.fib_index, 0));
+  else
+    tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
+
+  if (clib_bihash_search_8_8 (&tnm->user_hash, &key, &value))
+    return;
+  u = pool_elt_at_index (tnm->users, value.value);
+  if (!u->nsessions && !u->nstaticsessions)
+    return;
+
+  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);
+  session_index = elt->value;
+  while (session_index != ~0)
+    {
+      s = pool_elt_at_index (tnm->sessions, session_index);
+
+      send_nat44_ei_user_session_details (s, reg, mp->context);
+
+      elt_index = elt->next;
+      elt = pool_elt_at_index (tnm->list_pool, elt_index);
+      session_index = elt->value;
+    }
+}
+
+static void
+vl_api_nat44_ei_del_session_t_handler (vl_api_nat44_ei_del_session_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_del_session_reply_t *rmp;
+  ip4_address_t addr, eh_addr;
+  u16 port;
+  u32 vrf_id;
+  int rv = 0;
+  u8 is_in;
+  nat_protocol_t proto;
+
+  memcpy (&addr.as_u8, mp->address, 4);
+  port = mp->port;
+  vrf_id = clib_net_to_host_u32 (mp->vrf_id);
+  proto = ip_proto_to_nat_proto (mp->protocol);
+  memcpy (&eh_addr.as_u8, mp->ext_host_address, 4);
+
+  // is session inside ?
+  is_in = mp->flags & NAT44_EI_IF_INSIDE;
+
+  rv = nat44_ei_del_session (nm, &addr, port, proto, vrf_id, is_in);
+
+  REPLY_MACRO (VL_API_NAT44_EI_DEL_SESSION_REPLY);
+}
+
+static void
+vl_api_nat44_ei_forwarding_enable_disable_t_handler (
+  vl_api_nat44_ei_forwarding_enable_disable_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_forwarding_enable_disable_reply_t *rmp;
+  int rv = 0;
+  u32 *ses_to_be_removed = 0, *ses_index;
+  nat44_ei_main_per_thread_data_t *tnm;
+  nat44_ei_session_t *s;
+
+  nm->forwarding_enabled = mp->enable != 0;
+
+  if (mp->enable == 0)
+    {
+      vec_foreach (tnm, nm->per_thread_data)
+       {
+         vec_foreach (ses_index, ses_to_be_removed)
+           {
+             s = pool_elt_at_index (tnm->sessions, ses_index[0]);
+             nat44_ei_free_session_data (nm, s, tnm - nm->per_thread_data, 0);
+             nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
+           }
+
+         vec_free (ses_to_be_removed);
+       }
+    }
+
+  REPLY_MACRO (VL_API_NAT44_EI_FORWARDING_ENABLE_DISABLE_REPLY);
+}
+
+static void
+vl_api_nat44_ei_set_fq_options_t_handler (vl_api_nat44_ei_set_fq_options_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_set_fq_options_reply_t *rmp;
+  int rv = 0;
+  u32 frame_queue_nelts = ntohl (mp->frame_queue_nelts);
+  rv = nat44_ei_set_frame_queue_nelts (frame_queue_nelts);
+  REPLY_MACRO (VL_API_NAT44_EI_SET_FQ_OPTIONS_REPLY);
+}
+
+static void
+vl_api_nat44_ei_show_fq_options_t_handler (
+  vl_api_nat44_ei_show_fq_options_t *mp)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vl_api_nat44_ei_show_fq_options_reply_t *rmp;
+  int rv = 0;
+  /* clang-format off */
+  REPLY_MACRO2_ZERO (VL_API_NAT44_EI_SHOW_FQ_OPTIONS_REPLY,
+  ({
+    rmp->frame_queue_nelts = htonl (nm->frame_queue_nelts);
+  }));
+  /* clang-format on */
+}
+
+/* API definitions */
+#include <vnet/format_fns.h>
+#include <nat/nat44-ei/nat44_ei.api.c>
+
+/* Set up the API message handling tables */
+clib_error_t *
+nat44_ei_api_hookup (vlib_main_t *vm)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nm->msg_id_base = setup_message_id_table ();
+  return 0;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_cli.c b/src/plugins/nat/nat44-ei/nat44_ei_cli.c
new file mode 100644 (file)
index 0000000..3aa3a2f
--- /dev/null
@@ -0,0 +1,2025 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/fib/fib_table.h>
+
+#include <nat/lib/log.h>
+#include <nat/lib/nat_inlines.h>
+#include <nat/lib/ipfix_logging.h>
+
+#include <nat/nat44-ei/nat44_ei.h>
+#include <nat/nat44-ei/nat44_ei_ha.h>
+
+u8 *
+format_nat44_ei_session (u8 *s, va_list *args)
+{
+  nat44_ei_main_per_thread_data_t *tnm =
+    va_arg (*args, nat44_ei_main_per_thread_data_t *);
+  nat44_ei_session_t *sess = va_arg (*args, nat44_ei_session_t *);
+
+  if (nat44_ei_is_unk_proto_session (sess))
+    {
+      s =
+       format (s, "  i2o %U proto %u fib %u\n", format_ip4_address,
+               &sess->in2out.addr, sess->in2out.port, sess->in2out.fib_index);
+      s =
+       format (s, "  o2i %U proto %u fib %u\n", format_ip4_address,
+               &sess->out2in.addr, sess->out2in.port, sess->out2in.fib_index);
+    }
+  else
+    {
+      s = format (s, "  i2o %U proto %U port %d fib %d\n", format_ip4_address,
+                 &sess->in2out.addr, format_nat_protocol, sess->nat_proto,
+                 clib_net_to_host_u16 (sess->in2out.port),
+                 sess->in2out.fib_index);
+      s = format (s, "  o2i %U proto %U port %d fib %d\n", format_ip4_address,
+                 &sess->out2in.addr, format_nat_protocol, sess->nat_proto,
+                 clib_net_to_host_u16 (sess->out2in.port),
+                 sess->out2in.fib_index);
+    }
+
+  s = format (s, "       index %llu\n", sess - tnm->sessions);
+  s = format (s, "       last heard %.2f\n", sess->last_heard);
+  s = format (s, "       total pkts %d, total bytes %lld\n", sess->total_pkts,
+             sess->total_bytes);
+  if (nat44_ei_is_session_static (sess))
+    s = format (s, "       static translation\n");
+  else
+    s = format (s, "       dynamic translation\n");
+
+  return s;
+}
+
+u8 *
+format_nat44_ei_user (u8 *s, va_list *args)
+{
+  nat44_ei_main_per_thread_data_t *tnm =
+    va_arg (*args, nat44_ei_main_per_thread_data_t *);
+  nat44_ei_user_t *u = va_arg (*args, nat44_ei_user_t *);
+  int verbose = va_arg (*args, int);
+  dlist_elt_t *head, *elt;
+  u32 elt_index, head_index;
+  u32 session_index;
+  nat44_ei_session_t *sess;
+
+  s = format (s, "%U: %d dynamic translations, %d static translations\n",
+             format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
+
+  if (verbose == 0)
+    return s;
+
+  if (u->nsessions || u->nstaticsessions)
+    {
+      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);
+      session_index = elt->value;
+
+      while (session_index != ~0)
+       {
+         sess = pool_elt_at_index (tnm->sessions, session_index);
+
+         s = format (s, "  %U\n", format_nat44_ei_session, tnm, sess);
+
+         elt_index = elt->next;
+         elt = pool_elt_at_index (tnm->list_pool, elt_index);
+         session_index = elt->value;
+       }
+    }
+
+  return s;
+}
+
+u8 *
+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 (nat44_ei_is_addr_only_static_mapping (m))
+       s = format (s, "identity mapping %U", format_ip4_address,
+                   &m->local_addr);
+      else
+       s = format (s, "identity mapping %U %U:%d", format_nat_protocol,
+                   m->proto, format_ip4_address, &m->local_addr,
+                   clib_net_to_host_u16 (m->local_port));
+
+      pool_foreach (local, m->locals)
+       {
+         s = format (s, " vrf %d", local->vrf_id);
+       }
+
+      return s;
+    }
+
+  if (nat44_ei_is_addr_only_static_mapping (m))
+    {
+      s = format (s, "local %U external %U vrf %d", format_ip4_address,
+                 &m->local_addr, format_ip4_address, &m->external_addr,
+                 m->vrf_id);
+    }
+  else
+    {
+      s = format (s, "%U local %U:%d external %U:%d vrf %d",
+                 format_nat_protocol, m->proto, format_ip4_address,
+                 &m->local_addr, clib_net_to_host_u16 (m->local_port),
+                 format_ip4_address, &m->external_addr,
+                 clib_net_to_host_u16 (m->external_port), m->vrf_id);
+    }
+  return s;
+}
+
+u8 *
+format_nat44_ei_static_map_to_resolve (u8 *s, va_list *args)
+{
+  nat44_ei_static_map_resolve_t *m =
+    va_arg (*args, nat44_ei_static_map_resolve_t *);
+  vnet_main_t *vnm = vnet_get_main ();
+
+  if (m->addr_only)
+    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);
+  else
+    s = format (s, "%U local %U:%d external %U:%d vrf %d", format_nat_protocol,
+               m->proto, format_ip4_address, &m->l_addr,
+               clib_net_to_host_u16 (m->l_port), format_vnet_sw_if_index_name,
+               vnm, m->sw_if_index, clib_net_to_host_u16 (m->e_port),
+               m->vrf_id);
+
+  return s;
+}
+
+static clib_error_t *
+nat44_ei_enable_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;
+  clib_error_t *error = 0;
+
+  nat44_ei_config_t c = { 0 };
+  u8 mode_set = 0;
+
+  if (nm->enabled)
+    return clib_error_return (0, "nat44 ei already enabled");
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    {
+      if (nat44_ei_plugin_enable (c) != 0)
+       return clib_error_return (0, "nat44 ei enable failed");
+      return 0;
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (!mode_set && unformat (line_input, "static-mapping-only"))
+       {
+         mode_set = 1;
+         c.static_mapping_only = 1;
+         if (unformat (line_input, "connection-tracking"))
+           {
+             c.connection_tracking = 1;
+           }
+       }
+      else if (!mode_set && unformat (line_input, "out2in-dpo"))
+       {
+         mode_set = 1;
+         c.out2in_dpo = 1;
+       }
+      else if (unformat (line_input, "inside-vrf %u", &c.inside_vrf))
+       ;
+      else if (unformat (line_input, "outside-vrf %u", &c.outside_vrf))
+       ;
+      else if (unformat (line_input, "users %u", &c.users))
+       ;
+      else if (unformat (line_input, "sessions %u", &c.sessions))
+       ;
+      else if (unformat (line_input, "user-sessions %u", &c.user_sessions))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (!c.sessions)
+    {
+      error = clib_error_return (0, "number of sessions is required");
+      goto done;
+    }
+
+  if (nat44_ei_plugin_enable (c) != 0)
+    error = clib_error_return (0, "nat44 ei enable failed");
+done:
+  unformat_free (line_input);
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_disable_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                            vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  clib_error_t *error = 0;
+
+  if (!nm->enabled)
+    return clib_error_return (0, "nat44 ei already disabled");
+
+  if (nat44_ei_plugin_disable () != 0)
+    error = clib_error_return (0, "nat44 ei disable failed");
+
+  return error;
+}
+
+static clib_error_t *
+set_workers_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                       vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  uword *bitmap = 0;
+  int rv = 0;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (bitmap == 0)
+    {
+      error = clib_error_return (0, "List of workers must be specified.");
+      goto done;
+    }
+
+  rv = nat44_ei_set_workers (bitmap);
+
+  clib_bitmap_free (bitmap);
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_INVALID_WORKER:
+      error = clib_error_return (0, "Invalid worker(s).");
+      goto done;
+    case VNET_API_ERROR_FEATURE_DISABLED:
+      error =
+       clib_error_return (0, "Supported only if 2 or more workes available.");
+      goto done;
+    default:
+      break;
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat_show_workers_commnad_fn (vlib_main_t *vm, unformat_input_t *input,
+                            vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u32 *worker;
+
+  if (nm->num_workers > 1)
+    {
+      vlib_cli_output (vm, "%d workers", vec_len (nm->workers));
+      vec_foreach (worker, nm->workers)
+       {
+         vlib_worker_thread_t *w =
+           vlib_worker_threads + *worker + nm->first_worker_index;
+         vlib_cli_output (vm, "  %s", w->name);
+       }
+    }
+
+  return 0;
+}
+
+static clib_error_t *
+nat44_ei_set_log_level_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                  vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  u8 log_level = NAT_LOG_NONE;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  if (!unformat (line_input, "%d", &log_level))
+    {
+      error = clib_error_return (0, "unknown input '%U'",
+                                format_unformat_error, line_input);
+      goto done;
+    }
+  if (log_level > NAT_LOG_DEBUG)
+    {
+      error = clib_error_return (0, "unknown logging level '%d'", log_level);
+      goto done;
+    }
+  nm->log_level = log_level;
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_ipfix_logging_enable_disable_command_fn (vlib_main_t *vm,
+                                                 unformat_input_t *input,
+                                                 vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  u32 domain_id = 0;
+  u32 src_port = 0;
+  u8 enable = 1;
+  int rv = 0;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    {
+      rv =
+       nat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
+      if (rv)
+       return clib_error_return (0, "ipfix logging enable failed");
+      return 0;
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "domain %d", &domain_id))
+       ;
+      else if (unformat (line_input, "src-port %d", &src_port))
+       ;
+      else if (unformat (line_input, "disable"))
+       enable = 0;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  rv = nat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
+
+  if (rv)
+    {
+      error = clib_error_return (0, "ipfix logging enable failed");
+      goto done;
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_show_hash_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                              vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm;
+  int i;
+  int verbose = 0;
+
+  if (unformat (input, "detail"))
+    verbose = 1;
+  else if (unformat (input, "verbose"))
+    verbose = 2;
+
+  vlib_cli_output (vm, "%U", format_bihash_8_8, &nm->static_mapping_by_local,
+                  verbose);
+  vlib_cli_output (vm, "%U", format_bihash_8_8,
+                  &nm->static_mapping_by_external, verbose);
+  vec_foreach_index (i, nm->per_thread_data)
+    {
+      tnm = vec_elt_at_index (nm->per_thread_data, i);
+      vlib_cli_output (vm, "-------- thread %d %s --------\n", i,
+                      vlib_worker_threads[i].name);
+
+      vlib_cli_output (vm, "%U", format_bihash_8_8, &nm->in2out, verbose);
+      vlib_cli_output (vm, "%U", format_bihash_8_8, &nm->out2in, verbose);
+      vlib_cli_output (vm, "%U", format_bihash_8_8, &tnm->user_hash, verbose);
+    }
+
+  vlib_cli_output (vm, "-------- hash table parameters --------\n");
+  vlib_cli_output (vm, "translation buckets: %u", nm->translation_buckets);
+  vlib_cli_output (vm, "user buckets: %u", nm->user_buckets);
+  return 0;
+}
+
+static clib_error_t *
+nat44_ei_set_alloc_addr_and_port_alg_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 psid, psid_offset, psid_length, port_start, port_end;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "default"))
+       nat44_ei_set_alloc_default ();
+      else if (unformat (line_input,
+                        "map-e psid %d psid-offset %d psid-len %d", &psid,
+                        &psid_offset, &psid_length))
+       nat44_ei_set_alloc_mape ((u16) psid, (u16) psid_offset,
+                                (u16) psid_length);
+      else if (unformat (line_input, "port-range %d - %d", &port_start,
+                        &port_end))
+       {
+         if (port_end <= port_start)
+           {
+             error = clib_error_return (
+               0, "The end-port must be greater than start-port");
+             goto done;
+           }
+         nat44_ei_set_alloc_range ((u16) port_start, (u16) port_end);
+       }
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+};
+
+u8 *
+format_nat44_ei_addr_and_port_alloc_alg (u8 *s, va_list *args)
+{
+  u32 i = va_arg (*args, u32);
+  u8 *t = 0;
+
+  switch (i)
+    {
+#define _(v, N, s)                                                            \
+  case NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_##N:                                  \
+    t = (u8 *) s;                                                             \
+    break;
+      foreach_nat44_ei_addr_and_port_alloc_alg
+#undef _
+       default : s = format (s, "unknown");
+      return s;
+    }
+  s = format (s, "%s", t);
+  return s;
+}
+
+static clib_error_t *
+nat44_ei_show_alloc_addr_and_port_alg_command_fn (vlib_main_t *vm,
+                                                 unformat_input_t *input,
+                                                 vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  vlib_cli_output (vm, "NAT address and port: %U",
+                  format_nat44_ei_addr_and_port_alloc_alg,
+                  nm->addr_and_port_alloc_alg);
+  switch (nm->addr_and_port_alloc_alg)
+    {
+    case NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_MAPE:
+      vlib_cli_output (vm, "  psid %d psid-offset %d psid-len %d", nm->psid,
+                      nm->psid_offset, nm->psid_length);
+      break;
+    case NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_RANGE:
+      vlib_cli_output (vm, "  start-port %d end-port %d", nm->start_port,
+                      nm->end_port);
+      break;
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+static clib_error_t *
+nat_set_mss_clamping_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  clib_error_t *error = 0;
+  u32 mss;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "disable"))
+       nm->mss_clamping = 0;
+      else if (unformat (line_input, "%d", &mss))
+       nm->mss_clamping = (u16) mss;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat_show_mss_clamping_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                 vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  if (nm->mss_clamping)
+    vlib_cli_output (vm, "mss-clamping %d", nm->mss_clamping);
+  else
+    vlib_cli_output (vm, "mss-clamping disabled");
+
+  return 0;
+}
+
+static clib_error_t *
+nat_ha_failover_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                           vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  ip4_address_t addr;
+  u32 port, session_refresh_interval = 10;
+  int rv;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U:%u", unformat_ip4_address, &addr, &port))
+       ;
+      else if (unformat (line_input, "refresh-interval %u",
+                        &session_refresh_interval))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  rv = nat_ha_set_failover (&addr, (u16) port, session_refresh_interval);
+  if (rv)
+    error = clib_error_return (0, "set HA failover failed");
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat_ha_listener_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                           vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  ip4_address_t addr;
+  u32 port, path_mtu = 512;
+  int rv;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U:%u", unformat_ip4_address, &addr, &port))
+       ;
+      else if (unformat (line_input, "path-mtu %u", &path_mtu))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  rv = nat_ha_set_listener (&addr, (u16) port, path_mtu);
+  if (rv)
+    error = clib_error_return (0, "set HA listener failed");
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat_show_ha_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                       vlib_cli_command_t *cmd)
+{
+  ip4_address_t addr;
+  u16 port;
+  u32 path_mtu, session_refresh_interval, resync_ack_missed;
+  u8 in_resync;
+
+  nat_ha_get_listener (&addr, &port, &path_mtu);
+  if (!port)
+    {
+      vlib_cli_output (vm, "NAT HA disabled\n");
+      return 0;
+    }
+
+  vlib_cli_output (vm, "LISTENER:\n");
+  vlib_cli_output (vm, "  %U:%u path-mtu %u\n", format_ip4_address, &addr,
+                  port, path_mtu);
+
+  nat_ha_get_failover (&addr, &port, &session_refresh_interval);
+  vlib_cli_output (vm, "FAILOVER:\n");
+  if (port)
+    vlib_cli_output (vm, "  %U:%u refresh-interval %usec\n",
+                    format_ip4_address, &addr, port,
+                    session_refresh_interval);
+  else
+    vlib_cli_output (vm, "  NA\n");
+
+  nat_ha_get_resync_status (&in_resync, &resync_ack_missed);
+  vlib_cli_output (vm, "RESYNC:\n");
+  if (in_resync)
+    vlib_cli_output (vm, "  in progress\n");
+  else
+    vlib_cli_output (vm, "  completed (%d ACK missed)\n", resync_ack_missed);
+
+  return 0;
+}
+
+static clib_error_t *
+nat_ha_flush_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                        vlib_cli_command_t *cmd)
+{
+  nat_ha_flush (0);
+  return 0;
+}
+
+static clib_error_t *
+nat_ha_resync_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                         vlib_cli_command_t *cmd)
+{
+  clib_error_t *error = 0;
+
+  if (nat_ha_resync (0, 0, 0))
+    error = clib_error_return (0, "NAT HA resync already running");
+
+  return error;
+}
+
+static clib_error_t *
+add_address_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                       vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  ip4_address_t start_addr, end_addr, this_addr;
+  u32 start_host_order, end_host_order;
+  u32 vrf_id = ~0;
+  int i, count;
+  int is_add = 1;
+  int rv = 0;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U - %U", unformat_ip4_address, &start_addr,
+                   unformat_ip4_address, &end_addr))
+       ;
+      else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
+       ;
+      else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
+       end_addr = start_addr;
+      else if (unformat (line_input, "del"))
+       is_add = 0;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (nm->static_mapping_only)
+    {
+      error = clib_error_return (0, "static mapping only mode");
+      goto done;
+    }
+
+  start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
+  end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
+
+  if (end_host_order < start_host_order)
+    {
+      error = clib_error_return (0, "end address less than start address");
+      goto done;
+    }
+
+  count = (end_host_order - start_host_order) + 1;
+
+  if (count > 1024)
+    nat44_ei_log_info ("%U - %U, %d addresses...", format_ip4_address,
+                      &start_addr, format_ip4_address, &end_addr, count);
+
+  this_addr = start_addr;
+
+  for (i = 0; i < count; i++)
+    {
+      if (is_add)
+       rv = nat44_ei_add_address (nm, &this_addr, vrf_id);
+      else
+       rv = nat44_ei_del_address (nm, this_addr, 0);
+
+      switch (rv)
+       {
+       case VNET_API_ERROR_VALUE_EXIST:
+         error = clib_error_return (0, "NAT address already in use.");
+         goto done;
+       case VNET_API_ERROR_NO_SUCH_ENTRY:
+         error = clib_error_return (0, "NAT address not exist.");
+         goto done;
+       case VNET_API_ERROR_UNSPECIFIED:
+         error = clib_error_return (0, "NAT address used in static mapping.");
+         goto done;
+       case VNET_API_ERROR_FEATURE_DISABLED:
+         goto done;
+       default:
+         break;
+       }
+
+      if (nm->out2in_dpo)
+       nat44_ei_add_del_address_dpo (this_addr, is_add);
+
+      increment_v4_address (&this_addr);
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_show_addresses_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                   vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_address_t *ap;
+
+  vlib_cli_output (vm, "NAT44 pool addresses:");
+  vec_foreach (ap, nm->addresses)
+    {
+      vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
+      if (ap->fib_index != ~0)
+       vlib_cli_output (
+         vm, "  tenant VRF: %u",
+         fib_table_get (ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
+      else
+       vlib_cli_output (vm, "  tenant VRF independent");
+#define _(N, i, n, s)                                                         \
+  vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
+      foreach_nat_protocol
+#undef _
+    }
+  return 0;
+}
+
+static clib_error_t *
+nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                            vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  vnet_main_t *vnm = vnet_get_main ();
+  clib_error_t *error = 0;
+  u32 sw_if_index;
+  u32 *inside_sw_if_indices = 0;
+  u32 *outside_sw_if_indices = 0;
+  u8 is_output_feature = 0;
+  int is_del = 0;
+  int i;
+
+  sw_if_index = ~0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "in %U", unformat_vnet_sw_interface, vnm,
+                   &sw_if_index))
+       vec_add1 (inside_sw_if_indices, sw_if_index);
+      else if (unformat (line_input, "out %U", unformat_vnet_sw_interface, vnm,
+                        &sw_if_index))
+       vec_add1 (outside_sw_if_indices, sw_if_index);
+      else if (unformat (line_input, "output-feature"))
+       is_output_feature = 1;
+      else if (unformat (line_input, "del"))
+       is_del = 1;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (vec_len (inside_sw_if_indices))
+    {
+      for (i = 0; i < vec_len (inside_sw_if_indices); i++)
+       {
+         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))
+               {
+                 error = clib_error_return (
+                   0, "%s %U failed", is_del ? "del" : "add",
+                   format_vnet_sw_if_index_name, vnm, sw_if_index);
+                 goto done;
+               }
+           }
+         else
+           {
+             if (nat44_ei_interface_add_del (sw_if_index, 1, is_del))
+               {
+                 error = clib_error_return (
+                   0, "%s %U failed", is_del ? "del" : "add",
+                   format_vnet_sw_if_index_name, vnm, sw_if_index);
+                 goto done;
+               }
+           }
+       }
+    }
+
+  if (vec_len (outside_sw_if_indices))
+    {
+      for (i = 0; i < vec_len (outside_sw_if_indices); i++)
+       {
+         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))
+               {
+                 error = clib_error_return (
+                   0, "%s %U failed", is_del ? "del" : "add",
+                   format_vnet_sw_if_index_name, vnm, sw_if_index);
+                 goto done;
+               }
+           }
+         else
+           {
+             if (nat44_ei_interface_add_del (sw_if_index, 0, is_del))
+               {
+                 error = clib_error_return (
+                   0, "%s %U failed", is_del ? "del" : "add",
+                   format_vnet_sw_if_index_name, vnm, sw_if_index);
+                 goto done;
+               }
+           }
+       }
+    }
+
+done:
+  unformat_free (line_input);
+  vec_free (inside_sw_if_indices);
+  vec_free (outside_sw_if_indices);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_show_interfaces_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                    vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i;
+  vnet_main_t *vnm = vnet_get_main ();
+
+  vlib_cli_output (vm, "NAT44 interfaces:");
+  pool_foreach (i, nm->interfaces)
+    {
+      vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
+                      i->sw_if_index,
+                      (nat44_ei_interface_is_inside (i) &&
+                       nat44_ei_interface_is_outside (i)) ?
+                        "in out" :
+                        (nat44_ei_interface_is_inside (i) ? "in" : "out"));
+    }
+
+  pool_foreach (i, nm->output_feature_interfaces)
+    {
+      vlib_cli_output (vm, " %U output-feature %s",
+                      format_vnet_sw_if_index_name, vnm, i->sw_if_index,
+                      (nat44_ei_interface_is_inside (i) &&
+                       nat44_ei_interface_is_outside (i)) ?
+                        "in out" :
+                        (nat44_ei_interface_is_inside (i) ? "in" : "out"));
+    }
+
+  return 0;
+}
+
+static clib_error_t *
+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 ();
+  nat_protocol_t proto = NAT_PROTOCOL_OTHER;
+  u8 proto_set = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
+                   &l_port))
+       addr_only = 0;
+      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;
+      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;
+      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;
+      else
+       {
+         error = clib_error_return (0, "unknown input: '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (addr_only)
+    {
+      if (proto_set)
+       {
+         error = clib_error_return (
+           0, "address only mapping doesn't support protocol");
+         goto done;
+       }
+    }
+  else if (!proto_set)
+    {
+      error = clib_error_return (0, "protocol is required");
+      goto done;
+    }
+
+  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);
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_INVALID_VALUE:
+      error = clib_error_return (0, "External port already in use.");
+      goto done;
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      if (is_add)
+       error = clib_error_return (0, "External address must be allocated.");
+      else
+       error = clib_error_return (0, "Mapping not exist.");
+      goto done;
+    case VNET_API_ERROR_NO_SUCH_FIB:
+      error = clib_error_return (0, "No such VRF id.");
+      goto done;
+    case VNET_API_ERROR_VALUE_EXIST:
+      error = clib_error_return (0, "Mapping already exist.");
+      goto done;
+    case VNET_API_ERROR_FEATURE_DISABLED:
+      goto done;
+    default:
+      break;
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+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;
+  nat_protocol_t proto;
+
+  addr.as_u32 = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", unformat_ip4_address, &addr))
+       ;
+      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 %u", unformat_nat_protocol, &proto,
+                        &port))
+       addr_only = 0;
+      else if (unformat (line_input, "del"))
+       is_add = 0;
+      else
+       {
+         error = clib_error_return (0, "unknown input: '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  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);
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_INVALID_VALUE:
+      error = clib_error_return (0, "External port already in use.");
+      goto done;
+    case VNET_API_ERROR_NO_SUCH_ENTRY:
+      if (is_add)
+       error = clib_error_return (0, "External address must be allocated.");
+      else
+       error = clib_error_return (0, "Mapping not exist.");
+      goto done;
+    case VNET_API_ERROR_NO_SUCH_FIB:
+      error = clib_error_return (0, "No such VRF id.");
+      goto done;
+    case VNET_API_ERROR_VALUE_EXIST:
+      error = clib_error_return (0, "Mapping already exist.");
+      goto done;
+    default:
+      break;
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_show_static_mappings_command_fn (vlib_main_t *vm,
+                                         unformat_input_t *input,
+                                         vlib_cli_command_t *cmd)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_static_mapping_t *m;
+  nat44_ei_static_map_resolve_t *rp;
+
+  vlib_cli_output (vm, "NAT44 static mappings:");
+  pool_foreach (m, nm->static_mappings)
+    {
+      vlib_cli_output (vm, " %U", format_nat44_ei_static_mapping, m);
+    }
+  vec_foreach (rp, nm->to_resolve)
+    vlib_cli_output (vm, " %U", format_nat44_ei_static_map_to_resolve, rp);
+
+  return 0;
+}
+
+static clib_error_t *
+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;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", unformat_vnet_sw_interface,
+                   nm->vnet_main, &sw_if_index))
+       ;
+      else if (unformat (line_input, "del"))
+       is_del = 1;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del);
+
+  switch (rv)
+    {
+    case 0:
+      break;
+
+    default:
+      error = clib_error_return (
+       0, "nat44_ei_add_interface_address returned %d", rv);
+      goto done;
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_show_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;
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 *sw_if_index;
+
+  vlib_cli_output (vm, "NAT44 pool address interfaces:");
+  vec_foreach (sw_if_index, nm->auto_add_sw_if_indices)
+    {
+      vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
+                      *sw_if_index);
+    }
+  return 0;
+}
+
+static clib_error_t *
+nat44_ei_show_sessions_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;
+
+  nat44_ei_main_per_thread_data_t *tnm;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  int detail = 0;
+  int i = 0;
+
+  if (!unformat_user (input, unformat_line_input, line_input))
+    goto print;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "detail"))
+       detail = 1;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         break;
+       }
+    }
+  unformat_free (line_input);
+
+print:
+  vlib_cli_output (vm, "NAT44 sessions:");
+
+  vec_foreach_index (i, nm->per_thread_data)
+    {
+      tnm = vec_elt_at_index (nm->per_thread_data, i);
+
+      vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n", i,
+                      vlib_worker_threads[i].name, pool_elts (tnm->sessions));
+
+      nat44_ei_user_t *u;
+      pool_foreach (u, tnm->users)
+       {
+         vlib_cli_output (vm, "  %U", format_nat44_ei_user, tnm, u, detail);
+       }
+    }
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_del_user_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 addr;
+  u32 fib_index = 0;
+  int rv;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U", unformat_ip4_address, &addr))
+       ;
+      else if (unformat (line_input, "fib %u", &fib_index))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  rv = nat44_ei_user_del (&addr, fib_index);
+
+  if (!rv)
+    {
+      error = clib_error_return (0, "nat44_ei_user_del returned %d", rv);
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_clear_sessions_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                   vlib_cli_command_t *cmd)
+{
+  clib_error_t *error = 0;
+  nat44_ei_sessions_clear ();
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_del_session_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 port = 0, vrf_id = nm->outside_vrf_id;
+  clib_error_t *error = 0;
+  nat_protocol_t proto;
+  ip4_address_t addr;
+  int rv, is_in = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
+                   unformat_nat_protocol, &proto))
+       ;
+      else if (unformat (line_input, "in"))
+       {
+         is_in = 1;
+         vrf_id = nm->inside_vrf_id;
+       }
+      else if (unformat (line_input, "out"))
+       {
+         is_in = 0;
+         vrf_id = nm->outside_vrf_id;
+       }
+      else if (unformat (line_input, "vrf %u", &vrf_id))
+       ;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  rv = nat44_ei_del_session (nm, &addr, clib_host_to_net_u16 (port), proto,
+                            vrf_id, is_in);
+
+  switch (rv)
+    {
+    case 0:
+      break;
+
+    default:
+      error = clib_error_return (0, "nat44_ei_del_session returned %d", rv);
+      goto done;
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ei_forwarding_set_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;
+  u8 forwarding_enable;
+  u8 forwarding_enable_set = 0;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return clib_error_return (0, "'enable' or 'disable' expected");
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (!forwarding_enable_set && unformat (line_input, "enable"))
+       {
+         forwarding_enable = 1;
+         forwarding_enable_set = 1;
+       }
+      else if (!forwarding_enable_set && unformat (line_input, "disable"))
+       {
+         forwarding_enable = 0;
+         forwarding_enable_set = 1;
+       }
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (!forwarding_enable_set)
+    {
+      error = clib_error_return (0, "'enable' or 'disable' expected");
+      goto done;
+    }
+
+  nm->forwarding_enabled = forwarding_enable;
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+set_timeout_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;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "udp %u", &nm->timeouts.udp))
+       ;
+      else if (unformat (line_input, "tcp-established %u",
+                        &nm->timeouts.tcp.established))
+       ;
+      else if (unformat (line_input, "tcp-transitory %u",
+                        &nm->timeouts.tcp.transitory))
+       ;
+      else if (unformat (line_input, "icmp %u", &nm->timeouts.icmp))
+       ;
+      else if (unformat (line_input, "reset"))
+       nat_reset_timeouts (&nm->timeouts);
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+done:
+  unformat_free (line_input);
+  return error;
+}
+
+static clib_error_t *
+nat_show_timeouts_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                             vlib_cli_command_t *cmd)
+{
+  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);
+  vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
+                  nm->timeouts.tcp.transitory);
+  vlib_cli_output (vm, "icmp timeout: %dsec", nm->timeouts.icmp);
+
+  return 0;
+}
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei enable}
+ * Enable nat44 ei plugin
+ * To enable nat44, use:
+ *  vpp# nat44 ei enable sessions <n>
+ * To enable nat44 ei static mapping only, use:
+ *  vpp# nat44 ei enable sessions <n> static-mapping
+ * To enable nat44 ei static mapping with connection tracking, use:
+ *  vpp# nat44 ei enable sessions <n> static-mapping connection-tracking
+ * To enable nat44 ei out2in dpo, use:
+ *  vpp# nat44 ei enable sessions <n> out2in-dpo
+ * To set inside-vrf outside-vrf, use:
+ *  vpp# nat44 ei enable sessions <n> inside-vrf <id> outside-vrf <id>
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_enable_command, static) = {
+  .path = "nat44 ei enable",
+  .short_help =
+    "nat44 ei enable sessions <max-number> [users <max-number>] "
+    "[static-mappig-only [connection-tracking]|out2in-dpo] [inside-vrf "
+    "<vrf-id>] [outside-vrf <vrf-id>] [user-sessions <max-number>]",
+  .function = nat44_ei_enable_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei disable}
+ * Disable nat44 ei plugin
+ * To disable nat44, use:
+ *  vpp# nat44 ei disable
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_disable_command, static) = {
+  .path = "nat44 ei disable",
+  .short_help = "nat44 ei disable",
+  .function = nat44_ei_disable_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{set snat44 ei workers}
+ * Set NAT workers if 2 or more workers available, use:
+ *  vpp# set snat44 ei workers 0-2,5
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (set_workers_command, static) = {
+  .path = "set nat44 ei workers",
+  .function = set_workers_command_fn,
+  .short_help = "set nat44 ei workers <workers-list>",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei workers}
+ * Show NAT workers.
+ *  vpp# show nat44 ei workers:
+ *  2 workers
+ *    vpp_wk_0
+ *    vpp_wk_1
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
+  .path = "show nat44 ei workers",
+  .short_help = "show nat44 ei workers",
+  .function = nat_show_workers_commnad_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{set nat44 ei timeout}
+ * Set values of timeouts for NAT sessions (in seconds), use:
+ *  vpp# set nat44 ei timeout udp 120 tcp-established 7500 tcp-transitory 250
+icmp 90
+ * To reset default values use:
+ *  vpp# set nat44 ei timeout reset
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (set_timeout_command, static) = {
+  .path = "set nat44 ei timeout",
+  .function = set_timeout_command_fn,
+  .short_help = "set nat44 ei timeout [udp <sec> | tcp-established <sec> "
+               "tcp-transitory <sec> | icmp <sec> | reset]",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei timeouts}
+ * Show values of timeouts for NAT sessions.
+ * vpp# show nat44 ei timeouts
+ * udp timeout: 300sec
+ * tcp-established timeout: 7440sec
+ * tcp-transitory timeout: 240sec
+ * icmp timeout: 60sec
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_show_timeouts_command, static) = {
+  .path = "show nat44 ei timeouts",
+  .short_help = "show nat44 ei timeouts",
+  .function = nat_show_timeouts_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei set logging level}
+ * To set NAT logging level use:
+ * Set nat44 ei logging level
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_set_log_level_command, static) = {
+  .path = "nat44 ei set logging level",
+  .function = nat44_ei_set_log_level_command_fn,
+  .short_help = "nat44 ei set logging level <level>",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{snat44 ei ipfix logging}
+ * To enable NAT IPFIX logging use:
+ *  vpp# nat44 ei ipfix logging
+ * To set IPFIX exporter use:
+ *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_ipfix_logging_enable_disable_command, static) = {
+  .path = "nat44 ei ipfix logging",
+  .function = nat44_ei_ipfix_logging_enable_disable_command_fn,
+  .short_help =
+    "nat44 ei ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei addr-port-assignment-alg}
+ * Set address and port assignment algorithm
+ * For the MAP-E CE limit port choice based on PSID use:
+ *  vpp# nat44 ei addr-port-assignment-alg map-e psid 10 psid-offset 6 psid-len
+6
+ * For port range use:
+ *  vpp# nat44 ei addr-port-assignment-alg port-range <start-port> - <end-port>
+ * To set standard (default) address and port assignment algorithm use:
+ *  vpp# nat44 ei addr-port-assignment-alg default
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_set_alloc_addr_and_port_alg_command, static) = {
+  .path = "nat44 ei addr-port-assignment-alg",
+  .short_help = "nat44 ei addr-port-assignment-alg <alg-name> [<alg-params>]",
+  .function = nat44_ei_set_alloc_addr_and_port_alg_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei addr-port-assignment-alg}
+ * Show address and port assignment algorithm
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_alloc_addr_and_port_alg_command, static) = {
+  .path = "show nat44 ei addr-port-assignment-alg",
+  .short_help = "show nat44 ei addr-port-assignment-alg",
+  .function = nat44_ei_show_alloc_addr_and_port_alg_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei mss-clamping}
+ * Set TCP MSS rewriting configuration
+ * To enable TCP MSS rewriting use:
+ *  vpp# nat44 ei mss-clamping 1452
+ * To disbale TCP MSS rewriting use:
+ *  vpp# nat44 ei mss-clamping disable
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_set_mss_clamping_command, static) = {
+  .path = "nat44 ei mss-clamping",
+  .short_help = "nat44 ei mss-clamping <mss-value>|disable",
+  .function = nat_set_mss_clamping_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei mss-clamping}
+ * Show TCP MSS rewriting configuration
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_show_mss_clamping_command, static) = {
+  .path = "show nat44 ei mss-clamping",
+  .short_help = "show nat44 ei mss-clamping",
+  .function = nat_show_mss_clamping_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei ha failover}
+ * Set HA failover (remote settings)
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_ha_failover_command, static) = {
+  .path = "nat44 ei ha failover",
+  .short_help =
+    "nat44 ei ha failover <ip4-address>:<port> [refresh-interval <sec>]",
+  .function = nat_ha_failover_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei ha listener}
+ * Set HA listener (local settings)
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_ha_listener_command, static) = {
+  .path = "nat44 ei ha listener",
+  .short_help =
+    "nat44 ei ha listener <ip4-address>:<port> [path-mtu <path-mtu>]",
+  .function = nat_ha_listener_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei ha}
+ * Show HA configuration/status
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_show_ha_command, static) = {
+  .path = "show nat44 ei ha",
+  .short_help = "show nat44 ei ha",
+  .function = nat_show_ha_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei ha flush}
+ * Flush the current HA data (for testing)
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_ha_flush_command, static) = {
+  .path = "nat44 ei ha flush",
+  .short_help = "nat44 ei ha flush",
+  .function = nat_ha_flush_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei ha resync}
+ * Resync HA (resend existing sessions to new failover)
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat_ha_resync_command, static) = {
+  .path = "nat44 ei ha resync",
+  .short_help = "nat44 ei ha resync",
+  .function = nat_ha_resync_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei hash tables}
+ * Show NAT44 hash tables
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_hash, static) = {
+  .path = "show nat44 ei hash tables",
+  .short_help = "show nat44 ei hash tables [detail|verbose]",
+  .function = nat44_ei_show_hash_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei add address}
+ * Add/delete NAT44 pool address.
+ * To add NAT44 pool address use:
+ *  vpp# nat44 ei add address 172.16.1.3
+ *  vpp# nat44 ei add address 172.16.2.2 - 172.16.2.24
+ * To add NAT44 pool address for specific tenant (identified by VRF id) use:
+ *  vpp# nat44 ei add address 172.16.1.3 tenant-vrf 10
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (add_address_command, static) = {
+  .path = "nat44 ei add address",
+  .short_help = "nat44 ei add address <ip4-range-start> [- <ip4-range-end>] "
+               "[tenant-vrf <vrf-id>] [del]",
+  .function = add_address_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei addresses}
+ * Show NAT44 pool addresses.
+ * vpp# show nat44 ei addresses
+ * NAT44 pool addresses:
+ * 172.16.2.2
+ *   tenant VRF independent
+ *   10 busy udp ports
+ *   0 busy tcp ports
+ *   0 busy icmp ports
+ * 172.16.1.3
+ *   tenant VRF: 10
+ *   0 busy udp ports
+ *   2 busy tcp ports
+ *   0 busy icmp ports
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_addresses_command, static) = {
+  .path = "show nat44 ei addresses",
+  .short_help = "show nat44 ei addresses",
+  .function = nat44_ei_show_addresses_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{set interface nat44}
+ * Enable/disable NAT44 feature on the interface.
+ * To enable NAT44 feature with local network interface use:
+ *  vpp# set interface nat44 ei in GigabitEthernet0/8/0
+ * To enable NAT44 feature with external network interface use:
+ *  vpp# set interface nat44 ei out GigabitEthernet0/a/0
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (set_interface_nat44_ei_command, static) = {
+  .path = "set interface nat44 ei",
+  .function = nat44_ei_feature_command_fn,
+  .short_help =
+    "set interface nat44 ei in <intfc> out <intfc> [output-feature] "
+    "[del]",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei interfaces}
+ * Show interfaces with NAT44 feature.
+ * vpp# show nat44 ei interfaces
+ * NAT44 interfaces:
+ *  GigabitEthernet0/8/0 in
+ *  GigabitEthernet0/a/0 out
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_interfaces_command, static) = {
+  .path = "show nat44 ei interfaces",
+  .short_help = "show nat44 ei interfaces",
+  .function = nat44_ei_show_interfaces_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei add static mapping}
+ * Static mapping allows hosts on the external network to initiate connection
+ * to to the local network host.
+ * To create static mapping between local host address 10.0.0.3 port 6303 and
+ * external address 4.4.4.4 port 3606 for TCP protocol use:
+ *  vpp# nat44 ei add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4
+3606
+ * If not runnig "static mapping only" NAT plugin mode use before:
+ *  vpp# nat44 ei add address 4.4.4.4
+ * To create address only static mapping between local and external address
+use:
+ *  vpp# nat44 ei add static mapping local 10.0.0.3 external 4.4.4.4
+ * To create ICMP static mapping between local and external with ICMP echo
+ * identifier 10 use:
+ *  vpp# nat44 ei add static mapping icmp local 10.0.0.3 10 external 4.4.4.4 10
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
+  .path = "nat44 ei add static mapping",
+  .function = add_static_mapping_command_fn,
+  .short_help = "nat44 ei add static mapping tcp|udp|icmp local <addr> "
+               "[<port|icmp-echo-id>] "
+               "external <addr> [<port|icmp-echo-id>] [vrf <table-id>] [del]",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei add identity mapping}
+ * Identity mapping translate an IP address to itself.
+ * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
+ * use:
+ *  vpp# nat44 ei add identity mapping 10.0.0.3 tcp 6303
+ * To create identity mapping for address 10.0.0.3 use:
+ *  vpp# nat44 ei add identity mapping 10.0.0.3
+ * To create identity mapping for DHCP addressed interface use:
+ *  vpp# nat44 ei add identity mapping external GigabitEthernet0/a/0 tcp 3606
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
+  .path = "nat44 ei add identity mapping",
+  .function = add_identity_mapping_command_fn,
+  .short_help =
+    "nat44 ei add identity mapping <ip4-addr>|external <interface> "
+    "[<protocol> <port>] [vrf <table-id>] [del]",
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei static mappings}
+ * Show NAT44 static mappings.
+ * vpp# show nat44 ei static mappings
+ * NAT44 static mappings:
+ *  local 10.0.0.3 external 4.4.4.4 vrf 0
+ *  tcp local 192.168.0.4:6303 external 4.4.4.3:3606 vrf 0
+ *  tcp vrf 0 external 1.2.3.4:80
+ *   local 10.100.10.10:8080 probability 80
+ *   local 10.100.10.20:8080 probability 20
+ *  tcp local 10.0.0.10:3603 external GigabitEthernet0/a/0:6306 vrf 10
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_static_mappings_command, static) = {
+  .path = "show nat44 ei static mappings",
+  .short_help = "show nat44 ei static mappings",
+  .function = nat44_ei_show_static_mappings_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei add interface address}
+ * Use NAT44 pool address from specific interfce
+ * To add NAT44 pool address from specific interface use:
+ *  vpp# nat44 ei add interface address GigabitEthernet0/8/0
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_add_interface_address_command, static) = {
+  .path = "nat44 ei add interface address",
+  .short_help = "nat44 ei add interface address <interface> [del]",
+  .function = nat44_ei_add_interface_address_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei interface address}
+ * Show NAT44 pool address interfaces
+ * vpp# show nat44 ei interface address
+ * NAT44 pool address interfaces:
+ *  GigabitEthernet0/a/0
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_interface_address_command, static) = {
+  .path = "show nat44 ei interface address",
+  .short_help = "show nat44 ei interface address",
+  .function = nat44_ei_show_interface_address_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 ei sessions}
+ * Show NAT44 sessions.
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_show_sessions_command, static) = {
+  .path = "show nat44 ei sessions",
+  .short_help = "show nat44 ei sessions [detail|metrics]",
+  .function = nat44_ei_show_sessions_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei del user}
+ * To delete all NAT44 user sessions:
+ *  vpp# nat44 ei del user 10.0.0.3
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_del_user_command, static) = {
+  .path = "nat44 ei del user",
+  .short_help = "nat44 ei del user <addr> [fib <index>]",
+  .function = nat44_ei_del_user_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{clear nat44 ei sessions}
+ * To clear all NAT44 sessions
+ *  vpp# clear nat44 ei sessions
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_clear_sessions_command, static) = {
+  .path = "clear nat44 ei sessions",
+  .short_help = "clear nat44 ei sessions",
+  .function = nat44_ei_clear_sessions_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei del session}
+ * To administratively delete NAT44 session by inside address and port use:
+ *  vpp# nat44 ei del session in 10.0.0.3:6303 tcp
+ * To administratively delete NAT44 session by outside address and port use:
+ *  vpp# nat44 ei del session out 1.0.0.3:6033 udp
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_del_session_command, static) = {
+  .path = "nat44 ei del session",
+  .short_help = "nat44 ei del session in|out <addr>:<port> tcp|udp|icmp [vrf "
+               "<id>] [external-host <addr>:<port>]",
+  .function = nat44_ei_del_session_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 ei forwarding}
+ * Enable or disable forwarding
+ * Forward packets which don't match existing translation
+ * or static mapping instead of dropping them.
+ * To enable forwarding, use:
+ *  vpp# nat44 ei forwarding enable
+ * To disable forwarding, use:
+ *  vpp# nat44 ei forwarding disable
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ei_forwarding_set_command, static) = {
+  .path = "nat44 ei forwarding",
+  .short_help = "nat44 ei forwarding enable|disable",
+  .function = nat44_ei_forwarding_set_command_fn,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
similarity index 84%
rename from src/plugins/nat/nat_dpo.c
rename to src/plugins/nat/nat44-ei/nat44_ei_dpo.c
index 46ccda8..51016df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Copyright (c) 2020 Cisco and/or its affiliates.
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  */
 
 #include <vnet/ip/ip.h>
-#include <nat/nat_dpo.h>
+#include <nat/nat44-ei/nat44_ei_dpo.h>
 
 dpo_type_t nat_dpo_type;
 
 void
-nat_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t * dpo)
+nat_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t *dpo)
 {
   dpo_set (dpo, nat_dpo_type, dproto, aftr_index);
 }
 
 u8 *
-format_nat_dpo (u8 * s, va_list * args)
+format_nat_dpo (u8 *s, va_list *args)
 {
   index_t index = va_arg (*args, index_t);
   CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
@@ -34,12 +34,12 @@ format_nat_dpo (u8 * s, va_list * args)
 }
 
 static void
-nat_dpo_lock (dpo_id_t * dpo)
+nat_dpo_lock (dpo_id_t *dpo)
 {
 }
 
 static void
-nat_dpo_unlock (dpo_id_t * dpo)
+nat_dpo_unlock (dpo_id_t *dpo)
 {
 }
 
@@ -50,7 +50,7 @@ const static dpo_vft_t nat_dpo_vft = {
 };
 
 const static char *const nat_ip4_nodes[] = {
-  "nat44-out2in",
+  "nat44-ei-out2in",
   NULL,
 };
 
similarity index 94%
rename from src/plugins/nat/nat_dpo.h
rename to src/plugins/nat/nat44-ei/nat44_ei_dpo.h
index e85b3e8..9a5ce5b 100644 (file)
@@ -19,9 +19,9 @@
 #include <vnet/vnet.h>
 #include <vnet/dpo/dpo.h>
 
-void nat_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t * dpo);
+void nat_dpo_create (dpo_proto_t dproto, u32 aftr_index, dpo_id_t *dpo);
 
-u8 *format_nat_dpo (u8 * s, va_list * args);
+u8 *format_nat_dpo (u8 *s, va_list *args);
 
 void nat_dpo_module_init (void);
 
index aea758a..ca99efc 100644 (file)
  * limitations under the License.
  */
 
-#include <nat/nat_inlines.h>
-#include <nat/nat44/ed_inlines.h>
-#include <nat/nat44-ei/nat44_ei_ha.h>
+//#include <vnet/fib/fib_source.h>
+#include <vnet/fib/fib_table.h>
 #include <vnet/udp/udp_local.h>
-#include <nat/nat.h>
 #include <vppinfra/atomics.h>
 
+#include <nat/lib/log.h>
+
+#include <nat/nat44-ei/nat44_ei.h>
+#include <nat/nat44-ei/nat44_ei_ha.h>
+#include <nat/nat44-ei/nat44_ei_inlines.h>
+
 /* number of retries */
 #define NAT_HA_RETRIES 3
 
@@ -173,14 +177,14 @@ nat44_ei_ha_sadd (ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr,
                  ip4_address_t *ehn_addr, u16 ehn_port, u8 proto,
                  u32 fib_index, u16 flags, u32 thread_index)
 {
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  snat_user_t *u;
-  snat_session_t *s;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
+  nat44_ei_user_t *u;
+  nat44_ei_session_t *s;
   clib_bihash_kv_8_8_t kv;
   vlib_main_t *vm = vlib_get_main ();
   f64 now = vlib_time_now (vm);
-  nat_outside_fib_t *outside_fib;
+  nat44_ei_outside_fib_t *outside_fib;
   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
   fib_prefix_t pfx = {
     .fp_proto = FIB_PROTOCOL_IP4,
@@ -190,26 +194,21 @@ nat44_ei_ha_sadd (ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr,
                },
   };
 
-  if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
+  if (!(flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING))
     {
-      if (nat_set_outside_address_and_port (sm->addresses, thread_index,
-                                           *out_addr, out_port, proto))
+      if (nat44_ei_set_outside_address_and_port (nm->addresses, thread_index,
+                                                *out_addr, out_port, proto))
        return;
     }
 
-  u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
+  u = nat44_ei_user_get_or_create (nm, in_addr, fib_index, thread_index);
   if (!u)
     return;
 
-  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
+  s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
   if (!s)
     return;
 
-  if (sm->endpoint_dependent)
-    {
-      nat_ed_lru_insert (tsm, s, now, nat_proto_to_ip_proto (proto));
-    }
-
   s->out2in.addr.as_u32 = out_addr->as_u32;
   s->out2in.port = out_port;
   s->nat_proto = proto;
@@ -217,17 +216,17 @@ nat44_ei_ha_sadd (ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr,
   s->flags = flags;
   s->ext_host_addr.as_u32 = eh_addr->as_u32;
   s->ext_host_port = eh_port;
-  user_session_increment (sm, u, snat_is_session_static (s));
-  switch (vec_len (sm->outside_fibs))
+  nat44_ei_user_session_increment (nm, u, nat44_ei_is_session_static (s));
+  switch (vec_len (nm->outside_fibs))
     {
     case 0:
-      s->out2in.fib_index = sm->outside_fib_index;
+      s->out2in.fib_index = nm->outside_fib_index;
       break;
     case 1:
-      s->out2in.fib_index = sm->outside_fibs[0].fib_index;
+      s->out2in.fib_index = nm->outside_fibs[0].fib_index;
       break;
     default:
-      vec_foreach (outside_fib, sm->outside_fibs)
+      vec_foreach (outside_fib, nm->outside_fibs)
        {
          fei = fib_table_lookup (outside_fib->fib_index, &pfx);
          if (FIB_NODE_INDEX_INVALID != fei)
@@ -241,16 +240,16 @@ nat44_ei_ha_sadd (ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr,
        }
       break;
     }
-  init_nat_o2i_kv (&kv, s, thread_index, s - tsm->sessions);
-  if (clib_bihash_add_del_8_8 (&sm->out2in, &kv, 1))
-    nat_elog_warn ("out2in key add failed");
+  init_nat_o2i_kv (&kv, s, thread_index, s - tnm->sessions);
+  if (clib_bihash_add_del_8_8 (&nm->out2in, &kv, 1))
+    nat_elog_warn (nm, "out2in key add failed");
 
   s->in2out.addr.as_u32 = in_addr->as_u32;
   s->in2out.port = in_port;
   s->in2out.fib_index = fib_index;
-  init_nat_i2o_kv (&kv, s, thread_index, s - tsm->sessions);
-  if (clib_bihash_add_del_8_8 (&sm->in2out, &kv, 1))
-    nat_elog_warn ("in2out key add failed");
+  init_nat_i2o_kv (&kv, s, thread_index, s - tnm->sessions);
+  if (clib_bihash_add_del_8_8 (&nm->in2out, &kv, 1))
+    nat_elog_warn (nm, "in2out key add failed");
 }
 
 static_always_inline void
@@ -258,27 +257,27 @@ nat44_ei_ha_sdel (ip4_address_t *out_addr, u16 out_port,
                  ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index,
                  u32 ti)
 {
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   clib_bihash_kv_8_8_t kv, value;
   u32 thread_index;
-  snat_session_t *s;
-  snat_main_per_thread_data_t *tsm;
+  nat44_ei_session_t *s;
+  nat44_ei_main_per_thread_data_t *tnm;
 
-  if (sm->num_workers > 1)
-    thread_index = sm->first_worker_index +
-                  (sm->workers[(clib_net_to_host_u16 (out_port) - 1024) /
-                               sm->port_per_thread]);
+  if (nm->num_workers > 1)
+    thread_index = nm->first_worker_index +
+                  (nm->workers[(clib_net_to_host_u16 (out_port) - 1024) /
+                               nm->port_per_thread]);
   else
-    thread_index = sm->num_workers;
-  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+    thread_index = nm->num_workers;
+  tnm = vec_elt_at_index (nm->per_thread_data, thread_index);
 
   init_nat_k (&kv, *out_addr, out_port, fib_index, proto);
-  if (clib_bihash_search_8_8 (&sm->out2in, &kv, &value))
+  if (clib_bihash_search_8_8 (&nm->out2in, &kv, &value))
     return;
 
-  s = pool_elt_at_index (tsm->sessions, nat_value_get_session_index (&value));
-  nat_free_session_data (sm, s, thread_index, 1);
-  nat44_delete_session (sm, s, thread_index);
+  s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (&value));
+  nat44_ei_free_session_data_v2 (nm, s, thread_index, 1);
+  nat44_ei_delete_session (nm, s, thread_index);
 }
 
 static_always_inline void
@@ -286,18 +285,18 @@ nat44_ei_ha_sref (ip4_address_t *out_addr, u16 out_port,
                  ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index,
                  u32 total_pkts, u64 total_bytes, u32 thread_index)
 {
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   clib_bihash_kv_8_8_t kv, value;
-  snat_session_t *s;
-  snat_main_per_thread_data_t *tsm;
+  nat44_ei_session_t *s;
+  nat44_ei_main_per_thread_data_t *tnm;
 
-  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+  tnm = vec_elt_at_index (nm->per_thread_data, thread_index);
 
   init_nat_k (&kv, *out_addr, out_port, fib_index, proto);
-  if (clib_bihash_search_8_8 (&sm->out2in, &kv, &value))
+  if (clib_bihash_search_8_8 (&nm->out2in, &kv, &value))
     return;
 
-  s = pool_elt_at_index (tsm->sessions, nat_value_get_session_index (&value));
+  s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (&value));
   s->total_pkts = total_pkts;
   s->total_bytes = total_bytes;
 }
@@ -305,6 +304,7 @@ nat44_ei_ha_sref (ip4_address_t *out_addr, u16 out_port,
 static void
 nat_ha_resync_fin (void)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   nat_ha_main_t *ha = &nat_ha_main;
 
   /* if no more resync ACK remainig we are done */
@@ -314,11 +314,11 @@ nat_ha_resync_fin (void)
   ha->in_resync = 0;
   if (ha->resync_ack_missed)
     {
-      nat_elog_info ("resync completed with result FAILED");
+      nat_elog_info (nm, "resync completed with result FAILED");
     }
   else
     {
-      nat_elog_info ("resync completed with result SUCCESS");
+      nat_elog_info (nm, "resync completed with result SUCCESS");
     }
   if (ha->event_callback)
     ha->event_callback (ha->client_index, ha->pid, ha->resync_ack_missed);
@@ -347,6 +347,7 @@ nat_ha_resend_queue_add (u32 seq, u8 * data, u8 data_len, u8 is_resync,
 static_always_inline void
 nat_ha_ack_recv (u32 seq, u32 thread_index)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   nat_ha_main_t *ha = &nat_ha_main;
   nat_ha_per_thread_data_t *td = &ha->per_thread_data[thread_index];
   u32 i;
@@ -366,7 +367,7 @@ nat_ha_ack_recv (u32 seq, u32 thread_index)
       }
     vec_free (td->resend_queue[i].data);
     vec_del1 (td->resend_queue, i);
-    nat_elog_debug_X1 ("ACK for seq %d received", "i4",
+    nat_elog_debug_X1 (nm, "ACK for seq %d received", "i4",
                       clib_net_to_host_u32 (seq));
 
     return;
@@ -377,6 +378,7 @@ nat_ha_ack_recv (u32 seq, u32 thread_index)
 static void
 nat_ha_resend_scan (f64 now, u32 thread_index)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   nat_ha_main_t *ha = &nat_ha_main;
   nat_ha_per_thread_data_t *td = &ha->per_thread_data[thread_index];
   u32 i, *del, *to_delete = 0;
@@ -394,7 +396,7 @@ nat_ha_resend_scan (f64 now, u32 thread_index)
     /* maximum retry reached delete cached data */
     if (td->resend_queue[i].retry_count >= NAT_HA_RETRIES)
       {
-       nat_elog_notice_X1 ("seq %d missed", "i4",
+       nat_elog_notice_X1 (nm, "seq %d missed", "i4",
                            clib_net_to_host_u32 (td->resend_queue[i].seq));
        if (td->resend_queue[i].is_resync)
          {
@@ -410,14 +412,14 @@ nat_ha_resend_scan (f64 now, u32 thread_index)
       }
 
     /* retry to send non-ACKed data */
-    nat_elog_debug_X1 ("state sync seq %d resend", "i4",
+    nat_elog_debug_X1 (nm, "state sync seq %d resend", "i4",
                       clib_net_to_host_u32 (td->resend_queue[i].seq));
     td->resend_queue[i].retry_count++;
     vlib_increment_simple_counter (&ha->counters[NAT_HA_COUNTER_RETRY_COUNT],
                                   thread_index, 0, 1);
     if (vlib_buffer_alloc (vm, &bi, 1) != 1)
       {
-       nat_elog_warn ("HA NAT state sync can't allocate buffer");
+       nat_elog_warn (nm, "HA NAT state sync can't allocate buffer");
        return;
       }
     b = vlib_get_buffer (vm, bi);
@@ -465,13 +467,13 @@ nat_ha_set_node_indexes (nat_ha_main_t *ha, vlib_main_t *vm)
 {
   vlib_node_t *node;
 
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-ha-handoff");
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-ha-handoff");
   ha->ha_handoff_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-ha-process");
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-ha-process");
   ha->ha_process_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-ha-worker");
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-ha-worker");
   ha->ha_worker_node_index = node->index;
-  node = vlib_get_node_by_name (vm, (u8 *) "nat-ha");
+  node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-ha");
   ha->ha_node_index = node->index;
 }
 
@@ -489,10 +491,11 @@ nat_ha_init (vlib_main_t * vm, u32 num_workers, u32 num_threads)
   ha->num_workers = num_workers;
   vec_validate (ha->per_thread_data, num_threads);
 
-#define _(N, s, v) ha->counters[v].name = s;          \
-  ha->counters[v].stat_segment_name = "/nat44/ha/" s; \
-  vlib_validate_simple_counter(&ha->counters[v], 0);  \
-  vlib_zero_simple_counter(&ha->counters[v], 0);
+#define _(N, s, v)                                                            \
+  ha->counters[v].name = s;                                                   \
+  ha->counters[v].stat_segment_name = "/nat44-ei/ha/" s;                      \
+  vlib_validate_simple_counter (&ha->counters[v], 0);                         \
+  vlib_zero_simple_counter (&ha->counters[v], 0);
   foreach_nat_ha_counter
 #undef _
 }
@@ -500,6 +503,7 @@ nat_ha_init (vlib_main_t * vm, u32 num_workers, u32 num_threads)
 int
 nat_ha_set_listener (ip4_address_t * addr, u16 port, u32 path_mtu)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   nat_ha_main_t *ha = &nat_ha_main;
 
   /* unregister previously set UDP port */
@@ -524,7 +528,8 @@ nat_ha_set_listener (ip4_address_t * addr, u16 port, u32 path_mtu)
        {
          udp_register_dst_port (ha->vlib_main, port, ha->ha_node_index, 1);
        }
-      nat_elog_info_X1 ("HA listening on port %d for state sync", "i4", port);
+      nat_elog_info_X1 (nm, "HA listening on port %d for state sync", "i4",
+                       port);
     }
 
   return 0;
@@ -633,6 +638,7 @@ nat_ha_recv_refresh (nat_ha_event_t * event, f64 now, u32 thread_index)
 static_always_inline void
 nat_ha_event_process (nat_ha_event_t * event, f64 now, u32 thread_index)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   switch (event->event_type)
     {
     case NAT_HA_ADD:
@@ -645,7 +651,7 @@ nat_ha_event_process (nat_ha_event_t * event, f64 now, u32 thread_index)
       nat_ha_recv_refresh (event, now, thread_index);
       break;
     default:
-      nat_elog_notice_X1 ("Unsupported HA event type %d", "i4",
+      nat_elog_notice_X1 (nm, "Unsupported HA event type %d", "i4",
                          event->event_type);
       break;
     }
@@ -728,6 +734,7 @@ static_always_inline void
 nat_ha_event_add (nat_ha_event_t * event, u8 do_flush, u32 thread_index,
                  u8 is_resync)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   nat_ha_main_t *ha = &nat_ha_main;
   nat_ha_per_thread_data_t *td = &ha->per_thread_data[thread_index];
   vlib_main_t *vm = vlib_mains[thread_index];
@@ -744,7 +751,7 @@ nat_ha_event_add (nat_ha_event_t * event, u8 do_flush, u32 thread_index,
 
       if (vlib_buffer_alloc (vm, &bi, 1) != 1)
        {
-         nat_elog_warn ("HA NAT state sync can't allocate buffer");
+         nat_elog_warn (nm, "HA NAT state sync can't allocate buffer");
          return;
        }
 
@@ -932,10 +939,10 @@ nat_ha_worker_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
 
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat_ha_worker_node) = {
-    .function = nat_ha_worker_fn,
-    .type = VLIB_NODE_TYPE_INPUT,
-    .state = VLIB_NODE_STATE_INTERRUPT,
-    .name = "nat-ha-worker",
+  .function = nat_ha_worker_fn,
+  .type = VLIB_NODE_TYPE_INPUT,
+  .state = VLIB_NODE_STATE_INTERRUPT,
+  .name = "nat44-ei-ha-worker",
 };
 /* *INDENT-ON* */
 
@@ -943,6 +950,7 @@ VLIB_REGISTER_NODE (nat_ha_worker_node) = {
 static uword
 nat_ha_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   nat_ha_main_t *ha = &nat_ha_main;
   uword event_type;
   uword *event_data = 0;
@@ -951,7 +959,7 @@ nat_ha_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
   vlib_process_wait_for_event (vm);
   event_type = vlib_process_get_events (vm, &event_data);
   if (event_type)
-    nat_elog_info ("nat-ha-process: bogus kickoff event received");
+    nat_elog_info (nm, "nat44-ei-ha-process: bogus kickoff event received");
   vec_reset_length (event_data);
 
   while (1)
@@ -974,9 +982,9 @@ nat_ha_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
 
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat_ha_process_node) = {
-    .function = nat_ha_process,
-    .type = VLIB_NODE_TYPE_PROCESS,
-    .name = "nat-ha-process",
+  .function = nat_ha_process,
+  .type = VLIB_NODE_TYPE_PROCESS,
+  .name = "nat44-ei-ha-process",
 };
 /* *INDENT-ON* */
 
@@ -1002,9 +1010,8 @@ format_nat_ha_trace (u8 * s, va_list * args)
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   nat_ha_trace_t *t = va_arg (*args, nat_ha_trace_t *);
 
-  s =
-    format (s, "nat-ha: %u events from %U", t->event_count,
-           format_ip4_address, &t->addr);
+  s = format (s, "nat44-ei-ha: %u events from %U", t->event_count,
+             format_ip4_address, &t->addr);
 
   return s;
 }
@@ -1173,7 +1180,7 @@ nat_ha_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat_ha_node) = {
   .function = nat_ha_node_fn,
-  .name = "nat-ha",
+  .name = "nat44-ei-ha",
   .vector_size = sizeof (u32),
   .format_trace = format_nat_ha_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
@@ -1294,7 +1301,7 @@ nat_ha_resync (u32 client_index, u32 pid,
 /* *INDENT-OFF* */
 VLIB_REGISTER_NODE (nat_ha_handoff_node) = {
   .function = nat_ha_handoff_node_fn,
-  .name = "nat-ha-handoff",
+  .name = "nat44-ei-ha-handoff",
   .vector_size = sizeof (u32),
   .format_trace = format_nat_ha_handoff_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
index 5639c8d..c466d4c 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
-#include <nat/nat.h>
 
 /* Call back functions for received HA events on passive/failover */
 typedef void (*nat_ha_sadd_cb_t) (ip4_address_t * in_addr, u16 in_port,
@@ -31,7 +30,6 @@ typedef void (*nat_ha_sadd_cb_t) (ip4_address_t * in_addr, u16 in_port,
                                  ip4_address_t * ehn_addr, u16 ehn_port,
                                  u8 proto, u32 fib_index, u16 flags,
                                  u32 thread_index);
-
 typedef void (*nat_ha_sdel_cb_t) (ip4_address_t * out_addr, u16 out_port,
                                  ip4_address_t * eh_addr, u16 eh_port,
                                  u8 proto, u32 fib_index, u32 thread_index);
similarity index 57%
rename from src/plugins/nat/nat44_hairpinning.c
rename to src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c
index a2cb2eb..0de2de1 100644 (file)
@@ -1,45 +1,46 @@
 /*
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
+ * nat44_ei.c - nat44 endpoint dependent plugin
+ * * Copyright (c) 2020 Cisco and/or its affiliates.  * Licensed under the
+ * Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License
+ * at:
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file
- * @brief NAT44 hairpinning
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
  */
 
 #include <vlib/vlib.h>
 #include <vnet/vnet.h>
 #include <vnet/fib/ip4_fib.h>
-#include <nat/nat.h>
-#include <nat/nat_inlines.h>
-#include <nat/nat44_hairpinning.h>
+
+#include <nat/nat44-ei/nat44_ei.h>
+#include <nat/nat44-ei/nat44_ei_inlines.h>
+#include <nat/nat44-ei/nat44_ei_hairpinning.h>
+
+/* NAT buffer flags */
+#define NAT44_EI_FLAG_HAIRPINNING (1 << 0)
 
 typedef enum
 {
-  SNAT_HAIRPIN_SRC_NEXT_DROP,
-  SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT,
-  SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH,
-  SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT,
-  SNAT_HAIRPIN_SRC_N_NEXT,
-} snat_hairpin_src_next_t;
+  NAT44_EI_HAIRPIN_SRC_NEXT_DROP,
+  NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT,
+  NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH,
+  NAT44_EI_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT,
+  NAT44_EI_HAIRPIN_SRC_N_NEXT,
+} nat44_ei_hairpin_src_next_t;
 
 typedef enum
 {
-  NAT_HAIRPIN_NEXT_LOOKUP,
-  NAT_HAIRPIN_NEXT_DROP,
-  NAT_HAIRPIN_NEXT_HANDOFF,
-  NAT_HAIRPIN_N_NEXT,
-} nat_hairpin_next_t;
+  NAT44_EI_HAIRPIN_NEXT_LOOKUP,
+  NAT44_EI_HAIRPIN_NEXT_DROP,
+  NAT44_EI_HAIRPIN_NEXT_HANDOFF,
+  NAT44_EI_HAIRPIN_N_NEXT,
+} nat44_ei_hairpin_next_t;
 
 typedef struct
 {
@@ -47,18 +48,17 @@ typedef struct
   u16 port;
   u32 fib_index;
   u32 session_index;
-} nat_hairpin_trace_t;
+} nat44_ei_hairpin_trace_t;
 
 static u8 *
-format_nat_hairpin_trace (u8 * s, va_list * args)
+format_nat44_ei_hairpin_trace (u8 *s, va_list *args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  nat_hairpin_trace_t *t = va_arg (*args, nat_hairpin_trace_t *);
+  nat44_ei_hairpin_trace_t *t = va_arg (*args, nat44_ei_hairpin_trace_t *);
 
-  s =
-    format (s, "new dst addr %U port %u fib-index %u", format_ip4_address,
-           &t->addr, clib_net_to_host_u16 (t->port), t->fib_index);
+  s = format (s, "new dst addr %U port %u fib-index %u", format_ip4_address,
+             &t->addr, clib_net_to_host_u16 (t->port), t->fib_index);
   if (~0 == t->session_index)
     {
       s = format (s, " is-static-mapping");
@@ -74,32 +74,60 @@ format_nat_hairpin_trace (u8 * s, va_list * args)
 extern vnet_feature_arc_registration_t vnet_feat_arc_ip4_local;
 
 static_always_inline int
-is_hairpinning (snat_main_t * sm, ip4_address_t * dst_addr)
+nat44_ei_is_hairpinning (nat44_ei_main_t *nm, ip4_address_t *dst_addr)
 {
-  snat_address_t *ap;
+  nat44_ei_address_t *ap;
   clib_bihash_kv_8_8_t kv, value;
 
-  vec_foreach (ap, sm->addresses)
+  vec_foreach (ap, nm->addresses)
     {
       if (ap->addr.as_u32 == dst_addr->as_u32)
-        return 1;
+       return 1;
     }
 
   init_nat_k (&kv, *dst_addr, 0, 0, 0);
-  if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
+  if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
     return 1;
 
   return 0;
 }
 
+#ifndef CLIB_MARCH_VARIANT
+void
+nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
+                                      ip4_header_t *ip)
+{
+  clib_bihash_kv_8_8_t kv, value;
+  nat44_ei_static_mapping_t *m;
+  u32 old_addr, new_addr;
+  ip_csum_t sum;
+
+  init_nat_k (&kv, ip->dst_address, 0, 0, 0);
+  if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
+    return;
+
+  m = pool_elt_at_index (nm->static_mappings, value.value);
+
+  old_addr = ip->dst_address.as_u32;
+  new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
+  sum = ip->checksum;
+  sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
+  ip->checksum = ip_csum_fold (sum);
+
+  if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
+    vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
+}
+#endif
+
 #ifndef CLIB_MARCH_VARIANT
 int
-snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
-                 u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0,
-                 udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0,
-                 int do_trace, u32 *required_thread_index)
+nat44_ei_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node,
+                     nat44_ei_main_t *nm, u32 thread_index, vlib_buffer_t *b0,
+                     ip4_header_t *ip0, udp_header_t *udp0,
+                     tcp_header_t *tcp0, u32 proto0, int do_trace,
+                     u32 *required_thread_index)
 {
-  snat_session_t *s0 = NULL;
+  nat44_ei_session_t *s0 = NULL;
   clib_bihash_kv_8_8_t kv0, value0;
   ip_csum_t sum0;
   u32 new_dst_addr0 = 0, old_dst_addr0, si = ~0;
@@ -109,10 +137,11 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
   u16 sm0_port;
   u32 sm0_fib_index;
   u32 old_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+
   /* Check if destination is static mappings */
-  if (!snat_static_mapping_match
-      (sm, ip0->dst_address, udp0->dst_port, sm->outside_fib_index, proto0,
-       &sm0_addr, &sm0_port, &sm0_fib_index, 1, 0, 0, 0, 0, 0, 0))
+  if (!nat44_ei_static_mapping_match (
+       ip0->dst_address, udp0->dst_port, nm->outside_fib_index, proto0,
+       &sm0_addr, &sm0_port, &sm0_fib_index, 1 /* by external */, 0, 0))
     {
       new_dst_addr0 = sm0_addr.as_u32;
       new_dst_port0 = sm0_port;
@@ -122,8 +151,8 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
   else
     {
       init_nat_k (&kv0, ip0->dst_address, udp0->dst_port,
-                 sm->outside_fib_index, proto0);
-      rv = clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0);
+                 nm->outside_fib_index, proto0);
+      rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0);
       if (rv)
        {
          rv = 0;
@@ -137,7 +166,7 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
        }
 
       si = nat_value_get_session_index (&value0);
-      s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, si);
+      s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions, si);
       new_dst_addr0 = s0->in2out.addr.as_u32;
       new_dst_port0 = s0->in2out.port;
       vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
@@ -149,9 +178,8 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
      changed. */
   old_dst_addr0 = ip0->dst_address.as_u32;
   old_dst_port0 = tcp0->dst;
-  if (new_dst_addr0 == old_dst_addr0
-      && new_dst_port0 == old_dst_port0
-      && vnet_buffer (b0)->sw_if_index[VLIB_TX] == old_sw_if_index)
+  if (new_dst_addr0 == old_dst_addr0 && new_dst_port0 == old_dst_port0 &&
+      vnet_buffer (b0)->sw_if_index[VLIB_TX] == old_sw_if_index)
     return 0;
 
   /* Destination is behind the same NAT, use internal address and port */
@@ -160,8 +188,8 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
       old_dst_addr0 = ip0->dst_address.as_u32;
       ip0->dst_address.as_u32 = new_dst_addr0;
       sum0 = ip0->checksum;
-      sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
-                            ip4_header_t, dst_address);
+      sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t,
+                            dst_address);
       ip0->checksum = ip_csum_fold (sum0);
 
       old_dst_port0 = tcp0->dst;
@@ -174,7 +202,7 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
              sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
                                     ip4_header_t, dst_address);
              sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0,
-                                    ip4_header_t /* cheat */ , length);
+                                    ip4_header_t /* cheat */, length);
              tcp0->checksum = ip_csum_fold (sum0);
            }
          else
@@ -198,10 +226,10 @@ snat_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, snat_main_t *sm,
     }
   rv = 0;
 trace:
-  if (do_trace && PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
-                                && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+  if (do_trace && PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                                (b0->flags & VLIB_BUFFER_IS_TRACED)))
     {
-      nat_hairpin_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+      nat44_ei_hairpin_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
       t->addr.as_u32 = new_dst_addr0;
       t->port = new_dst_port0;
       t->fib_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
@@ -220,9 +248,9 @@ trace:
 
 #ifndef CLIB_MARCH_VARIANT
 u32
-snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
-                      ip4_header_t *ip0, icmp46_header_t *icmp0,
-                      u32 *required_thread_index)
+nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0,
+                          u32 thread_index, ip4_header_t *ip0,
+                          icmp46_header_t *icmp0, u32 *required_thread_index)
 {
   clib_bihash_kv_8_8_t kv0, value0;
   u32 old_dst_addr0, new_dst_addr0;
@@ -231,11 +259,11 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
   u16 old_checksum0, new_checksum0;
   u32 si, ti = 0;
   ip_csum_t sum0;
-  snat_session_t *s0;
-  snat_static_mapping_t *m0;
+  nat44_ei_session_t *s0;
+  nat44_ei_static_mapping_t *m0;
 
-  if (icmp_type_is_error_message
-      (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
+  if (icmp_type_is_error_message (
+       vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
     {
       ip4_header_t *inner_ip0 = 0;
       tcp_udp_header_t *l4_header = 0;
@@ -248,8 +276,8 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
        return 1;
 
       init_nat_k (&kv0, ip0->dst_address, l4_header->src_port,
-                 sm->outside_fib_index, protocol);
-      if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
+                 nm->outside_fib_index, protocol);
+      if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
        return 1;
       ti = nat_value_get_thread_index (&value0);
       if (ti != thread_index)
@@ -258,7 +286,7 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
          return 1;
        }
       si = nat_value_get_session_index (&value0);
-      s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
+      s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si);
       new_dst_addr0 = s0->in2out.addr.as_u32;
       vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
 
@@ -267,15 +295,15 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
       inner_ip0->src_address.as_u32 = new_dst_addr0;
       new_addr0 = inner_ip0->src_address.as_u32;
       sum0 = icmp0->checksum;
-      sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
-                            src_address);
+      sum0 =
+       ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address);
       icmp0->checksum = ip_csum_fold (sum0);
 
       /* update inner IP header checksum */
       old_checksum0 = inner_ip0->checksum;
       sum0 = inner_ip0->checksum;
-      sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
-                            src_address);
+      sum0 =
+       ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address);
       inner_ip0->checksum = ip_csum_fold (sum0);
       new_checksum0 = inner_ip0->checksum;
       sum0 = icmp0->checksum;
@@ -294,15 +322,15 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
     }
   else
     {
-      init_nat_k (&kv0, ip0->dst_address, 0, sm->outside_fib_index, 0);
-      if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0,
+      init_nat_k (&kv0, ip0->dst_address, 0, nm->outside_fib_index, 0);
+      if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv0,
                                  &value0))
        {
          icmp_echo_header_t *echo0 = (icmp_echo_header_t *) (icmp0 + 1);
          u16 icmp_id0 = echo0->identifier;
-         init_nat_k (&kv0, ip0->dst_address, icmp_id0, sm->outside_fib_index,
+         init_nat_k (&kv0, ip0->dst_address, icmp_id0, nm->outside_fib_index,
                      NAT_PROTOCOL_ICMP);
-         int rv = clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0);
+         int rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0);
          if (!rv)
            {
              ti = nat_value_get_thread_index (&value0);
@@ -312,7 +340,7 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
                  return 1;
                }
              si = nat_value_get_session_index (&value0);
-             s0 = pool_elt_at_index (sm->per_thread_data[ti].sessions, si);
+             s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si);
              new_dst_addr0 = s0->in2out.addr.as_u32;
              vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
              echo0->identifier = s0->in2out.port;
@@ -326,7 +354,7 @@ snat_icmp_hairpinning (snat_main_t *sm, vlib_buffer_t *b0, u32 thread_index,
          return 1;
        }
 
-      m0 = pool_elt_at_index (sm->static_mappings, value0.value);
+      m0 = pool_elt_at_index (nm->static_mappings, value0.value);
 
       new_dst_addr0 = m0->local_addr.as_u32;
       if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
@@ -339,29 +367,32 @@ change_addr:
       old_dst_addr0 = ip0->dst_address.as_u32;
       ip0->dst_address.as_u32 = new_dst_addr0;
       sum0 = ip0->checksum;
-      sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0,
-                            ip4_header_t, dst_address);
+      sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t,
+                            dst_address);
       ip0->checksum = ip_csum_fold (sum0);
     }
   return 0;
 }
 #endif
 
+void nat44_ei_hairpinning_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
+                                        ip4_header_t *ip);
+
 #ifndef CLIB_MARCH_VARIANT
 void
-nat_hairpinning_sm_unknown_proto (snat_main_t * sm,
-                                 vlib_buffer_t * b, ip4_header_t * ip)
+nat44_ei_hairpinning_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
+                                   ip4_header_t *ip)
 {
   clib_bihash_kv_8_8_t kv, value;
-  snat_static_mapping_t *m;
+  nat44_ei_static_mapping_t *m;
   u32 old_addr, new_addr;
   ip_csum_t sum;
 
   init_nat_k (&kv, ip->dst_address, 0, 0, 0);
-  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
+  if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
     return;
 
-  m = pool_elt_at_index (sm->static_mappings, value.value);
+  m = pool_elt_at_index (nm->static_mappings, value.value);
 
   old_addr = ip->dst_address.as_u32;
   new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
@@ -374,17 +405,12 @@ nat_hairpinning_sm_unknown_proto (snat_main_t * sm,
 }
 #endif
 
-static inline uword
-nat44_hairpinning_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
-                            vlib_frame_t *frame)
+VLIB_NODE_FN (nat44_ei_hairpin_src_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
   u32 n_left_from, *from, *to_next;
-  u32 thread_index = vm->thread_index;
-  nat_hairpin_next_t next_index;
-  snat_main_t *sm = &snat_main;
-  vnet_feature_main_t *fm = &feature_main;
-  u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
-  vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
+  nat44_ei_hairpin_src_next_t next_index;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -401,12 +427,8 @@ nat44_hairpinning_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          u32 bi0;
          vlib_buffer_t *b0;
          u32 next0;
-         ip4_header_t *ip0;
-         u32 proto0;
-         udp_header_t *udp0;
-         tcp_header_t *tcp0;
+         nat44_ei_interface_t *i;
          u32 sw_if_index0;
-         u32 required_thread_index = thread_index;
 
          /* speculatively enqueue b0 to the current next frame */
          bi0 = from[0];
@@ -417,45 +439,36 @@ nat44_hairpinning_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
-         ip0 = vlib_buffer_get_current (b0);
-         udp0 = ip4_next_header (ip0);
-         tcp0 = (tcp_header_t *) udp0;
          sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         vnet_feature_next (&next0, b0);
 
-         proto0 = ip_proto_to_nat_proto (ip0->protocol);
-         int next0_resolved = 0;
-
-         if (snat_hairpinning (vm, node, sm, thread_index, b0, ip0, udp0,
-                               tcp0, proto0, 1 /* do_trace */,
-                               &required_thread_index))
+         pool_foreach (i, nm->output_feature_interfaces)
            {
-             next0 = NAT_HAIRPIN_NEXT_LOOKUP;
-             next0_resolved = 1;
-           }
-
-         if (thread_index != required_thread_index)
-           {
-             vnet_buffer (b0)->snat.required_thread_index =
-               required_thread_index;
-             next0 = NAT_HAIRPIN_NEXT_HANDOFF;
-             next0_resolved = 1;
+             /* Only packets from NAT inside interface */
+             if ((nat44_ei_interface_is_inside (i)) &&
+                 (sw_if_index0 == i->sw_if_index))
+               {
+                 if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) &
+                                    NAT44_EI_FLAG_HAIRPINNING))
+                   {
+                     if (PREDICT_TRUE (nm->num_workers > 1))
+                       next0 = NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH;
+                     else
+                       next0 = NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT;
+                   }
+                 break;
+               }
            }
 
-         if (!next0_resolved)
-           vnet_get_config_data (&cm->config_main, &b0->current_config_index,
-                                 &next0, 0);
-
-         if (next0 != NAT_HAIRPIN_NEXT_DROP)
+         if (next0 != NAT44_EI_HAIRPIN_SRC_NEXT_DROP)
            {
-             vlib_increment_simple_counter (&sm->counters.hairpinning,
-                                            vm->thread_index, sw_if_index0,
-                                            1);
+             vlib_increment_simple_counter (
+               &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1);
            }
 
          /* verify speculative enqueue, maybe switch current next frame */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, next0);
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
        }
 
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
@@ -464,55 +477,13 @@ nat44_hairpinning_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
   return frame->n_vectors;
 }
 
-VLIB_NODE_FN (nat44_hairpinning_node) (vlib_main_t * vm,
-                                      vlib_node_runtime_t * node,
-                                      vlib_frame_t * frame)
-{
-  return nat44_hairpinning_fn_inline (vm, node, frame);
-}
-
-VLIB_REGISTER_NODE (nat44_hairpinning_node) = {
-  .name = "nat44-hairpinning",
-  .vector_size = sizeof (u32),
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .format_trace = format_nat_hairpin_trace,
-  .n_next_nodes = NAT_HAIRPIN_N_NEXT,
-  .next_nodes = {
-    [NAT_HAIRPIN_NEXT_DROP] = "error-drop",
-    [NAT_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup",
-    [NAT_HAIRPIN_NEXT_HANDOFF] = "nat44-hairpinning-handoff",
-  },
-};
-
-VLIB_NODE_FN (nat44_hairpinning_handoff_node)
+VLIB_NODE_FN (nat44_ei_hairpin_dst_node)
 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
-{
-  return nat44_hairpinning_handoff_fn_inline (
-    vm, node, frame, snat_main.nat44_hairpinning_fq_index);
-}
-
-VLIB_REGISTER_NODE (nat44_hairpinning_handoff_node) = {
-  .name = "nat44-hairpinning-handoff",
-  .vector_size = sizeof (u32),
-  .n_errors = ARRAY_LEN(nat44_hairpinning_handoff_error_strings),
-  .error_strings = nat44_hairpinning_handoff_error_strings,
-  .format_trace = format_nat44_hairpinning_handoff_trace,
-
-  .n_next_nodes = 1,
-
-  .next_nodes = {
-    [0] = "error-drop",
-  },
-};
-
-static inline uword
-snat_hairpin_dst_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
-                           vlib_frame_t *frame)
 {
   u32 n_left_from, *from, *to_next;
   u32 thread_index = vm->thread_index;
-  nat_hairpin_next_t next_index;
-  snat_main_t *sm = &snat_main;
+  nat44_ei_hairpin_next_t next_index;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -543,57 +514,55 @@ snat_hairpin_dst_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
-         next0 = NAT_HAIRPIN_NEXT_LOOKUP;
+         next0 = NAT44_EI_HAIRPIN_NEXT_LOOKUP;
          ip0 = vlib_buffer_get_current (b0);
          sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
 
          proto0 = ip_proto_to_nat_proto (ip0->protocol);
 
          vnet_buffer (b0)->snat.flags = 0;
-         if (PREDICT_FALSE (is_hairpinning (sm, &ip0->dst_address)))
+         if (PREDICT_FALSE (nat44_ei_is_hairpinning (nm, &ip0->dst_address)))
            {
              if (proto0 == NAT_PROTOCOL_TCP || proto0 == NAT_PROTOCOL_UDP)
                {
                  udp_header_t *udp0 = ip4_next_header (ip0);
                  tcp_header_t *tcp0 = (tcp_header_t *) udp0;
 
-                 snat_hairpinning (vm, node, sm, thread_index, b0, ip0, udp0,
-                                   tcp0, proto0, 1 /* do_trace */,
-                                   &required_thread_index);
+                 nat44_ei_hairpinning (vm, node, nm, thread_index, b0, ip0,
+                                       udp0, tcp0, proto0, 1 /* do_trace */,
+                                       &required_thread_index);
                }
              else if (proto0 == NAT_PROTOCOL_ICMP)
                {
                  icmp46_header_t *icmp0 = ip4_next_header (ip0);
 
-                 snat_icmp_hairpinning (sm, b0, thread_index, ip0, icmp0,
-                                        &required_thread_index);
+                 nat44_ei_icmp_hairpinning (nm, b0, thread_index, ip0, icmp0,
+                                            &required_thread_index);
                }
              else
                {
-                 nat_hairpinning_sm_unknown_proto (sm, b0, ip0);
+                 nat44_ei_hairpinning_unknown_proto (nm, b0, ip0);
                }
 
-             vnet_buffer (b0)->snat.flags = SNAT_FLAG_HAIRPINNING;
+             vnet_buffer (b0)->snat.flags = NAT44_EI_FLAG_HAIRPINNING;
            }
 
          if (thread_index != required_thread_index)
            {
              vnet_buffer (b0)->snat.required_thread_index =
                required_thread_index;
-             next0 = NAT_HAIRPIN_NEXT_HANDOFF;
+             next0 = NAT44_EI_HAIRPIN_NEXT_HANDOFF;
            }
 
-         if (next0 != NAT_HAIRPIN_NEXT_DROP)
+         if (next0 != NAT44_EI_HAIRPIN_NEXT_DROP)
            {
-             vlib_increment_simple_counter (&sm->counters.hairpinning,
-                                            vm->thread_index, sw_if_index0,
-                                            1);
+             vlib_increment_simple_counter (
+               &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1);
            }
 
          /* verify speculative enqueue, maybe switch current next frame */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, next0);
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
        }
 
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
@@ -602,54 +571,16 @@ snat_hairpin_dst_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
   return frame->n_vectors;
 }
 
-VLIB_NODE_FN (snat_hairpin_dst_node) (vlib_main_t * vm,
-                                     vlib_node_runtime_t * node,
-                                     vlib_frame_t * frame)
-{
-  return snat_hairpin_dst_fn_inline (vm, node, frame);
-}
-
-VLIB_REGISTER_NODE (snat_hairpin_dst_node) = {
-  .name = "nat44-hairpin-dst",
-  .vector_size = sizeof (u32),
-  .type = VLIB_NODE_TYPE_INTERNAL,
-  .format_trace = format_nat_hairpin_trace,
-  .n_next_nodes = NAT_HAIRPIN_N_NEXT,
-  .next_nodes = {
-    [NAT_HAIRPIN_NEXT_DROP] = "error-drop",
-    [NAT_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup",
-    [NAT_HAIRPIN_NEXT_HANDOFF] = "nat44-hairpin-dst-handoff",
-  },
-};
-
-VLIB_NODE_FN (nat44_hairpinning_dst_handoff_node)
+VLIB_NODE_FN (nat44_ei_hairpinning_node)
 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
-{
-  return nat44_hairpinning_handoff_fn_inline (
-    vm, node, frame, snat_main.snat_hairpin_dst_fq_index);
-}
-
-VLIB_REGISTER_NODE (nat44_hairpinning_dst_handoff_node) = {
-  .name = "nat44-hairpin-dst-handoff",
-  .vector_size = sizeof (u32),
-  .n_errors = ARRAY_LEN(nat44_hairpinning_handoff_error_strings),
-  .error_strings = nat44_hairpinning_handoff_error_strings,
-  .format_trace = format_nat44_hairpinning_handoff_trace,
-
-  .n_next_nodes = 1,
-
-  .next_nodes = {
-    [0] = "error-drop",
-  },
-};
-
-static inline uword
-snat_hairpin_src_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
-                           vlib_frame_t *frame)
 {
   u32 n_left_from, *from, *to_next;
-  snat_hairpin_src_next_t next_index;
-  snat_main_t *sm = &snat_main;
+  u32 thread_index = vm->thread_index;
+  nat44_ei_hairpin_next_t next_index;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  vnet_feature_main_t *fm = &feature_main;
+  u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index;
+  vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index];
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -666,8 +597,12 @@ snat_hairpin_src_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          u32 bi0;
          vlib_buffer_t *b0;
          u32 next0;
-         snat_interface_t *i;
+         ip4_header_t *ip0;
+         u32 proto0;
+         udp_header_t *udp0;
+         tcp_header_t *tcp0;
          u32 sw_if_index0;
+         u32 required_thread_index = thread_index;
 
          /* speculatively enqueue b0 to the current next frame */
          bi0 = from[0];
@@ -678,37 +613,43 @@ snat_hairpin_src_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
+         ip0 = vlib_buffer_get_current (b0);
+         udp0 = ip4_next_header (ip0);
+         tcp0 = (tcp_header_t *) udp0;
          sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-         vnet_feature_next (&next0, b0);
 
-          pool_foreach (i, sm->output_feature_interfaces)
-           {
-            /* Only packets from NAT inside interface */
-            if ((nat_interface_is_inside(i)) && (sw_if_index0 == i->sw_if_index))
-              {
-                if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) &
-                                    SNAT_FLAG_HAIRPINNING))
-                  {
-                    if (PREDICT_TRUE (sm->num_workers > 1))
-                      next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH;
-                    else
-                      next0 = SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT;
-                  }
-                break;
-              }
-          }
-
-         if (next0 != SNAT_HAIRPIN_SRC_NEXT_DROP)
+         proto0 = ip_proto_to_nat_proto (ip0->protocol);
+         int next0_resolved = 0;
+
+         if (nat44_ei_hairpinning (vm, node, nm, thread_index, b0, ip0, udp0,
+                                   tcp0, proto0, 1 /* do_trace */,
+                                   &required_thread_index))
+           {
+             next0 = NAT44_EI_HAIRPIN_NEXT_LOOKUP;
+             next0_resolved = 1;
+           }
+
+         if (thread_index != required_thread_index)
+           {
+             vnet_buffer (b0)->snat.required_thread_index =
+               required_thread_index;
+             next0 = NAT44_EI_HAIRPIN_NEXT_HANDOFF;
+             next0_resolved = 1;
+           }
+
+         if (!next0_resolved)
+           vnet_get_config_data (&cm->config_main, &b0->current_config_index,
+                                 &next0, 0);
+
+         if (next0 != NAT44_EI_HAIRPIN_NEXT_DROP)
            {
-             vlib_increment_simple_counter (&sm->counters.hairpinning,
-                                            vm->thread_index, sw_if_index0,
-                                            1);
+             vlib_increment_simple_counter (
+               &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1);
            }
 
          /* verify speculative enqueue, maybe switch current next frame */
-         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
-                                          to_next, n_left_to_next,
-                                          bi0, next0);
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
        }
 
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
@@ -717,23 +658,84 @@ snat_hairpin_src_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
   return frame->n_vectors;
 }
 
-VLIB_NODE_FN (snat_hairpin_src_node) (vlib_main_t * vm,
-                                     vlib_node_runtime_t * node,
-                                     vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_hairpinning_dst_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return snat_hairpin_src_fn_inline (vm, node, frame);
+  return nat44_ei_hairpinning_handoff_fn_inline (
+    vm, node, frame, nat44_ei_main.hairpin_dst_fq_index);
 }
 
-VLIB_REGISTER_NODE (snat_hairpin_src_node) = {
-  .name = "nat44-hairpin-src",
+VLIB_NODE_FN (nat44_ei_hairpinning_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return nat44_ei_hairpinning_handoff_fn_inline (
+    vm, node, frame, nat44_ei_main.hairpinning_fq_index);
+}
+
+VLIB_REGISTER_NODE (nat44_ei_hairpinning_dst_handoff_node) = {
+  .name = "nat44-ei-hairpin-dst-handoff",
+  .vector_size = sizeof (u32),
+  .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
+  .error_strings = nat44_ei_hairpinning_handoff_error_strings,
+  .format_trace = format_nat44_ei_hairpinning_handoff_trace,
+
+  .n_next_nodes = 1,
+
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (nat44_ei_hairpinning_handoff_node) = {
+  .name = "nat44-ei-hairpinning-handoff",
+  .vector_size = sizeof (u32),
+  .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
+  .error_strings = nat44_ei_hairpinning_handoff_error_strings,
+  .format_trace = format_nat44_ei_hairpinning_handoff_trace,
+
+  .n_next_nodes = 1,
+
+  .next_nodes = {
+    [0] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (nat44_ei_hairpin_src_node) = {
+  .name = "nat44-ei-hairpin-src",
+  .vector_size = sizeof (u32),
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_next_nodes = NAT44_EI_HAIRPIN_SRC_N_NEXT,
+  .next_nodes = {
+     [NAT44_EI_HAIRPIN_SRC_NEXT_DROP] = "error-drop",
+     [NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT] = "nat44-ei-in2out-output",
+     [NAT44_EI_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT] = "interface-output",
+     [NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH] = "nat44-ei-in2out-output-worker-handoff",
+  },
+};
+
+VLIB_REGISTER_NODE (nat44_ei_hairpin_dst_node) = {
+  .name = "nat44-ei-hairpin-dst",
+  .vector_size = sizeof (u32),
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .format_trace = format_nat44_ei_hairpin_trace,
+  .n_next_nodes = NAT44_EI_HAIRPIN_N_NEXT,
+  .next_nodes = {
+    [NAT44_EI_HAIRPIN_NEXT_DROP] = "error-drop",
+    [NAT44_EI_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_HAIRPIN_NEXT_HANDOFF] = "nat44-ei-hairpin-dst-handoff",
+  },
+};
+
+VLIB_REGISTER_NODE (nat44_ei_hairpinning_node) = {
+  .name = "nat44-ei-hairpinning",
   .vector_size = sizeof (u32),
   .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_next_nodes = SNAT_HAIRPIN_SRC_N_NEXT,
+  .format_trace = format_nat44_ei_hairpin_trace,
+  .n_next_nodes = NAT44_EI_HAIRPIN_N_NEXT,
   .next_nodes = {
-     [SNAT_HAIRPIN_SRC_NEXT_DROP] = "error-drop",
-     [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT] = "nat44-in2out-output",
-     [SNAT_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT] = "interface-output",
-     [SNAT_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH] = "nat44-in2out-output-worker-handoff",
+    [NAT44_EI_HAIRPIN_NEXT_DROP] = "error-drop",
+    [NAT44_EI_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_HAIRPIN_NEXT_HANDOFF] = "nat44-ei-hairpinning-handoff",
   },
 };
 
similarity index 56%
rename from src/plugins/nat/nat44_hairpinning.h
rename to src/plugins/nat/nat44-ei/nat44_ei_hairpinning.h
index 2a8b73d..bdd2d21 100644 (file)
@@ -1,48 +1,48 @@
-#ifndef __included_nat44_hairpinning_h__
-#define __included_nat44_hairpinning_h__
+#ifndef __included_nat44_ei_hairpinning_h__
+#define __included_nat44_ei_hairpinning_h__
 
-#include <nat/nat.h>
+#include <nat/nat44-ei/nat44_ei.h>
 
-#define foreach_nat44_hairpinning_handoff_error                               \
+#define foreach_nat44_ei_hairpinning_handoff_error                            \
   _ (CONGESTION_DROP, "congestion drop")
 
 typedef enum
 {
-#define _(sym, str) NAT44_HAIRPINNING_HANDOFF_ERROR_##sym,
-  foreach_nat44_hairpinning_handoff_error
+#define _(sym, str) NAT44_EI_HAIRPINNING_HANDOFF_ERROR_##sym,
+  foreach_nat44_ei_hairpinning_handoff_error
 #undef _
-    NAT44_HAIRPINNING_HANDOFF_N_ERROR,
-} nat44_hairpinning_handoff_error_t;
+    NAT44_EI_HAIRPINNING_HANDOFF_N_ERROR,
+} nat44_ei_hairpinning_handoff_error_t;
 
-static char *nat44_hairpinning_handoff_error_strings[] = {
+static char *nat44_ei_hairpinning_handoff_error_strings[] = {
 #define _(sym, string) string,
-  foreach_nat44_hairpinning_handoff_error
+  foreach_nat44_ei_hairpinning_handoff_error
 #undef _
 };
 
 typedef struct
 {
   u32 next_worker_index;
-} nat44_hairpinning_handoff_trace_t;
+} nat44_ei_hairpinning_handoff_trace_t;
 
 static u8 *
-format_nat44_hairpinning_handoff_trace (u8 *s, va_list *args)
+format_nat44_ei_hairpinning_handoff_trace (u8 *s, va_list *args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  nat44_hairpinning_handoff_trace_t *t =
-    va_arg (*args, nat44_hairpinning_handoff_trace_t *);
+  nat44_ei_hairpinning_handoff_trace_t *t =
+    va_arg (*args, nat44_ei_hairpinning_handoff_trace_t *);
 
-  s = format (s, "nat-hairpinning-handoff: next-worker %d",
+  s = format (s, "nat44-ei-hairpinning-handoff: next-worker %d",
              t->next_worker_index);
 
   return s;
 }
 
 always_inline uword
-nat44_hairpinning_handoff_fn_inline (vlib_main_t *vm,
-                                    vlib_node_runtime_t *node,
-                                    vlib_frame_t *frame, u32 fq_index)
+nat44_ei_hairpinning_handoff_fn_inline (vlib_main_t *vm,
+                                       vlib_node_runtime_t *node,
+                                       vlib_frame_t *frame, u32 fq_index)
 {
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
   u32 n_enq, n_left_from, *from;
@@ -62,7 +62,7 @@ nat44_hairpinning_handoff_fn_inline (vlib_main_t *vm,
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
                         (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         nat44_hairpinning_handoff_trace_t *t =
+         nat44_ei_hairpinning_handoff_trace_t *t =
            vlib_add_trace (vm, node, b[0], sizeof (*t));
          t->next_worker_index = ti[0];
        }
@@ -76,12 +76,12 @@ nat44_hairpinning_handoff_fn_inline (vlib_main_t *vm,
 
   if (n_enq < frame->n_vectors)
     vlib_node_increment_counter (
-      vm, node->node_index, NAT44_HAIRPINNING_HANDOFF_ERROR_CONGESTION_DROP,
+      vm, node->node_index, NAT44_EI_HAIRPINNING_HANDOFF_ERROR_CONGESTION_DROP,
       frame->n_vectors - n_enq);
   return frame->n_vectors;
 }
 
-#endif // __included_nat44_hairpinning_h__
+#endif // __included_nat44_ei_hairpinning_h__
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_handoff.c b/src/plugins/nat/nat44-ei/nat44_ei_handoff.c
new file mode 100644 (file)
index 0000000..6b8db37
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/handoff.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vppinfra/error.h>
+
+#include <nat/nat44-ei/nat44_ei.h>
+
+typedef struct
+{
+  u32 next_worker_index;
+  u32 trace_index;
+  u8 in2out;
+  u8 output;
+} nat44_ei_handoff_trace_t;
+
+#define foreach_nat44_ei_handoff_error                                        \
+  _ (CONGESTION_DROP, "congestion drop")                                      \
+  _ (SAME_WORKER, "same worker")                                              \
+  _ (DO_HANDOFF, "do handoff")
+
+typedef enum
+{
+#define _(sym, str) NAT44_EI_HANDOFF_ERROR_##sym,
+  foreach_nat44_ei_handoff_error
+#undef _
+    NAT44_EI_HANDOFF_N_ERROR,
+} nat44_ei_handoff_error_t;
+
+static char *nat44_ei_handoff_error_strings[] = {
+#define _(sym, string) string,
+  foreach_nat44_ei_handoff_error
+#undef _
+};
+
+static u8 *
+format_nat44_ei_handoff_trace (u8 *s, va_list *args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  nat44_ei_handoff_trace_t *t = va_arg (*args, nat44_ei_handoff_trace_t *);
+  char *tag, *output;
+
+  tag = t->in2out ? "IN2OUT" : "OUT2IN";
+  output = t->output ? "OUTPUT-FEATURE" : "";
+  s =
+    format (s, "NAT44_EI_%s_WORKER_HANDOFF %s: next-worker %d trace index %d",
+           tag, output, t->next_worker_index, t->trace_index);
+
+  return s;
+}
+
+static inline uword
+nat44_ei_worker_handoff_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                                  vlib_frame_t *frame, u8 is_output,
+                                  u8 is_in2out)
+{
+  u32 n_enq, n_left_from, *from, do_handoff = 0, same_worker = 0;
+
+  u16 thread_indices[VLIB_FRAME_SIZE], *ti = thread_indices;
+  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  u32 fq_index, thread_index = vm->thread_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+
+  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;
+    }
+  else
+    {
+      fq_index = nm->fq_out2in_index;
+    }
+
+  while (n_left_from >= 4)
+    {
+      u32 arc_next0, arc_next1, arc_next2, arc_next3;
+      u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
+      u32 rx_fib_index0, rx_fib_index1, rx_fib_index2, rx_fib_index3;
+      u32 iph_offset0 = 0, iph_offset1 = 0, iph_offset2 = 0, iph_offset3 = 0;
+      ip4_header_t *ip0, *ip1, *ip2, *ip3;
+
+      if (PREDICT_TRUE (n_left_from >= 8))
+       {
+         vlib_prefetch_buffer_header (b[4], LOAD);
+         vlib_prefetch_buffer_header (b[5], LOAD);
+         vlib_prefetch_buffer_header (b[6], LOAD);
+         vlib_prefetch_buffer_header (b[7], LOAD);
+         CLIB_PREFETCH (&b[4]->data, CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (&b[5]->data, CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (&b[6]->data, CLIB_CACHE_LINE_BYTES, LOAD);
+         CLIB_PREFETCH (&b[7]->data, CLIB_CACHE_LINE_BYTES, LOAD);
+       }
+
+      if (is_output)
+       {
+         iph_offset0 = vnet_buffer (b[0])->ip.save_rewrite_length;
+         iph_offset1 = vnet_buffer (b[1])->ip.save_rewrite_length;
+         iph_offset2 = vnet_buffer (b[2])->ip.save_rewrite_length;
+         iph_offset3 = vnet_buffer (b[3])->ip.save_rewrite_length;
+       }
+
+      ip0 =
+       (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[0]) + iph_offset0);
+      ip1 =
+       (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[1]) + iph_offset1);
+      ip2 =
+       (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[2]) + iph_offset2);
+      ip3 =
+       (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[3]) + iph_offset3);
+
+      vnet_feature_next (&arc_next0, b[0]);
+      vnet_feature_next (&arc_next1, b[1]);
+      vnet_feature_next (&arc_next2, b[2]);
+      vnet_feature_next (&arc_next3, b[3]);
+
+      vnet_buffer2 (b[0])->nat.arc_next = arc_next0;
+      vnet_buffer2 (b[1])->nat.arc_next = arc_next1;
+      vnet_buffer2 (b[2])->nat.arc_next = arc_next2;
+      vnet_buffer2 (b[3])->nat.arc_next = arc_next3;
+
+      sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
+      sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
+      sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
+      sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
+
+      rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
+      rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
+      rx_fib_index2 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index2);
+      rx_fib_index3 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index3);
+
+      if (is_in2out)
+       {
+         ti[0] = nm->worker_in2out_cb (ip0, rx_fib_index0, is_output);
+         ti[1] = nm->worker_in2out_cb (ip1, rx_fib_index1, is_output);
+         ti[2] = nm->worker_in2out_cb (ip2, rx_fib_index2, is_output);
+         ti[3] = nm->worker_in2out_cb (ip3, rx_fib_index3, is_output);
+       }
+      else
+       {
+         ti[0] = nm->worker_out2in_cb (b[0], ip0, rx_fib_index0, is_output);
+         ti[1] = nm->worker_out2in_cb (b[1], ip1, rx_fib_index1, is_output);
+         ti[2] = nm->worker_out2in_cb (b[2], ip2, rx_fib_index2, is_output);
+         ti[3] = nm->worker_out2in_cb (b[3], ip3, rx_fib_index3, is_output);
+       }
+
+      if (ti[0] == thread_index)
+       same_worker++;
+      else
+       do_handoff++;
+
+      if (ti[1] == thread_index)
+       same_worker++;
+      else
+       do_handoff++;
+
+      if (ti[2] == thread_index)
+       same_worker++;
+      else
+       do_handoff++;
+
+      if (ti[3] == thread_index)
+       same_worker++;
+      else
+       do_handoff++;
+
+      b += 4;
+      ti += 4;
+      n_left_from -= 4;
+    }
+
+  while (n_left_from > 0)
+    {
+      u32 arc_next0;
+      u32 sw_if_index0;
+      u32 rx_fib_index0;
+      u32 iph_offset0 = 0;
+      ip4_header_t *ip0;
+
+      if (is_output)
+       iph_offset0 = vnet_buffer (b[0])->ip.save_rewrite_length;
+
+      ip0 =
+       (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b[0]) + iph_offset0);
+
+      vnet_feature_next (&arc_next0, b[0]);
+      vnet_buffer2 (b[0])->nat.arc_next = arc_next0;
+
+      sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
+      rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
+
+      if (is_in2out)
+       {
+         ti[0] = nm->worker_in2out_cb (ip0, rx_fib_index0, is_output);
+       }
+      else
+       {
+         ti[0] = nm->worker_out2in_cb (b[0], ip0, rx_fib_index0, is_output);
+       }
+
+      if (ti[0] == thread_index)
+       same_worker++;
+      else
+       do_handoff++;
+
+      b += 1;
+      ti += 1;
+      n_left_from -= 1;
+    }
+
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+    {
+      u32 i;
+      b = bufs;
+      ti = thread_indices;
+
+      for (i = 0; i < frame->n_vectors; i++)
+       {
+         if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
+           {
+             nat44_ei_handoff_trace_t *t =
+               vlib_add_trace (vm, node, b[0], sizeof (*t));
+             t->next_worker_index = ti[0];
+             t->trace_index = vlib_buffer_get_trace_index (b[0]);
+             t->in2out = is_in2out;
+             t->output = is_output;
+
+             b += 1;
+             ti += 1;
+           }
+         else
+           break;
+       }
+    }
+
+  n_enq = vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
+                                        frame->n_vectors, 1);
+
+  if (n_enq < frame->n_vectors)
+    {
+      vlib_node_increment_counter (vm, node->node_index,
+                                  NAT44_EI_HANDOFF_ERROR_CONGESTION_DROP,
+                                  frame->n_vectors - n_enq);
+    }
+
+  vlib_node_increment_counter (
+    vm, node->node_index, NAT44_EI_HANDOFF_ERROR_SAME_WORKER, same_worker);
+  vlib_node_increment_counter (vm, node->node_index,
+                              NAT44_EI_HANDOFF_ERROR_DO_HANDOFF, do_handoff);
+  return frame->n_vectors;
+}
+
+VLIB_NODE_FN (nat44_ei_in2out_worker_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return nat44_ei_worker_handoff_fn_inline (vm, node, frame, 0, 1);
+}
+
+VLIB_NODE_FN (nat44_ei_in2out_output_worker_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return nat44_ei_worker_handoff_fn_inline (vm, node, frame, 1, 1);
+}
+
+VLIB_NODE_FN (nat44_ei_out2in_worker_handoff_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+  return nat44_ei_worker_handoff_fn_inline (vm, node, frame, 0, 0);
+}
+
+VLIB_REGISTER_NODE (nat44_ei_in2out_output_worker_handoff_node) = {
+  .name = "nat44-ei-in2out-output-worker-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_nat44_ei_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (nat44_ei_handoff_error_strings),
+  .error_strings = nat44_ei_handoff_error_strings,
+};
+
+VLIB_REGISTER_NODE (nat44_ei_in2out_worker_handoff_node) = {
+  .name = "nat44-ei-in2out-worker-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_nat44_ei_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (nat44_ei_handoff_error_strings),
+  .error_strings = nat44_ei_handoff_error_strings,
+};
+
+VLIB_REGISTER_NODE (nat44_ei_out2in_worker_handoff_node) = {
+  .name = "nat44-ei-out2in-worker-handoff",
+  .vector_size = sizeof (u32),
+  .format_trace = format_nat44_ei_handoff_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (nat44_ei_handoff_error_strings),
+  .error_strings = nat44_ei_handoff_error_strings,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 54ed1a9..80beb7a 100644 (file)
  */
 /**
  * @file
- * @brief NAT44 inside to outside network translation
+ * @brief NAT44 EI inside to outside network translation
  */
 
 #include <vlib/vlib.h>
-#include <vnet/vnet.h>
 
+#include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
 #include <vnet/ethernet/ethernet.h>
-#include <vnet/fib/ip4_fib.h>
 #include <vnet/udp/udp_local.h>
-#include <nat/nat.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/nat_inlines.h>
-#include <nat/lib/nat_syslog.h>
-#include <nat/nat44-ei/nat44_ei_inlines.h>
-#include <nat/nat44-ei/nat44_ei.h>
+#include <vnet/fib/ip4_fib.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
-#include <vppinfra/elog.h>
+
+#include <nat/lib/log.h>
+#include <nat/lib/nat_syslog.h>
+#include <nat/lib/ipfix_logging.h>
 #include <nat/lib/nat_inlines.h>
-#include <nat/nat44_hairpinning.h>
+#include <nat/nat44-ei/nat44_ei_inlines.h>
+#include <nat/nat44-ei/nat44_ei.h>
+#include <nat/nat44-ei/nat44_ei_hairpinning.h>
 
 typedef struct
 {
@@ -44,15 +43,15 @@ typedef struct
   u32 session_index;
   u32 is_slow_path;
   u32 is_hairpinning;
-} snat_in2out_trace_t;
+} nat44_ei_in2out_trace_t;
 
 /* packet trace format function */
 static u8 *
-format_snat_in2out_trace (u8 * s, va_list * args)
+format_nat44_ei_in2out_trace (u8 *s, va_list *args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  snat_in2out_trace_t *t = va_arg (*args, snat_in2out_trace_t *);
+  nat44_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *);
   char *tag;
 
   tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH";
@@ -68,11 +67,11 @@ format_snat_in2out_trace (u8 * s, va_list * args)
 }
 
 static u8 *
-format_snat_in2out_fast_trace (u8 * s, va_list * args)
+format_nat44_ei_in2out_fast_trace (u8 *s, va_list *args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  snat_in2out_trace_t *t = va_arg (*args, snat_in2out_trace_t *);
+  nat44_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *);
 
   s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d",
              t->sw_if_index, t->next_index);
@@ -80,67 +79,125 @@ format_snat_in2out_fast_trace (u8 * s, va_list * args)
   return s;
 }
 
-#define foreach_snat_in2out_error                       \
-_(UNSUPPORTED_PROTOCOL, "unsupported protocol")         \
-_(OUT_OF_PORTS, "out of ports")                         \
-_(BAD_OUTSIDE_FIB, "outside VRF ID not found")          \
-_(BAD_ICMP_TYPE, "unsupported ICMP type")               \
-_(NO_TRANSLATION, "no translation")                     \
-_(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")   \
-_(CANNOT_CREATE_USER, "cannot create NAT user")
+#define foreach_nat44_ei_in2out_error                                         \
+  _ (UNSUPPORTED_PROTOCOL, "unsupported protocol")                            \
+  _ (OUT_OF_PORTS, "out of ports")                                            \
+  _ (BAD_OUTSIDE_FIB, "outside VRF ID not found")                             \
+  _ (BAD_ICMP_TYPE, "unsupported ICMP type")                                  \
+  _ (NO_TRANSLATION, "no translation")                                        \
+  _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")                      \
+  _ (CANNOT_CREATE_USER, "cannot create NAT user")
 
 typedef enum
 {
-#define _(sym,str) SNAT_IN2OUT_ERROR_##sym,
-  foreach_snat_in2out_error
+#define _(sym, str) NAT44_EI_IN2OUT_ERROR_##sym,
+  foreach_nat44_ei_in2out_error
 #undef _
-    SNAT_IN2OUT_N_ERROR,
-} snat_in2out_error_t;
+    NAT44_EI_IN2OUT_N_ERROR,
+} nat44_ei_in2out_error_t;
 
-static char *snat_in2out_error_strings[] = {
+static char *nat44_ei_in2out_error_strings[] = {
 #define _(sym,string) string,
-  foreach_snat_in2out_error
+  foreach_nat44_ei_in2out_error
 #undef _
 };
 
 typedef enum
 {
-  SNAT_IN2OUT_NEXT_LOOKUP,
-  SNAT_IN2OUT_NEXT_DROP,
-  SNAT_IN2OUT_NEXT_ICMP_ERROR,
-  SNAT_IN2OUT_NEXT_SLOW_PATH,
-  SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF,
-  SNAT_IN2OUT_N_NEXT,
-} snat_in2out_next_t;
+  NAT44_EI_IN2OUT_NEXT_LOOKUP,
+  NAT44_EI_IN2OUT_NEXT_DROP,
+  NAT44_EI_IN2OUT_NEXT_ICMP_ERROR,
+  NAT44_EI_IN2OUT_NEXT_SLOW_PATH,
+  NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF,
+  NAT44_EI_IN2OUT_N_NEXT,
+} nat44_ei_in2out_next_t;
 
 typedef enum
 {
-  NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP,
-  NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP,
-  NAT44_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
-} nat44_in2out_hairpinnig_finish_next_t;
+  NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP,
+  NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP,
+  NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
+} nat44_ei_in2out_hairpinnig_finish_next_t;
+
+static inline int
+nat44_ei_not_translate_fast (vlib_node_runtime_t *node, u32 sw_if_index0,
+                            ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+
+  if (nm->out2in_dpo)
+    return 0;
+
+  fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+  nat44_ei_outside_fib_t *outside_fib;
+  fib_prefix_t pfx = {
+    .fp_proto = FIB_PROTOCOL_IP4,
+    .fp_len = 32,
+    .fp_addr = {
+               .ip4.as_u32 = ip0->dst_address.as_u32,
+               }
+    ,
+  };
+
+  /* Don't NAT packet aimed at the intfc address */
+  if (PREDICT_FALSE (nat44_ei_is_interface_addr (
+       nm->ip4_main, node, sw_if_index0, ip0->dst_address.as_u32)))
+    return 1;
+
+  fei = fib_table_lookup (rx_fib_index0, &pfx);
+  if (FIB_NODE_INDEX_INVALID != fei)
+    {
+      u32 sw_if_index = fib_entry_get_resolving_interface (fei);
+      if (sw_if_index == ~0)
+       {
+         vec_foreach (outside_fib, nm->outside_fibs)
+           {
+             fei = fib_table_lookup (outside_fib->fib_index, &pfx);
+             if (FIB_NODE_INDEX_INVALID != fei)
+               {
+                 sw_if_index = fib_entry_get_resolving_interface (fei);
+                 if (sw_if_index != ~0)
+                   break;
+               }
+           }
+       }
+      if (sw_if_index == ~0)
+       return 1;
+
+      nat44_ei_interface_t *i;
+      pool_foreach (i, nm->interfaces)
+       {
+         /* NAT packet aimed at outside interface */
+         if ((nat44_ei_interface_is_outside (i)) &&
+             (sw_if_index == i->sw_if_index))
+           return 0;
+       }
+    }
+
+  return 1;
+}
 
 static inline int
-snat_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
-                   u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
-                   u32 rx_fib_index0, u32 thread_index)
+nat44_ei_not_translate (nat44_ei_main_t *nm, vlib_node_runtime_t *node,
+                       u32 sw_if_index0, ip4_header_t *ip0, u32 proto0,
+                       u32 rx_fib_index0, u32 thread_index)
 {
   udp_header_t *udp0 = ip4_next_header (ip0);
   clib_bihash_kv_8_8_t kv0, value0;
 
-  init_nat_k (&kv0, ip0->dst_address, udp0->dst_port, sm->outside_fib_index,
+  init_nat_k (&kv0, ip0->dst_address, udp0->dst_port, nm->outside_fib_index,
              proto0);
 
   /* NAT packet aimed at external address if */
   /* has active sessions */
-  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
+  if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
     {
       /* or is static mappings */
       ip4_address_t placeholder_addr;
       u16 placeholder_port;
       u32 placeholder_fib_index;
       if (!nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port,
-                                         sm->outside_fib_index, proto0,
+                                         nm->outside_fib_index, proto0,
                                          &placeholder_addr, &placeholder_port,
                                          &placeholder_fib_index, 1, 0, 0))
        return 0;
@@ -148,37 +205,38 @@ snat_not_translate (snat_main_t * sm, vlib_node_runtime_t * node,
   else
     return 0;
 
-  if (sm->forwarding_enabled)
+  if (nm->forwarding_enabled)
     return 1;
 
-  return snat_not_translate_fast (sm, node, sw_if_index0, ip0, proto0,
-                                 rx_fib_index0);
+  return nat44_ei_not_translate_fast (node, sw_if_index0, ip0, proto0,
+                                     rx_fib_index0);
 }
 
 static inline int
-nat_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip0,
-                                 u32 proto0, u16 src_port, u16 dst_port,
-                                 u32 thread_index, u32 sw_if_index)
+nat44_ei_not_translate_output_feature (nat44_ei_main_t *nm, ip4_header_t *ip0,
+                                      u32 proto0, u16 src_port, u16 dst_port,
+                                      u32 thread_index, u32 sw_if_index)
 {
   clib_bihash_kv_8_8_t kv0, value0;
-  snat_interface_t *i;
+  nat44_ei_interface_t *i;
 
   /* src NAT check */
   init_nat_k (&kv0, ip0->src_address, src_port,
              ip4_fib_table_get_index_for_sw_if_index (sw_if_index), proto0);
 
-  if (!clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
+  if (!clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
     return 1;
 
   /* dst NAT check */
   init_nat_k (&kv0, ip0->dst_address, dst_port,
              ip4_fib_table_get_index_for_sw_if_index (sw_if_index), proto0);
-  if (!clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
+  if (!clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
     {
       /* hairpinning */
-      pool_foreach (i, sm->output_feature_interfaces)
+      pool_foreach (i, nm->output_feature_interfaces)
        {
-         if ((nat_interface_is_inside (i)) && (sw_if_index == i->sw_if_index))
+         if ((nat44_ei_interface_is_inside (i)) &&
+             (sw_if_index == i->sw_if_index))
            return 0;
        }
       return 1;
@@ -191,21 +249,22 @@ nat_not_translate_output_feature (snat_main_t * sm, ip4_header_t * ip0,
 int
 nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
 {
-  snat_main_t *sm = &snat_main;
-  nat44_is_idle_session_ctx_t *ctx = arg;
-  snat_session_t *s;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_is_idle_session_ctx_t *ctx = arg;
+  nat44_ei_session_t *s;
   u64 sess_timeout_time;
-  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
-                                                      ctx->thread_index);
+  nat44_ei_main_per_thread_data_t *tnm =
+    vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
   clib_bihash_kv_8_8_t s_kv;
 
-  s = pool_elt_at_index (tsm->sessions, kv->value);
-  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
+  s = pool_elt_at_index (tnm->sessions, kv->value);
+  sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
+                                       &nm->timeouts, s->nat_proto, s->state);
   if (ctx->now >= sess_timeout_time)
     {
       init_nat_o2i_k (&s_kv, s);
-      if (clib_bihash_add_del_8_8 (&sm->out2in, &s_kv, 0))
-       nat_elog_warn ("out2in key del failed");
+      if (clib_bihash_add_del_8_8 (&nm->out2in, &s_kv, 0))
+       nat_elog_warn (nm, "out2in key del failed");
 
       nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
                                          s->in2out.addr.as_u32,
@@ -223,12 +282,12 @@ nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
                   s->ext_host_port, s->nat_proto, s->out2in.fib_index,
                   ctx->thread_index);
 
-      if (!snat_is_session_static (s))
-       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
-                                           &s->out2in.addr,
-                                           s->out2in.port, s->nat_proto);
+      if (!nat44_ei_is_session_static (s))
+       nat44_ei_free_outside_address_and_port (
+         nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
+         s->nat_proto);
 
-      nat44_delete_session (sm, s, ctx->thread_index);
+      nat44_ei_delete_session (nm, s, ctx->thread_index);
       return 1;
     }
 
@@ -237,20 +296,16 @@ nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
 #endif
 
 static u32
-slow_path (snat_main_t * sm, vlib_buffer_t * b0,
-          ip4_header_t * ip0,
-          ip4_address_t i2o_addr,
-          u16 i2o_port,
-          u32 rx_fib_index0,
-          nat_protocol_t nat_proto,
-          snat_session_t ** sessionp,
-          vlib_node_runtime_t * node, u32 next0, u32 thread_index, f64 now)
+slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0,
+          ip4_address_t i2o_addr, u16 i2o_port, u32 rx_fib_index0,
+          nat_protocol_t nat_proto, nat44_ei_session_t **sessionp,
+          vlib_node_runtime_t *node, u32 next0, u32 thread_index, f64 now)
 {
-  snat_user_t *u;
-  snat_session_t *s = 0;
+  nat44_ei_user_t *u;
+  nat44_ei_session_t *s = 0;
   clib_bihash_kv_8_8_t kv0;
   u8 is_sm = 0;
-  nat_outside_fib_t *outside_fib;
+  nat44_ei_outside_fib_t *outside_fib;
   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
   u8 identity_nat;
   fib_prefix_t pfx = {
@@ -260,18 +315,18 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
                .ip4.as_u32 = ip0->dst_address.as_u32,
                },
   };
-  nat44_is_idle_session_ctx_t ctx0;
+  nat44_ei_is_idle_session_ctx_t ctx0;
   ip4_address_t sm_addr;
   u16 sm_port;
   u32 sm_fib_index;
 
-  if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (sm, thread_index)))
+  if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
     {
-      b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
+      b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED];
       nat_ipfix_logging_max_sessions (thread_index,
-                                     sm->max_translations_per_thread);
-      nat_elog_notice ("maximum sessions exceeded");
-      return SNAT_IN2OUT_NEXT_DROP;
+                                     nm->max_translations_per_thread);
+      nat_elog_notice (nm, "maximum sessions exceeded");
+      return NAT44_EI_IN2OUT_NEXT_DROP;
     }
 
   /* First try to match static mapping by local address and port */
@@ -280,13 +335,13 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
                                     &sm_fib_index, 0, 0, &identity_nat))
     {
       /* Try to create dynamic translation */
-      if (sm->alloc_addr_and_port (
-           sm->addresses, rx_fib_index0, thread_index, nat_proto, &sm_addr,
-           &sm_port, sm->port_per_thread,
-           sm->per_thread_data[thread_index].snat_thread_index))
+      if (nm->alloc_addr_and_port (
+           nm->addresses, rx_fib_index0, thread_index, nat_proto, &sm_addr,
+           &sm_port, nm->port_per_thread,
+           nm->per_thread_data[thread_index].snat_thread_index))
        {
-         b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS];
-         return SNAT_IN2OUT_NEXT_DROP;
+         b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_OUT_OF_PORTS];
+         return NAT44_EI_IN2OUT_NEXT_DROP;
        }
     }
   else
@@ -300,53 +355,53 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
       is_sm = 1;
     }
 
-  u = nat_user_get_or_create (sm, &ip0->src_address, rx_fib_index0,
-                             thread_index);
+  u = nat44_ei_user_get_or_create (nm, &ip0->src_address, rx_fib_index0,
+                                  thread_index);
   if (!u)
     {
-      b0->error = node->errors[SNAT_IN2OUT_ERROR_CANNOT_CREATE_USER];
-      return SNAT_IN2OUT_NEXT_DROP;
+      b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_CANNOT_CREATE_USER];
+      return NAT44_EI_IN2OUT_NEXT_DROP;
     }
 
-  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
+  s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
   if (!s)
     {
-      nat44_delete_user_with_no_session (sm, u, thread_index);
-      nat_elog_warn ("create NAT session failed");
-      return SNAT_IN2OUT_NEXT_DROP;
+      nat44_ei_delete_user_with_no_session (nm, u, thread_index);
+      nat_elog_warn (nm, "create NAT session failed");
+      return NAT44_EI_IN2OUT_NEXT_DROP;
     }
 
   if (is_sm)
-    s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
-  user_session_increment (sm, u, is_sm);
+    s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
+  nat44_ei_user_session_increment (nm, u, is_sm);
   s->in2out.addr = i2o_addr;
   s->in2out.port = i2o_port;
   s->in2out.fib_index = rx_fib_index0;
   s->nat_proto = nat_proto;
   s->out2in.addr = sm_addr;
   s->out2in.port = sm_port;
-  s->out2in.fib_index = sm->outside_fib_index;
-  switch (vec_len (sm->outside_fibs))
+  s->out2in.fib_index = nm->outside_fib_index;
+  switch (vec_len (nm->outside_fibs))
     {
     case 0:
-      s->out2in.fib_index = sm->outside_fib_index;
+      s->out2in.fib_index = nm->outside_fib_index;
       break;
     case 1:
-      s->out2in.fib_index = sm->outside_fibs[0].fib_index;
+      s->out2in.fib_index = nm->outside_fibs[0].fib_index;
       break;
     default:
-      vec_foreach (outside_fib, sm->outside_fibs)
-        {
-          fei = fib_table_lookup (outside_fib->fib_index, &pfx);
-          if (FIB_NODE_INDEX_INVALID != fei)
-            {
-              if (fib_entry_get_resolving_interface (fei) != ~0)
-                {
-                  s->out2in.fib_index = outside_fib->fib_index;
-                  break;
-                }
-            }
-        }
+      vec_foreach (outside_fib, nm->outside_fibs)
+       {
+         fei = fib_table_lookup (outside_fib->fib_index, &pfx);
+         if (FIB_NODE_INDEX_INVALID != fei)
+           {
+             if (fib_entry_get_resolving_interface (fei) != ~0)
+               {
+                 s->out2in.fib_index = outside_fib->fib_index;
+                 break;
+               }
+           }
+       }
       break;
     }
   s->ext_host_addr.as_u32 = ip0->dst_address.as_u32;
@@ -357,41 +412,38 @@ slow_path (snat_main_t * sm, vlib_buffer_t * b0,
   ctx0.now = now;
   ctx0.thread_index = thread_index;
   init_nat_i2o_kv (&kv0, s, thread_index,
-                  s - sm->per_thread_data[thread_index].sessions);
+                  s - nm->per_thread_data[thread_index].sessions);
   if (clib_bihash_add_or_overwrite_stale_8_8 (
-       &sm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
-    nat_elog_notice ("in2out key add failed");
+       &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
+    nat_elog_notice (nm, "in2out key add failed");
 
   init_nat_o2i_kv (&kv0, s, thread_index,
-                  s - sm->per_thread_data[thread_index].sessions);
+                  s - nm->per_thread_data[thread_index].sessions);
   if (clib_bihash_add_or_overwrite_stale_8_8 (
-       &sm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
-    nat_elog_notice ("out2in key add failed");
+       &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
+    nat_elog_notice (nm, "out2in key add failed");
 
   /* log NAT event */
-  nat_ipfix_logging_nat44_ses_create (thread_index,
-                                     s->in2out.addr.as_u32,
-                                     s->out2in.addr.as_u32,
-                                     s->nat_proto,
-                                     s->in2out.port,
-                                     s->out2in.port, s->in2out.fib_index);
+  nat_ipfix_logging_nat44_ses_create (
+    thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->nat_proto,
+    s->in2out.port, s->out2in.port, s->in2out.fib_index);
 
-  nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
-                          &s->in2out.addr, s->in2out.port, &s->out2in.addr,
-                          s->out2in.port, s->nat_proto);
+  nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index, &s->in2out.addr,
+                          s->in2out.port, &s->out2in.addr, s->out2in.port,
+                          s->nat_proto);
 
   nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
               s->out2in.port, &s->ext_host_addr, s->ext_host_port,
-              &s->ext_host_nat_addr, s->ext_host_nat_port,
-              s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
+              &s->ext_host_nat_addr, s->ext_host_nat_port, s->nat_proto,
+              s->in2out.fib_index, s->flags, thread_index, 0);
 
   return next0;
 }
 
 #ifndef CLIB_MARCH_VARIANT
-static_always_inline snat_in2out_error_t
-icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
-             ip4_address_t * addr, u16 * port, nat_protocol_t * nat_proto)
+static_always_inline nat44_ei_in2out_error_t
+icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
+             u16 *port, nat_protocol_t *nat_proto)
 {
   icmp46_header_t *icmp0;
   icmp_echo_header_t *echo0, *inner_echo0 = 0;
@@ -427,7 +479,7 @@ icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
          *port = ((tcp_udp_header_t *) l4_header)->dst_port;
          break;
        default:
-         return SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
+         return NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL;
        }
     }
   return -1;                   /* success */
@@ -437,7 +489,7 @@ icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
  * Get address and port values to be used for ICMP packet translation
  * and create session if needed
  *
- * @param[in,out] sm             NAT main
+ * @param[in,out] nm             NAT main
  * @param[in,out] node           NAT node runtime
  * @param[in] thread_index       thread index
  * @param[in,out] b0             buffer containing packet to be translated
@@ -449,15 +501,16 @@ icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
  * @param e                      optional parameter
  */
 u32
-icmp_match_in2out_slow (snat_main_t *sm, vlib_node_runtime_t *node,
-                       u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0,
-                       ip4_address_t *addr, u16 *port, u32 *fib_index,
-                       nat_protocol_t *proto, snat_session_t **p_s0,
-                       u8 *dont_translate)
+nat44_ei_icmp_match_in2out_slow (vlib_node_runtime_t *node, u32 thread_index,
+                                vlib_buffer_t *b0, ip4_header_t *ip0,
+                                ip4_address_t *addr, u16 *port,
+                                u32 *fib_index, nat_protocol_t *proto,
+                                nat44_ei_session_t **p_s0, u8 *dont_translate)
 {
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
   u32 sw_if_index0;
-  snat_session_t *s0 = 0;
+  nat44_ei_session_t *s0 = 0;
   clib_bihash_kv_8_8_t kv0, value0;
   u32 next0 = ~0;
   int err;
@@ -471,18 +524,17 @@ icmp_match_in2out_slow (snat_main_t *sm, vlib_node_runtime_t *node,
   if (err != -1)
     {
       b0->error = node->errors[err];
-      next0 = SNAT_IN2OUT_NEXT_DROP;
+      next0 = NAT44_EI_IN2OUT_NEXT_DROP;
       goto out;
     }
 
   init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
-  if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
+  if (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
     {
       if (vnet_buffer (b0)->sw_if_index[VLIB_TX] != ~0)
        {
-         if (PREDICT_FALSE
-             (nat_not_translate_output_feature
-              (sm, ip0, *proto, *port, *port, thread_index, sw_if_index0)))
+         if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
+               nm, ip0, *proto, *port, *port, thread_index, sw_if_index0)))
            {
              *dont_translate = 1;
              goto out;
@@ -490,9 +542,9 @@ icmp_match_in2out_slow (snat_main_t *sm, vlib_node_runtime_t *node,
        }
       else
        {
-         if (PREDICT_FALSE (snat_not_translate (sm, node, sw_if_index0,
-                                                ip0, NAT_PROTOCOL_ICMP,
-                                                *fib_index, thread_index)))
+         if (PREDICT_FALSE (nat44_ei_not_translate (
+               nm, node, sw_if_index0, ip0, NAT_PROTOCOL_ICMP, *fib_index,
+               thread_index)))
            {
              *dont_translate = 1;
              goto out;
@@ -503,16 +555,15 @@ icmp_match_in2out_slow (snat_main_t *sm, vlib_node_runtime_t *node,
          (icmp_type_is_error_message
           (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)))
        {
-         b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
-         next0 = SNAT_IN2OUT_NEXT_DROP;
+         b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
+         next0 = NAT44_EI_IN2OUT_NEXT_DROP;
          goto out;
        }
 
-      next0 =
-       slow_path (sm, b0, ip0, *addr, *port, *fib_index, *proto, &s0, node,
-                  next0, thread_index, vlib_time_now (vm));
+      next0 = slow_path (nm, b0, ip0, *addr, *port, *fib_index, *proto, &s0,
+                        node, next0, thread_index, vlib_time_now (vm));
 
-      if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
+      if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
        goto out;
 
       if (!s0)
@@ -531,12 +582,12 @@ icmp_match_in2out_slow (snat_main_t *sm, vlib_node_runtime_t *node,
           && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
                                           reass.icmp_type_or_tcp_flags)))
        {
-         b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
-         next0 = SNAT_IN2OUT_NEXT_DROP;
+         b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
+         next0 = NAT44_EI_IN2OUT_NEXT_DROP;
          goto out;
        }
 
-      s0 = pool_elt_at_index (tsm->sessions,
+      s0 = pool_elt_at_index (tnm->sessions,
                              nat_value_get_session_index (&value0));
     }
 
@@ -554,26 +605,12 @@ out:
 #endif
 
 #ifndef CLIB_MARCH_VARIANT
-/**
- * Get address and port values to be used for ICMP packet translation
- *
- * @param[in] sm                 NAT main
- * @param[in,out] node           NAT node runtime
- * @param[in] thread_index       thread index
- * @param[in,out] b0             buffer containing packet to be translated
- * @param[in,out] ip0            ip header
- * @param[out] p_proto           protocol used for matching
- * @param[out] p_value           address and port after NAT translation
- * @param[out] p_dont_translate  if packet should not be translated
- * @param d                      optional parameter
- * @param e                      optional parameter
- */
 u32
-icmp_match_in2out_fast (snat_main_t *sm, vlib_node_runtime_t *node,
-                       u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0,
-                       ip4_address_t *addr, u16 *port, u32 *fib_index,
-                       nat_protocol_t *proto, snat_session_t **s0,
-                       u8 *dont_translate)
+nat44_ei_icmp_match_in2out_fast (vlib_node_runtime_t *node, u32 thread_index,
+                                vlib_buffer_t *b0, ip4_header_t *ip0,
+                                ip4_address_t *addr, u16 *port,
+                                u32 *fib_index, nat_protocol_t *proto,
+                                nat44_ei_session_t **s0, u8 *dont_translate)
 {
   u32 sw_if_index0;
   u8 is_addr_only;
@@ -588,7 +625,7 @@ icmp_match_in2out_fast (snat_main_t *sm, vlib_node_runtime_t *node,
   if (err != -1)
     {
       b0->error = node->errors[err];
-      next0 = SNAT_IN2OUT_NEXT_DROP;
+      next0 = NAT44_EI_IN2OUT_NEXT_DROP;
       goto out;
     }
 
@@ -600,9 +637,8 @@ icmp_match_in2out_fast (snat_main_t *sm, vlib_node_runtime_t *node,
                                     &sm_addr, &sm_port, &sm_fib_index, 0,
                                     &is_addr_only, 0))
     {
-      if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
-                                                 IP_PROTOCOL_ICMP,
-                                                 *fib_index)))
+      if (PREDICT_FALSE (nat44_ei_not_translate_fast (
+           node, sw_if_index0, ip0, IP_PROTOCOL_ICMP, *fib_index)))
        {
          *dont_translate = 1;
          goto out;
@@ -611,12 +647,12 @@ icmp_match_in2out_fast (snat_main_t *sm, vlib_node_runtime_t *node,
       if (icmp_type_is_error_message
          (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
        {
-         next0 = SNAT_IN2OUT_NEXT_DROP;
+         next0 = NAT44_EI_IN2OUT_NEXT_DROP;
          goto out;
        }
 
-      b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
-      next0 = SNAT_IN2OUT_NEXT_DROP;
+      b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_NO_TRANSLATION];
+      next0 = NAT44_EI_IN2OUT_NEXT_DROP;
       goto out;
     }
 
@@ -627,8 +663,8 @@ icmp_match_in2out_fast (snat_main_t *sm, vlib_node_runtime_t *node,
        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
                                       reass.icmp_type_or_tcp_flags)))
     {
-      b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE];
-      next0 = SNAT_IN2OUT_NEXT_DROP;
+      b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_BAD_ICMP_TYPE];
+      next0 = NAT44_EI_IN2OUT_NEXT_DROP;
       goto out;
     }
 
@@ -637,23 +673,25 @@ out:
 }
 #endif
 
-u32 icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
-                icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0,
-                vlib_node_runtime_t *node, u32 next0, u32 thread_index,
-                snat_session_t **p_s0);
+u32 nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0,
+                         icmp46_header_t *icmp0, u32 sw_if_index0,
+                         u32 rx_fib_index0, vlib_node_runtime_t *node,
+                         u32 next0, u32 thread_index,
+                         nat44_ei_session_t **p_s0);
 
 #ifndef CLIB_MARCH_VARIANT
 u32
-icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
-            icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0,
-            vlib_node_runtime_t *node, u32 next0, u32 thread_index,
-            snat_session_t **p_s0)
+nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0,
+                     icmp46_header_t *icmp0, u32 sw_if_index0,
+                     u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
+                     u32 thread_index, nat44_ei_session_t **p_s0)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   vlib_main_t *vm = vlib_get_main ();
   ip4_address_t addr;
   u16 port;
   u32 fib_index;
-  nat_protocol_t protocol;
+  nat_protocol_t proto;
   icmp_echo_header_t *echo0, *inner_echo0 = 0;
   ip4_header_t *inner_ip0;
   void *l4_header = 0;
@@ -669,12 +707,22 @@ icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
 
   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
 
-  next0_tmp =
-    sm->icmp_match_in2out_cb (sm, node, thread_index, b0, ip0, &addr, &port,
-                             &fib_index, &protocol, p_s0, &dont_translate);
+  if (PREDICT_TRUE (nm->pat))
+    {
+      next0_tmp = nat44_ei_icmp_match_in2out_slow (
+       node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
+       &dont_translate);
+    }
+  else
+    {
+      next0_tmp = nat44_ei_icmp_match_in2out_fast (
+       node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
+       &dont_translate);
+    }
+
   if (next0_tmp != ~0)
     next0 = next0_tmp;
-  if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate)
+  if (next0 == NAT44_EI_IN2OUT_NEXT_DROP || dont_translate)
     goto out;
 
   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
@@ -688,7 +736,7 @@ icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
       checksum0 = ~ip_csum_fold (sum0);
       if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
        {
-         next0 = SNAT_IN2OUT_NEXT_DROP;
+         next0 = NAT44_EI_IN2OUT_NEXT_DROP;
          goto out;
        }
     }
@@ -729,7 +777,7 @@ icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
 
          if (!ip4_header_checksum_is_valid (inner_ip0))
            {
-             next0 = SNAT_IN2OUT_NEXT_DROP;
+             next0 = NAT44_EI_IN2OUT_NEXT_DROP;
              goto out;
            }
 
@@ -755,7 +803,7 @@ icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
                            checksum);
          icmp0->checksum = ip_csum_fold (sum0);
 
-         switch (protocol)
+         switch (proto)
            {
            case NAT_PROTOCOL_ICMP:
              inner_icmp0 = (icmp46_header_t *) l4_header;
@@ -790,13 +838,13 @@ icmp_in2out (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
 
   if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
     {
-      if (0 != snat_icmp_hairpinning (sm, b0, thread_index, ip0, icmp0,
-                                     &required_thread_index))
+      if (0 != nat44_ei_icmp_hairpinning (nm, b0, thread_index, ip0, icmp0,
+                                         &required_thread_index))
        vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
       if (thread_index != required_thread_index)
        {
          vnet_buffer (b0)->snat.required_thread_index = required_thread_index;
-         next0 = SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
+         next0 = NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
        }
     }
 
@@ -805,48 +853,43 @@ out:
 }
 #endif
 
-static inline u32
-icmp_in2out_slow_path (snat_main_t * sm,
-                      vlib_buffer_t * b0,
-                      ip4_header_t * ip0,
-                      icmp46_header_t * icmp0,
-                      u32 sw_if_index0,
-                      u32 rx_fib_index0,
-                      vlib_node_runtime_t * node,
-                      u32 next0,
-                      f64 now, u32 thread_index, snat_session_t ** p_s0)
+static_always_inline u32
+nat44_ei_icmp_in2out_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
+                               ip4_header_t *ip0, icmp46_header_t *icmp0,
+                               u32 sw_if_index0, u32 rx_fib_index0,
+                               vlib_node_runtime_t *node, u32 next0, f64 now,
+                               u32 thread_index, nat44_ei_session_t **p_s0)
 {
   vlib_main_t *vm = vlib_get_main ();
 
-  next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-                      next0, thread_index, p_s0);
-  snat_session_t *s0 = *p_s0;
-  if (PREDICT_TRUE (next0 != SNAT_IN2OUT_NEXT_DROP && s0))
+  next0 = nat44_ei_icmp_in2out (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
+                               node, next0, thread_index, p_s0);
+  nat44_ei_session_t *s0 = *p_s0;
+  if (PREDICT_TRUE (next0 != NAT44_EI_IN2OUT_NEXT_DROP && s0))
     {
       /* Accounting */
       nat44_ei_session_update_counters (
        s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s0, thread_index);
+      nat44_ei_session_update_lru (nm, s0, thread_index);
     }
   return next0;
 }
 
 static int
-nat_in2out_sm_unknown_proto (snat_main_t * sm,
-                            vlib_buffer_t * b,
-                            ip4_header_t * ip, u32 rx_fib_index)
+nat_in2out_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
+                            ip4_header_t *ip, u32 rx_fib_index)
 {
   clib_bihash_kv_8_8_t kv, value;
-  snat_static_mapping_t *m;
+  nat44_ei_static_mapping_t *m;
   u32 old_addr, new_addr;
   ip_csum_t sum;
 
   init_nat_k (&kv, ip->src_address, 0, rx_fib_index, 0);
-  if (clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
+  if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
     return 1;
 
-  m = pool_elt_at_index (sm->static_mappings, value.value);
+  m = pool_elt_at_index (nm->static_mappings, value.value);
 
   old_addr = ip->src_address.as_u32;
   new_addr = ip->src_address.as_u32 = m->external_addr.as_u32;
@@ -859,20 +902,19 @@ nat_in2out_sm_unknown_proto (snat_main_t * sm,
   if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0)
     {
       vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
-      nat_hairpinning_sm_unknown_proto (sm, b, ip);
+      nat44_ei_hairpinning_sm_unknown_proto (nm, b, ip);
     }
 
   return 0;
 }
 
 static inline uword
-snat_in2out_node_fn_inline (vlib_main_t * vm,
-                           vlib_node_runtime_t * node,
-                           vlib_frame_t * frame, int is_slow_path,
-                           int is_output_feature)
+nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+                               vlib_frame_t *frame, int is_slow_path,
+                               int is_output_feature)
 {
   u32 n_left_from, *from;
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   f64 now = vlib_time_now (vm);
   u32 thread_index = vm->thread_index;
 
@@ -897,7 +939,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       icmp46_header_t *icmp0, *icmp1;
       u32 rx_fib_index0, rx_fib_index1;
       u32 proto0, proto1;
-      snat_session_t *s0 = 0, *s1 = 0;
+      nat44_ei_session_t *s0 = 0, *s1 = 0;
       clib_bihash_kv_8_8_t kv0, value0, kv1, value1;
       u32 iph_offset0 = 0, iph_offset1 = 0;
 
@@ -932,10 +974,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       icmp0 = (icmp46_header_t *) udp0;
 
       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-      rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
-                              sw_if_index0);
+      rx_fib_index0 =
+       vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
 
-      next0 = next1 = SNAT_IN2OUT_NEXT_LOOKUP;
+      next0 = next1 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
 
       if (PREDICT_FALSE (ip0->ttl == 1))
        {
@@ -943,7 +985,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
+         next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
          goto trace00;
        }
 
@@ -954,30 +996,28 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
        {
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
            {
-             if (nat_in2out_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
+             if (nat_in2out_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
                {
-                 next0 = SNAT_IN2OUT_NEXT_DROP;
+                 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
                  b0->error =
-                   node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
+                   node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
                }
-             vlib_increment_simple_counter (is_slow_path ? &sm->
-                                            counters.slowpath.in2out.
-                                            other : &sm->counters.fastpath.
-                                            in2out.other, thread_index,
-                                            sw_if_index0, 1);
+             vlib_increment_simple_counter (
+               is_slow_path ? &nm->counters.slowpath.in2out.other :
+                              &nm->counters.fastpath.in2out.other,
+               thread_index, sw_if_index0, 1);
              goto trace00;
            }
 
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
            {
-             next0 = icmp_in2out_slow_path
-               (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
-                node, next0, now, thread_index, &s0);
-             vlib_increment_simple_counter (is_slow_path ? &sm->
-                                            counters.slowpath.in2out.
-                                            icmp : &sm->counters.fastpath.
-                                            in2out.icmp, thread_index,
-                                            sw_if_index0, 1);
+             next0 = nat44_ei_icmp_in2out_slow_path (
+               nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0,
+               now, thread_index, &s0);
+             vlib_increment_simple_counter (
+               is_slow_path ? &nm->counters.slowpath.in2out.icmp :
+                              &nm->counters.fastpath.in2out.icmp,
+               thread_index, sw_if_index0, 1);
              goto trace00;
            }
        }
@@ -985,13 +1025,13 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
        {
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
            {
-             next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace00;
            }
 
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
            {
-             next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace00;
            }
        }
@@ -999,19 +1039,18 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       init_nat_k (&kv0, ip0->src_address,
                  vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
                  proto0);
-      if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0) !=
+      if (PREDICT_FALSE (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0) !=
                         0))
        {
          if (is_slow_path)
            {
              if (is_output_feature)
                {
-                 if (PREDICT_FALSE
-                     (nat_not_translate_output_feature
-                      (sm, ip0, proto0,
+                 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
+                       nm, ip0, proto0,
                        vnet_buffer (b0)->ip.reass.l4_src_port,
-                       vnet_buffer (b0)->ip.reass.l4_dst_port,
-                       thread_index, sw_if_index0)))
+                       vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
+                       sw_if_index0)))
                    goto trace00;
 
                  /*
@@ -1028,19 +1067,17 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                }
              else
                {
-                 if (PREDICT_FALSE
-                     (snat_not_translate
-                      (sm, node, sw_if_index0, ip0, proto0,
-                       rx_fib_index0, thread_index)))
+                 if (PREDICT_FALSE (nat44_ei_not_translate (
+                       nm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
+                       thread_index)))
                    goto trace00;
                }
 
-             next0 = slow_path (sm, b0, ip0,
-                                ip0->src_address,
+             next0 = slow_path (nm, b0, ip0, ip0->src_address,
                                 vnet_buffer (b0)->ip.reass.l4_src_port,
-                                rx_fib_index0,
-                                proto0, &s0, node, next0, thread_index, now);
-             if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
+                                rx_fib_index0, proto0, &s0, node, next0,
+                                thread_index, now);
+             if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
                goto trace00;
 
              if (PREDICT_FALSE (!s0))
@@ -1048,12 +1085,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
            }
          else
            {
-             next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace00;
            }
        }
       else
-       s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
+       s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
                                nat_value_get_session_index (&value0));
 
       b0->flags |= VNET_BUFFER_F_IS_NATED;
@@ -1083,12 +1120,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
              sum0 = ip_csum_update (sum0, old_port0, new_port0,
                                     ip4_header_t /* cheat */ ,
                                     length /* changed member */ );
-             mss_clamping (sm->mss_clamping, tcp0, &sum0);
+             mss_clamping (nm->mss_clamping, tcp0, &sum0);
              tcp0->checksum = ip_csum_fold (sum0);
            }
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.tcp : &sm->
-                                        counters.fastpath.in2out.tcp,
+         vlib_increment_simple_counter (is_slow_path ?
+                                          &nm->counters.slowpath.in2out.tcp :
+                                          &nm->counters.fastpath.in2out.tcp,
                                         thread_index, sw_if_index0, 1);
        }
       else
@@ -1110,9 +1147,9 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                  udp0->checksum = ip_csum_fold (sum0);
                }
            }
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.udp : &sm->
-                                        counters.fastpath.in2out.udp,
+         vlib_increment_simple_counter (is_slow_path ?
+                                          &nm->counters.slowpath.in2out.udp :
+                                          &nm->counters.fastpath.in2out.udp,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -1120,29 +1157,28 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       nat44_ei_session_update_counters (
        s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s0, thread_index);
+      nat44_ei_session_update_lru (nm, s0, thread_index);
     trace00:
 
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_in2out_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+         nat44_ei_in2out_trace_t *t =
+           vlib_add_trace (vm, node, b0, sizeof (*t));
          t->is_slow_path = is_slow_path;
          t->sw_if_index = sw_if_index0;
          t->next_index = next0;
          t->session_index = ~0;
          if (s0)
-           t->session_index =
-             s0 - sm->per_thread_data[thread_index].sessions;
+           t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
        }
 
-      if (next0 == SNAT_IN2OUT_NEXT_DROP)
+      if (next0 == NAT44_EI_IN2OUT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.
-                                        drops : &sm->counters.fastpath.
-                                        in2out.drops, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (
+           is_slow_path ? &nm->counters.slowpath.in2out.drops :
+                          &nm->counters.fastpath.in2out.drops,
+           thread_index, sw_if_index0, 1);
        }
 
       if (is_output_feature)
@@ -1156,8 +1192,8 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       icmp1 = (icmp46_header_t *) udp1;
 
       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
-      rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
-                              sw_if_index1);
+      rx_fib_index1 =
+       vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
 
       if (PREDICT_FALSE (ip1->ttl == 1))
        {
@@ -1165,7 +1201,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next1 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
+         next1 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
          goto trace01;
        }
 
@@ -1176,30 +1212,28 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
        {
          if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
            {
-             if (nat_in2out_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
+             if (nat_in2out_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
                {
-                 next1 = SNAT_IN2OUT_NEXT_DROP;
+                 next1 = NAT44_EI_IN2OUT_NEXT_DROP;
                  b1->error =
-                   node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
+                   node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
                }
-             vlib_increment_simple_counter (is_slow_path ? &sm->
-                                            counters.slowpath.in2out.
-                                            other : &sm->counters.fastpath.
-                                            in2out.other, thread_index,
-                                            sw_if_index1, 1);
+             vlib_increment_simple_counter (
+               is_slow_path ? &nm->counters.slowpath.in2out.other :
+                              &nm->counters.fastpath.in2out.other,
+               thread_index, sw_if_index1, 1);
              goto trace01;
            }
 
          if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
            {
-             next1 = icmp_in2out_slow_path
-               (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
-                next1, now, thread_index, &s1);
-             vlib_increment_simple_counter (is_slow_path ? &sm->
-                                            counters.slowpath.in2out.
-                                            icmp : &sm->counters.fastpath.
-                                            in2out.icmp, thread_index,
-                                            sw_if_index1, 1);
+             next1 = nat44_ei_icmp_in2out_slow_path (
+               nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1,
+               now, thread_index, &s1);
+             vlib_increment_simple_counter (
+               is_slow_path ? &nm->counters.slowpath.in2out.icmp :
+                              &nm->counters.fastpath.in2out.icmp,
+               thread_index, sw_if_index1, 1);
              goto trace01;
            }
        }
@@ -1207,13 +1241,13 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
        {
          if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
            {
-             next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace01;
            }
 
          if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
            {
-             next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace01;
            }
        }
@@ -1221,19 +1255,18 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       init_nat_k (&kv1, ip1->src_address,
                  vnet_buffer (b1)->ip.reass.l4_src_port, rx_fib_index1,
                  proto1);
-      if (PREDICT_FALSE (clib_bihash_search_8_8 (&sm->in2out, &kv1, &value1) !=
+      if (PREDICT_FALSE (clib_bihash_search_8_8 (&nm->in2out, &kv1, &value1) !=
                         0))
        {
          if (is_slow_path)
            {
              if (is_output_feature)
                {
-                 if (PREDICT_FALSE
-                     (nat_not_translate_output_feature
-                      (sm, ip1, proto1,
+                 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
+                       nm, ip1, proto1,
                        vnet_buffer (b1)->ip.reass.l4_src_port,
-                       vnet_buffer (b1)->ip.reass.l4_dst_port,
-                       thread_index, sw_if_index1)))
+                       vnet_buffer (b1)->ip.reass.l4_dst_port, thread_index,
+                       sw_if_index1)))
                    goto trace01;
 
                  /*
@@ -1250,19 +1283,17 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                }
              else
                {
-                 if (PREDICT_FALSE
-                     (snat_not_translate
-                      (sm, node, sw_if_index1, ip1, proto1,
-                       rx_fib_index1, thread_index)))
+                 if (PREDICT_FALSE (nat44_ei_not_translate (
+                       nm, node, sw_if_index1, ip1, proto1, rx_fib_index1,
+                       thread_index)))
                    goto trace01;
                }
 
-             next1 =
-               slow_path (sm, b1, ip1, ip1->src_address,
-                          vnet_buffer (b1)->ip.reass.l4_src_port,
-                          rx_fib_index1, proto1, &s1, node, next1,
-                          thread_index, now);
-             if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
+             next1 = slow_path (nm, b1, ip1, ip1->src_address,
+                                vnet_buffer (b1)->ip.reass.l4_src_port,
+                                rx_fib_index1, proto1, &s1, node, next1,
+                                thread_index, now);
+             if (PREDICT_FALSE (next1 == NAT44_EI_IN2OUT_NEXT_DROP))
                goto trace01;
 
              if (PREDICT_FALSE (!s1))
@@ -1270,12 +1301,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
            }
          else
            {
-             next1 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next1 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace01;
            }
        }
       else
-       s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
+       s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
                                nat_value_get_session_index (&value1));
 
       b1->flags |= VNET_BUFFER_F_IS_NATED;
@@ -1304,12 +1335,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
              sum1 = ip_csum_update (sum1, old_port1, new_port1,
                                     ip4_header_t /* cheat */ ,
                                     length /* changed member */ );
-             mss_clamping (sm->mss_clamping, tcp1, &sum1);
+             mss_clamping (nm->mss_clamping, tcp1, &sum1);
              tcp1->checksum = ip_csum_fold (sum1);
            }
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.tcp : &sm->
-                                        counters.fastpath.in2out.tcp,
+         vlib_increment_simple_counter (is_slow_path ?
+                                          &nm->counters.slowpath.in2out.tcp :
+                                          &nm->counters.fastpath.in2out.tcp,
                                         thread_index, sw_if_index1, 1);
        }
       else
@@ -1331,9 +1362,9 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                  udp1->checksum = ip_csum_fold (sum1);
                }
            }
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.udp : &sm->
-                                        counters.fastpath.in2out.udp,
+         vlib_increment_simple_counter (is_slow_path ?
+                                          &nm->counters.slowpath.in2out.udp :
+                                          &nm->counters.fastpath.in2out.udp,
                                         thread_index, sw_if_index1, 1);
        }
 
@@ -1341,28 +1372,27 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       nat44_ei_session_update_counters (
        s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s1, thread_index);
+      nat44_ei_session_update_lru (nm, s1, thread_index);
     trace01:
 
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b1->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_in2out_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
+         nat44_ei_in2out_trace_t *t =
+           vlib_add_trace (vm, node, b1, sizeof (*t));
          t->sw_if_index = sw_if_index1;
          t->next_index = next1;
          t->session_index = ~0;
          if (s1)
-           t->session_index =
-             s1 - sm->per_thread_data[thread_index].sessions;
+           t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
        }
 
-      if (next1 == SNAT_IN2OUT_NEXT_DROP)
+      if (next1 == NAT44_EI_IN2OUT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.
-                                        drops : &sm->counters.fastpath.
-                                        in2out.drops, thread_index,
-                                        sw_if_index1, 1);
+         vlib_increment_simple_counter (
+           is_slow_path ? &nm->counters.slowpath.in2out.drops :
+                          &nm->counters.fastpath.in2out.drops,
+           thread_index, sw_if_index1, 1);
        }
 
       n_left_from -= 2;
@@ -1385,13 +1415,13 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       icmp46_header_t *icmp0;
       u32 rx_fib_index0;
       u32 proto0;
-      snat_session_t *s0 = 0;
+      nat44_ei_session_t *s0 = 0;
       clib_bihash_kv_8_8_t kv0, value0;
       u32 iph_offset0 = 0;
 
       b0 = *b;
       b++;
-      next0 = SNAT_IN2OUT_NEXT_LOOKUP;
+      next0 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
 
       if (is_output_feature)
        iph_offset0 = vnet_buffer (b0)->ip.reass.save_rewrite_length;
@@ -1404,8 +1434,8 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       icmp0 = (icmp46_header_t *) udp0;
 
       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-      rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
-                              sw_if_index0);
+      rx_fib_index0 =
+       vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
 
       if (PREDICT_FALSE (ip0->ttl == 1))
        {
@@ -1413,7 +1443,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
+         next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
          goto trace0;
        }
 
@@ -1424,30 +1454,28 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
        {
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
            {
-             if (nat_in2out_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
+             if (nat_in2out_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
                {
-                 next0 = SNAT_IN2OUT_NEXT_DROP;
+                 next0 = NAT44_EI_IN2OUT_NEXT_DROP;
                  b0->error =
-                   node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
+                   node->errors[NAT44_EI_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
                }
-             vlib_increment_simple_counter (is_slow_path ? &sm->
-                                            counters.slowpath.in2out.
-                                            other : &sm->counters.fastpath.
-                                            in2out.other, thread_index,
-                                            sw_if_index0, 1);
+             vlib_increment_simple_counter (
+               is_slow_path ? &nm->counters.slowpath.in2out.other :
+                              &nm->counters.fastpath.in2out.other,
+               thread_index, sw_if_index0, 1);
              goto trace0;
            }
 
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
            {
-             next0 = icmp_in2out_slow_path
-               (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-                next0, now, thread_index, &s0);
-             vlib_increment_simple_counter (is_slow_path ? &sm->
-                                            counters.slowpath.in2out.
-                                            icmp : &sm->counters.fastpath.
-                                            in2out.icmp, thread_index,
-                                            sw_if_index0, 1);
+             next0 = nat44_ei_icmp_in2out_slow_path (
+               nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0,
+               now, thread_index, &s0);
+             vlib_increment_simple_counter (
+               is_slow_path ? &nm->counters.slowpath.in2out.icmp :
+                              &nm->counters.fastpath.in2out.icmp,
+               thread_index, sw_if_index0, 1);
              goto trace0;
            }
        }
@@ -1455,13 +1483,13 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
        {
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
            {
-             next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace0;
            }
 
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
            {
-             next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace0;
            }
        }
@@ -1470,18 +1498,17 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                  vnet_buffer (b0)->ip.reass.l4_src_port, rx_fib_index0,
                  proto0);
 
-      if (clib_bihash_search_8_8 (&sm->in2out, &kv0, &value0))
+      if (clib_bihash_search_8_8 (&nm->in2out, &kv0, &value0))
        {
          if (is_slow_path)
            {
              if (is_output_feature)
                {
-                 if (PREDICT_FALSE
-                     (nat_not_translate_output_feature
-                      (sm, ip0, proto0,
+                 if (PREDICT_FALSE (nat44_ei_not_translate_output_feature (
+                       nm, ip0, proto0,
                        vnet_buffer (b0)->ip.reass.l4_src_port,
-                       vnet_buffer (b0)->ip.reass.l4_dst_port,
-                       thread_index, sw_if_index0)))
+                       vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
+                       sw_if_index0)))
                    goto trace0;
 
                  /*
@@ -1498,20 +1525,18 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                }
              else
                {
-                 if (PREDICT_FALSE
-                     (snat_not_translate
-                      (sm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
+                 if (PREDICT_FALSE (nat44_ei_not_translate (
+                       nm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
                        thread_index)))
                    goto trace0;
                }
 
-             next0 =
-               slow_path (sm, b0, ip0, ip0->src_address,
-                          vnet_buffer (b0)->ip.reass.l4_src_port,
-                          rx_fib_index0, proto0, &s0, node, next0,
-                          thread_index, now);
+             next0 = slow_path (nm, b0, ip0, ip0->src_address,
+                                vnet_buffer (b0)->ip.reass.l4_src_port,
+                                rx_fib_index0, proto0, &s0, node, next0,
+                                thread_index, now);
 
-             if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
+             if (PREDICT_FALSE (next0 == NAT44_EI_IN2OUT_NEXT_DROP))
                goto trace0;
 
              if (PREDICT_FALSE (!s0))
@@ -1519,12 +1544,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
            }
          else
            {
-             next0 = SNAT_IN2OUT_NEXT_SLOW_PATH;
+             next0 = NAT44_EI_IN2OUT_NEXT_SLOW_PATH;
              goto trace0;
            }
        }
       else
-       s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
+       s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
                                nat_value_get_session_index (&value0));
 
       b0->flags |= VNET_BUFFER_F_IS_NATED;
@@ -1554,12 +1579,12 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                ip_csum_update (sum0, old_port0, new_port0,
                                ip4_header_t /* cheat */ ,
                                length /* changed member */ );
-             mss_clamping (sm->mss_clamping, tcp0, &sum0);
+             mss_clamping (nm->mss_clamping, tcp0, &sum0);
              tcp0->checksum = ip_csum_fold (sum0);
            }
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.tcp : &sm->
-                                        counters.fastpath.in2out.tcp,
+         vlib_increment_simple_counter (is_slow_path ?
+                                          &nm->counters.slowpath.in2out.tcp :
+                                          &nm->counters.fastpath.in2out.tcp,
                                         thread_index, sw_if_index0, 1);
        }
       else
@@ -1582,9 +1607,9 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
                  udp0->checksum = ip_csum_fold (sum0);
                }
            }
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.udp : &sm->
-                                        counters.fastpath.in2out.udp,
+         vlib_increment_simple_counter (is_slow_path ?
+                                          &nm->counters.slowpath.in2out.udp :
+                                          &nm->counters.fastpath.in2out.udp,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -1592,29 +1617,28 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
       nat44_ei_session_update_counters (
        s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s0, thread_index);
+      nat44_ei_session_update_lru (nm, s0, thread_index);
 
     trace0:
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_in2out_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+         nat44_ei_in2out_trace_t *t =
+           vlib_add_trace (vm, node, b0, sizeof (*t));
          t->is_slow_path = is_slow_path;
          t->sw_if_index = sw_if_index0;
          t->next_index = next0;
          t->session_index = ~0;
          if (s0)
-           t->session_index =
-             s0 - sm->per_thread_data[thread_index].sessions;
+           t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
        }
 
-      if (next0 == SNAT_IN2OUT_NEXT_DROP)
+      if (next0 == NAT44_EI_IN2OUT_NEXT_DROP)
        {
-         vlib_increment_simple_counter (is_slow_path ? &sm->
-                                        counters.slowpath.in2out.
-                                        drops : &sm->counters.fastpath.
-                                        in2out.drops, thread_index,
-                                        sw_if_index0, 1);
+         vlib_increment_simple_counter (
+           is_slow_path ? &nm->counters.slowpath.in2out.drops :
+                          &nm->counters.fastpath.in2out.drops,
+           thread_index, sw_if_index0, 1);
        }
 
       n_left_from--;
@@ -1627,138 +1651,133 @@ snat_in2out_node_fn_inline (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
-VLIB_NODE_FN (snat_in2out_node) (vlib_main_t * vm,
-                                vlib_node_runtime_t * node,
-                                vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_in2out_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */ ,
-                                    0);
+  return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */,
+                                        0);
 }
 
-VLIB_REGISTER_NODE (snat_in2out_node) = {
-  .name = "nat44-in2out",
+VLIB_REGISTER_NODE (nat44_ei_in2out_node) = {
+  .name = "nat44-ei-in2out",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_trace,
+  .format_trace = format_nat44_ei_in2out_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
-    [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
-    [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
-    [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-    [SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-in2out-hairpinning-handoff-ip4-lookup",
+    [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
+    [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
   },
 };
 
-VLIB_NODE_FN (snat_in2out_output_node) (vlib_main_t * vm,
-                                       vlib_node_runtime_t * node,
-                                       vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_in2out_output_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return snat_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */ ,
-                                    1);
+  return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */,
+                                        1);
 }
 
-VLIB_REGISTER_NODE (snat_in2out_output_node) = {
-  .name = "nat44-in2out-output",
+VLIB_REGISTER_NODE (nat44_ei_in2out_output_node) = {
+  .name = "nat44-ei-in2out-output",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_trace,
+  .format_trace = format_nat44_ei_in2out_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
-    [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
-    [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
-    [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-    [SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-in2out-hairpinning-handoff-interface-output",
+    [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output",
+    [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath",
+    [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output",
   },
 };
 
-VLIB_NODE_FN (snat_in2out_slowpath_node) (vlib_main_t * vm,
-                                         vlib_node_runtime_t * node,
-                                         vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_in2out_slowpath_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */ ,
-                                    0);
+  return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */,
+                                        0);
 }
 
-VLIB_REGISTER_NODE (snat_in2out_slowpath_node) = {
-  .name = "nat44-in2out-slowpath",
+VLIB_REGISTER_NODE (nat44_ei_in2out_slowpath_node) = {
+  .name = "nat44-ei-in2out-slowpath",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_trace,
+  .format_trace = format_nat44_ei_in2out_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
-    [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
-    [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
-    [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-    [SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-in2out-hairpinning-handoff-ip4-lookup",
+    [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
+    [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
   },
 };
 
-VLIB_NODE_FN (snat_in2out_output_slowpath_node) (vlib_main_t * vm,
-                                                vlib_node_runtime_t * node,
-                                                vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_in2out_output_slowpath_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return snat_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */ ,
-                                    1);
+  return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */,
+                                        1);
 }
 
-VLIB_REGISTER_NODE (snat_in2out_output_slowpath_node) = {
-  .name = "nat44-in2out-output-slowpath",
+VLIB_REGISTER_NODE (nat44_ei_in2out_output_slowpath_node) = {
+  .name = "nat44-ei-in2out-output-slowpath",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_trace,
+  .format_trace = format_nat44_ei_in2out_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
-    [SNAT_IN2OUT_NEXT_LOOKUP] = "interface-output",
-    [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-output-slowpath",
-    [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-    [SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-in2out-hairpinning-handoff-interface-output",
+    [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output",
+    [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath",
+    [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output",
   },
 };
 
-VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
-                                     vlib_node_runtime_t * node,
-                                     vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_in2out_fast_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
   u32 n_left_from, *from, *to_next;
   u32 thread_index = vm->thread_index;
-  snat_in2out_next_t next_index;
-  snat_main_t *sm = &snat_main;
+  nat44_ei_in2out_next_t next_index;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   int is_hairpinning = 0;
 
   from = vlib_frame_vector_args (frame);
@@ -1800,7 +1819,7 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
-         next0 = SNAT_IN2OUT_NEXT_LOOKUP;
+         next0 = NAT44_EI_IN2OUT_NEXT_LOOKUP;
 
          ip0 = vlib_buffer_get_current (b0);
          udp0 = ip4_next_header (ip0);
@@ -1817,7 +1836,7 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
              icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
                                           ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                           0);
-             next0 = SNAT_IN2OUT_NEXT_ICMP_ERROR;
+             next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR;
              goto trace0;
            }
 
@@ -1828,8 +1847,8 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
 
          if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
            {
-             next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
-                                  rx_fib_index0, node, next0, ~0, 0);
+             next0 = nat44_ei_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
+                                           rx_fib_index0, node, next0, ~0, 0);
              goto trace0;
            }
 
@@ -1837,8 +1856,8 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
                ip0->src_address, udp0->src_port, rx_fib_index0, proto0,
                &sm0_addr, &sm0_port, &sm0_fib_index, 0, 0, 0))
            {
-             b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
-             next0 = SNAT_IN2OUT_NEXT_DROP;
+             b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_NO_TRANSLATION];
+             next0 = NAT44_EI_IN2OUT_NEXT_DROP;
              goto trace0;
            }
 
@@ -1868,7 +1887,7 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
                  sum0 = ip_csum_update (sum0, old_port0, new_port0,
                                         ip4_header_t /* cheat */ ,
                                         length /* changed member */ );
-                 mss_clamping (sm->mss_clamping, tcp0, &sum0);
+                 mss_clamping (nm->mss_clamping, tcp0, &sum0);
                  tcp0->checksum = ip_csum_fold (sum0);
                }
              else if (udp0->checksum)
@@ -1891,7 +1910,7 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
                  sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
                                         ip4_header_t,
                                         dst_address /* changed member */ );
-                 mss_clamping (sm->mss_clamping, tcp0, &sum0);
+                 mss_clamping (nm->mss_clamping, tcp0, &sum0);
                  tcp0->checksum = ip_csum_fold (sum0);
                }
              else if (udp0->checksum)
@@ -1905,34 +1924,34 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
            }
 
          /* Hairpinning */
-         is_hairpinning = snat_hairpinning (
-           vm, node, sm, thread_index, b0, ip0, udp0, tcp0, proto0,
+         is_hairpinning = nat44_ei_hairpinning (
+           vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0,
            0 /* do_trace */, &required_thread_index);
 
          if (thread_index != required_thread_index)
            {
              vnet_buffer (b0)->snat.required_thread_index =
                required_thread_index;
-             next0 = SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
+             next0 = NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF;
            }
 
        trace0:
          if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                             && (b0->flags & VLIB_BUFFER_IS_TRACED)))
            {
-             snat_in2out_trace_t *t =
+             nat44_ei_in2out_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
              t->sw_if_index = sw_if_index0;
              t->next_index = next0;
              t->is_hairpinning = is_hairpinning;
            }
 
-         if (next0 != SNAT_IN2OUT_NEXT_DROP)
+         if (next0 != NAT44_EI_IN2OUT_NEXT_DROP)
            {
 
-             vlib_increment_simple_counter (&sm->counters.fastpath.
-                                            in2out.other, sw_if_index0,
-                                            vm->thread_index, 1);
+             vlib_increment_simple_counter (
+               &nm->counters.fastpath.in2out.other, sw_if_index0,
+               vm->thread_index, 1);
            }
 
          /* verify speculative enqueue, maybe switch current next frame */
@@ -1947,43 +1966,43 @@ VLIB_NODE_FN (snat_in2out_fast_node) (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
-VLIB_REGISTER_NODE (snat_in2out_fast_node) = {
-  .name = "nat44-in2out-fast",
+VLIB_REGISTER_NODE (nat44_ei_in2out_fast_node) = {
+  .name = "nat44-ei-in2out-fast",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_fast_trace,
+  .format_trace = format_nat44_ei_in2out_fast_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_IN2OUT_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_IN2OUT_NEXT_DROP] = "error-drop",
-    [SNAT_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
-    [SNAT_IN2OUT_NEXT_SLOW_PATH] = "nat44-in2out-slowpath",
-    [SNAT_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
-    [SNAT_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-in2out-hairpinning-handoff-ip4-lookup",
+    [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath",
+    [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
   },
 };
 
-VLIB_NODE_FN (nat44_in2out_hairpinning_handoff_ip4_lookup_node)
+VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node)
 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return nat44_hairpinning_handoff_fn_inline (
+  return nat44_ei_hairpinning_handoff_fn_inline (
     vm, node, frame,
-    snat_main.nat44_in2out_hairpinning_finish_ip4_lookup_node_fq_index);
+    nat44_ei_main.in2out_hairpinning_finish_ip4_lookup_node_fq_index);
 }
 
-VLIB_REGISTER_NODE (nat44_in2out_hairpinning_handoff_ip4_lookup_node) = {
-  .name = "nat44-in2out-hairpinning-handoff-ip4-lookup",
+VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) = {
+  .name = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup",
   .vector_size = sizeof (u32),
-  .n_errors = ARRAY_LEN(nat44_hairpinning_handoff_error_strings),
-  .error_strings = nat44_hairpinning_handoff_error_strings,
-  .format_trace = format_nat44_hairpinning_handoff_trace,
+  .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
+  .error_strings = nat44_ei_hairpinning_handoff_error_strings,
+  .format_trace = format_nat44_ei_hairpinning_handoff_trace,
 
   .n_next_nodes = 1,
 
@@ -1992,20 +2011,20 @@ VLIB_REGISTER_NODE (nat44_in2out_hairpinning_handoff_ip4_lookup_node) = {
   },
 };
 
-VLIB_NODE_FN (nat44_in2out_hairpinning_handoff_interface_output_node)
+VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_interface_output_node)
 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return nat44_hairpinning_handoff_fn_inline (
+  return nat44_ei_hairpinning_handoff_fn_inline (
     vm, node, frame,
-    snat_main.nat44_in2out_hairpinning_finish_interface_output_node_fq_index);
+    nat44_ei_main.in2out_hairpinning_finish_interface_output_node_fq_index);
 }
 
-VLIB_REGISTER_NODE (nat44_in2out_hairpinning_handoff_interface_output_node) = {
-  .name = "nat44-in2out-hairpinning-handoff-interface-output",
+VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_interface_output_node) = {
+  .name = "nat44-ei-in2out-hairpinning-handoff-interface-output",
   .vector_size = sizeof (u32),
-  .n_errors = ARRAY_LEN(nat44_hairpinning_handoff_error_strings),
-  .error_strings = nat44_hairpinning_handoff_error_strings,
-  .format_trace = format_nat44_hairpinning_handoff_trace,
+  .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings),
+  .error_strings = nat44_ei_hairpinning_handoff_error_strings,
+  .format_trace = format_nat44_ei_hairpinning_handoff_trace,
 
   .n_next_nodes = 1,
 
@@ -2015,14 +2034,14 @@ VLIB_REGISTER_NODE (nat44_in2out_hairpinning_handoff_interface_output_node) = {
 };
 
 static_always_inline int
-nat44_in2out_hairpinning_finish_inline (vlib_main_t *vm,
-                                       vlib_node_runtime_t *node,
-                                       vlib_frame_t *frame)
+nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm,
+                                          vlib_node_runtime_t *node,
+                                          vlib_frame_t *frame)
 {
   u32 n_left_from, *from, *to_next;
   u32 thread_index = vm->thread_index;
-  snat_in2out_next_t next_index;
-  snat_main_t *sm = &snat_main;
+  nat44_ei_in2out_next_t next_index;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   int is_hairpinning = 0;
 
   from = vlib_frame_vector_args (frame);
@@ -2057,7 +2076,7 @@ nat44_in2out_hairpinning_finish_inline (vlib_main_t *vm,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
-         next0 = NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP;
+         next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP;
 
          ip0 = vlib_buffer_get_current (b0);
          udp0 = ip4_next_header (ip0);
@@ -2072,41 +2091,41 @@ nat44_in2out_hairpinning_finish_inline (vlib_main_t *vm,
            case NAT_PROTOCOL_TCP:
              // fallthrough
            case NAT_PROTOCOL_UDP:
-             is_hairpinning = snat_hairpinning (
-               vm, node, sm, thread_index, b0, ip0, udp0, tcp0, proto0,
+             is_hairpinning = nat44_ei_hairpinning (
+               vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0,
                0 /* do_trace */, &required_thread_index);
              break;
            case NAT_PROTOCOL_ICMP:
-             is_hairpinning =
-               (0 == snat_icmp_hairpinning (sm, b0, thread_index, ip0, icmp0,
-                                            &required_thread_index));
+             is_hairpinning = (0 == nat44_ei_icmp_hairpinning (
+                                      nm, b0, thread_index, ip0, icmp0,
+                                      &required_thread_index));
              break;
            case NAT_PROTOCOL_OTHER:
              // this should never happen
-             next0 = NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
+             next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
              break;
            }
 
          if (thread_index != required_thread_index)
            {
              // but we already did a handoff ...
-             next0 = NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
+             next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP;
            }
 
          if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
                             (b0->flags & VLIB_BUFFER_IS_TRACED)))
            {
-             snat_in2out_trace_t *t =
+             nat44_ei_in2out_trace_t *t =
                vlib_add_trace (vm, node, b0, sizeof (*t));
              t->sw_if_index = sw_if_index0;
              t->next_index = next0;
              t->is_hairpinning = is_hairpinning;
            }
 
-         if (next0 != NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP)
+         if (next0 != NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP)
            {
              vlib_increment_simple_counter (
-               &sm->counters.fastpath.in2out.other, sw_if_index0,
+               &nm->counters.fastpath.in2out.other, sw_if_index0,
                vm->thread_index, 1);
            }
 
@@ -2121,55 +2140,55 @@ nat44_in2out_hairpinning_finish_inline (vlib_main_t *vm,
   return frame->n_vectors;
 }
 
-VLIB_NODE_FN (nat44_in2out_hairpinning_finish_ip4_lookup_node)
+VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node)
 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return nat44_in2out_hairpinning_finish_inline (vm, node, frame);
+  return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame);
 }
 
-VLIB_REGISTER_NODE (nat44_in2out_hairpinning_finish_ip4_lookup_node) = {
-  .name = "nat44-in2out-hairpinning-finish-ip4-lookup",
+VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node) = {
+  .name = "nat44-ei-in2out-hairpinning-finish-ip4-lookup",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_fast_trace,
+  .format_trace = format_nat44_ei_in2out_fast_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = NAT44_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
-    [NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "ip4-lookup",
   },
 };
 
-VLIB_NODE_FN (nat44_in2out_hairpinning_finish_interface_output_node)
+VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_interface_output_node)
 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
-  return nat44_in2out_hairpinning_finish_inline (vm, node, frame);
+  return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame);
 }
 
-VLIB_REGISTER_NODE (nat44_in2out_hairpinning_finish_interface_output_node) = {
-  .name = "nat44-in2out-hairpinning-finish-interface-output",
+VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_interface_output_node) = {
+  .name = "nat44-ei-in2out-hairpinning-finish-interface-output",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_in2out_fast_trace,
+  .format_trace = format_nat44_ei_in2out_fast_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_in2out_error_strings),
-  .error_strings = snat_in2out_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings),
+  .error_strings = nat44_ei_in2out_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = NAT44_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
+  .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
-    [NAT44_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "interface-output",
+    [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop",
+    [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "interface-output",
   },
 };
 
index f7089ea..3093588 100644 (file)
 #ifndef __included_nat44_ei_inlines_h__
 #define __included_nat44_ei_inlines_h__
 
+#include <vppinfra/clib.h>
+
+#include <nat/nat44-ei/nat44_ei.h>
 #include <nat/nat44-ei/nat44_ei_ha.h>
 
+always_inline u64
+calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto)
+{
+  ASSERT (fib_index <= (1 << 14) - 1);
+  ASSERT (proto <= (1 << 3) - 1);
+  return (u64) addr.as_u32 << 32 | (u64) port << 16 | fib_index << 3 |
+        (proto & 0x7);
+}
+
+always_inline void
+split_nat_key (u64 key, ip4_address_t *addr, u16 *port, u32 *fib_index,
+              nat_protocol_t *proto)
+{
+  if (addr)
+    {
+      addr->as_u32 = key >> 32;
+    }
+  if (port)
+    {
+      *port = (key >> 16) & (u16) ~0;
+    }
+  if (fib_index)
+    {
+      *fib_index = key >> 3 & ((1 << 13) - 1);
+    }
+  if (proto)
+    {
+      *proto = key & 0x7;
+    }
+}
+
+always_inline void
+init_nat_k (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port,
+           u32 fib_index, nat_protocol_t proto)
+{
+  kv->key = calc_nat_key (addr, port, fib_index, proto);
+  kv->value = ~0ULL;
+}
+
+always_inline void
+init_nat_kv (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port,
+            u32 fib_index, nat_protocol_t proto, u32 thread_index,
+            u32 session_index)
+{
+  init_nat_k (kv, addr, port, fib_index, proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline void
+init_nat_i2o_k (clib_bihash_kv_8_8_t *kv, nat44_ei_session_t *s)
+{
+  return init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
+                    s->nat_proto);
+}
+
+always_inline void
+init_nat_i2o_kv (clib_bihash_kv_8_8_t *kv, nat44_ei_session_t *s,
+                u32 thread_index, u32 session_index)
+{
+  init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
+             s->nat_proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline void
+init_nat_o2i_k (clib_bihash_kv_8_8_t *kv, nat44_ei_session_t *s)
+{
+  return init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
+                    s->nat_proto);
+}
+
+always_inline void
+init_nat_o2i_kv (clib_bihash_kv_8_8_t *kv, nat44_ei_session_t *s,
+                u32 thread_index, u32 session_index)
+{
+  init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
+             s->nat_proto);
+  kv->value = (u64) thread_index << 32 | session_index;
+}
+
+always_inline u32
+nat_value_get_thread_index (clib_bihash_kv_8_8_t *value)
+{
+  return value->value >> 32;
+}
+
+always_inline u32
+nat_value_get_session_index (clib_bihash_kv_8_8_t *value)
+{
+  return value->value & ~(u32) 0;
+}
+
+always_inline u8
+nat44_ei_is_interface_addr (ip4_main_t *im, vlib_node_runtime_t *node,
+                           u32 sw_if_index0, u32 ip4_addr)
+{
+  nat44_ei_runtime_t *rt = (nat44_ei_runtime_t *) node->runtime_data;
+  ip4_address_t *first_int_addr;
+
+  if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
+    {
+      first_int_addr = ip4_interface_first_address (
+       im, sw_if_index0, 0 /* just want the address */);
+      rt->cached_sw_if_index = sw_if_index0;
+      if (first_int_addr)
+       rt->cached_ip4_address = first_int_addr->as_u32;
+      else
+       rt->cached_ip4_address = 0;
+    }
+
+  if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
+    return 1;
+  else
+    return 0;
+}
+
+/** \brief Per-user LRU list maintenance */
+always_inline void
+nat44_ei_session_update_lru (nat44_ei_main_t *nm, nat44_ei_session_t *s,
+                            u32 thread_index)
+{
+  /* don't update too often - timeout is in magnitude of seconds anyway */
+  if (s->last_heard > s->last_lru_update + 1)
+    {
+      clib_dlist_remove (nm->per_thread_data[thread_index].list_pool,
+                        s->per_user_index);
+      clib_dlist_addtail (nm->per_thread_data[thread_index].list_pool,
+                         s->per_user_list_head_index, s->per_user_index);
+      s->last_lru_update = s->last_heard;
+    }
+}
+
+always_inline void
+nat44_ei_user_session_increment (nat44_ei_main_t *nm, nat44_ei_user_t *u,
+                                u8 is_static)
+{
+  if (u->nsessions + u->nstaticsessions < nm->max_translations_per_user)
+    {
+      if (is_static)
+       u->nstaticsessions++;
+      else
+       u->nsessions++;
+    }
+}
+
+always_inline void
+nat44_ei_delete_user_with_no_session (nat44_ei_main_t *nm, nat44_ei_user_t *u,
+                                     u32 thread_index)
+{
+  clib_bihash_kv_8_8_t kv;
+  nat44_ei_user_key_t u_key;
+  nat44_ei_main_per_thread_data_t *tnm =
+    vec_elt_at_index (nm->per_thread_data, thread_index);
+
+  if (u->nstaticsessions == 0 && u->nsessions == 0)
+    {
+      u_key.addr.as_u32 = u->addr.as_u32;
+      u_key.fib_index = u->fib_index;
+      kv.key = u_key.as_u64;
+      pool_put_index (tnm->list_pool, u->sessions_per_user_list_head_index);
+      pool_put (tnm->users, u);
+      clib_bihash_add_del_8_8 (&tnm->user_hash, &kv, 0);
+      vlib_set_simple_counter (&nm->total_users, thread_index, 0,
+                              pool_elts (tnm->users));
+    }
+}
+
 static_always_inline u8
-nat44_ei_maximum_sessions_exceeded (snat_main_t *sm, u32 thread_index)
+nat44_ei_maximum_sessions_exceeded (nat44_ei_main_t *nm, u32 thread_index)
 {
-  if (pool_elts (sm->per_thread_data[thread_index].sessions) >=
-      sm->max_translations_per_thread)
+  if (pool_elts (nm->per_thread_data[thread_index].sessions) >=
+      nm->max_translations_per_thread)
     return 1;
   return 0;
 }
 
 always_inline void
-nat44_ei_session_update_counters (snat_session_t *s, f64 now, uword bytes,
+nat44_ei_session_update_counters (nat44_ei_session_t *s, f64 now, uword bytes,
                                  u32 thread_index)
 {
   s->last_heard = now;
index ca3c272..1d5ebd3 100644 (file)
  */
 /**
  * @file
- * @brief NAT44 endpoint-dependent outside to inside network translation
+ * @brief NAT44 EI outside to inside network translation
  */
 
 #include <vlib/vlib.h>
-#include <vnet/vnet.h>
 
+#include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
-#include <vnet/udp/udp_local.h>
 #include <vnet/ethernet/ethernet.h>
+#include <vnet/udp/udp_local.h>
 #include <vnet/fib/ip4_fib.h>
-#include <nat/nat.h>
-#include <nat/lib/ipfix_logging.h>
-#include <nat/nat_inlines.h>
-#include <nat/lib/nat_syslog.h>
-#include <nat/nat44-ei/nat44_ei_inlines.h>
-#include <nat/nat44-ei/nat44_ei.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
-#include <vppinfra/elog.h>
+
+#include <nat/lib/log.h>
+#include <nat/lib/nat_syslog.h>
+#include <nat/lib/ipfix_logging.h>
+#include <nat/nat44-ei/nat44_ei_inlines.h>
+#include <nat/nat44-ei/nat44_ei.h>
 
 typedef struct
 {
   u32 sw_if_index;
   u32 next_index;
   u32 session_index;
-} snat_out2in_trace_t;
+} nat44_ei_out2in_trace_t;
 
 /* packet trace format function */
 static u8 *
-format_snat_out2in_trace (u8 * s, va_list * args)
+format_nat44_ei_out2in_trace (u8 *s, va_list *args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
+  nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
 
   s =
     format (s,
@@ -58,66 +57,67 @@ format_snat_out2in_trace (u8 * s, va_list * args)
 }
 
 static u8 *
-format_snat_out2in_fast_trace (u8 * s, va_list * args)
+format_nat44_ei_out2in_fast_trace (u8 *s, va_list *args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  snat_out2in_trace_t *t = va_arg (*args, snat_out2in_trace_t *);
+  nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
 
   s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d",
              t->sw_if_index, t->next_index);
   return s;
 }
 
-#define foreach_snat_out2in_error                       \
-_(UNSUPPORTED_PROTOCOL, "unsupported protocol")         \
-_(OUT_OF_PORTS, "out of ports")                         \
-_(BAD_ICMP_TYPE, "unsupported ICMP type")               \
-_(NO_TRANSLATION, "no translation")                     \
-_(MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")   \
-_(CANNOT_CREATE_USER, "cannot create NAT user")
+#define foreach_nat44_ei_out2in_error                                         \
+  _ (UNSUPPORTED_PROTOCOL, "unsupported protocol")                            \
+  _ (OUT_OF_PORTS, "out of ports")                                            \
+  _ (BAD_ICMP_TYPE, "unsupported ICMP type")                                  \
+  _ (NO_TRANSLATION, "no translation")                                        \
+  _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded")                      \
+  _ (CANNOT_CREATE_USER, "cannot create NAT user")
 
 typedef enum
 {
-#define _(sym,str) SNAT_OUT2IN_ERROR_##sym,
-  foreach_snat_out2in_error
+#define _(sym, str) NAT44_EI_OUT2IN_ERROR_##sym,
+  foreach_nat44_ei_out2in_error
 #undef _
-    SNAT_OUT2IN_N_ERROR,
-} snat_out2in_error_t;
+    NAT44_EI_OUT2IN_N_ERROR,
+} nat44_ei_out2in_error_t;
 
-static char *snat_out2in_error_strings[] = {
+static char *nat44_ei_out2in_error_strings[] = {
 #define _(sym,string) string,
-  foreach_snat_out2in_error
+  foreach_nat44_ei_out2in_error
 #undef _
 };
 
 typedef enum
 {
-  SNAT_OUT2IN_NEXT_DROP,
-  SNAT_OUT2IN_NEXT_LOOKUP,
-  SNAT_OUT2IN_NEXT_ICMP_ERROR,
-  SNAT_OUT2IN_N_NEXT,
-} snat_out2in_next_t;
+  NAT44_EI_OUT2IN_NEXT_DROP,
+  NAT44_EI_OUT2IN_NEXT_LOOKUP,
+  NAT44_EI_OUT2IN_NEXT_ICMP_ERROR,
+  NAT44_EI_OUT2IN_N_NEXT,
+} nat44_ei_out2in_next_t;
 
 #ifndef CLIB_MARCH_VARIANT
 int
 nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
 {
-  snat_main_t *sm = &snat_main;
-  nat44_is_idle_session_ctx_t *ctx = arg;
-  snat_session_t *s;
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_is_idle_session_ctx_t *ctx = arg;
+  nat44_ei_session_t *s;
   u64 sess_timeout_time;
-  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
-                                                      ctx->thread_index);
+  nat44_ei_main_per_thread_data_t *tnm =
+    vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
   clib_bihash_kv_8_8_t s_kv;
 
-  s = pool_elt_at_index (tsm->sessions, kv->value);
-  sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
+  s = pool_elt_at_index (tnm->sessions, kv->value);
+  sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
+                                       &nm->timeouts, s->nat_proto, s->state);
   if (ctx->now >= sess_timeout_time)
     {
       init_nat_i2o_k (&s_kv, s);
-      if (clib_bihash_add_del_8_8 (&sm->in2out, &s_kv, 0))
-       nat_elog_warn ("out2in key del failed");
+      if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0))
+       nat_elog_warn (nm, "out2in key del failed");
 
       nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
                                          s->in2out.addr.as_u32,
@@ -135,12 +135,12 @@ nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
                   s->ext_host_port, s->nat_proto, s->out2in.fib_index,
                   ctx->thread_index);
 
-      if (!snat_is_session_static (s))
-       snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
-                                           &s->out2in.addr, s->out2in.port,
-                                           s->nat_proto);
+      if (!nat44_ei_is_session_static (s))
+       nat44_ei_free_outside_address_and_port (
+         nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
+         s->nat_proto);
 
-      nat44_delete_session (sm, s, ctx->thread_index);
+      nat44_ei_delete_session (nm, s, ctx->thread_index);
       return 1;
     }
 
@@ -154,63 +154,56 @@ nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
  * Create NAT session initiated by host from external network with static
  * mapping.
  *
- * @param sm     NAT main.
+ * @param nm     NAT main.
  * @param b0     Vlib buffer.
  * @param in2out In2out NAT44 session key.
  * @param out2in Out2in NAT44 session key.
  * @param node   Vlib node.
  *
- * @returns SNAT session if successfully created otherwise 0.
+ * @returns NAT44_EI session if successfully created otherwise 0.
  */
-static inline snat_session_t *
-create_session_for_static_mapping (snat_main_t * sm,
-                                  vlib_buffer_t * b0,
-                                  ip4_address_t i2o_addr,
-                                  u16 i2o_port,
-                                  u32 i2o_fib_index,
-                                  ip4_address_t o2i_addr,
-                                  u16 o2i_port,
-                                  u32 o2i_fib_index,
-                                  nat_protocol_t proto,
-                                  vlib_node_runtime_t * node,
-                                  u32 thread_index, f64 now)
+static inline nat44_ei_session_t *
+create_session_for_static_mapping (
+  nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_address_t i2o_addr, u16 i2o_port,
+  u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
+  nat_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, f64 now)
 {
-  snat_user_t *u;
-  snat_session_t *s;
+  nat44_ei_user_t *u;
+  nat44_ei_session_t *s;
   clib_bihash_kv_8_8_t kv0;
   ip4_header_t *ip0;
   udp_header_t *udp0;
-  nat44_is_idle_session_ctx_t ctx0;
+  nat44_ei_is_idle_session_ctx_t ctx0;
 
-  if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (sm, thread_index)))
+  if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
     {
-      b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
-      nat_elog_notice ("maximum sessions exceeded");
+      b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
+      nat_elog_notice (nm, "maximum sessions exceeded");
       return 0;
     }
 
   ip0 = vlib_buffer_get_current (b0);
   udp0 = ip4_next_header (ip0);
 
-  u = nat_user_get_or_create (sm, &i2o_addr, i2o_fib_index, thread_index);
+  u = nat44_ei_user_get_or_create (nm, &i2o_addr, i2o_fib_index, thread_index);
   if (!u)
     {
-      b0->error = node->errors[SNAT_OUT2IN_ERROR_CANNOT_CREATE_USER];
+      b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_CANNOT_CREATE_USER];
       return 0;
     }
 
-  s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
+  s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
   if (!s)
     {
-      nat44_delete_user_with_no_session (sm, u, thread_index);
-      nat_elog_warn ("create NAT session failed");
+      nat44_ei_delete_user_with_no_session (nm, u, thread_index);
+      nat_elog_warn (nm, "create NAT session failed");
       return 0;
     }
 
-  s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
+  s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
   s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
   s->ext_host_port = udp0->src_port;
-  user_session_increment (sm, u, 1 /* static */ );
+  nat44_ei_user_session_increment (nm, u, 1 /* static */);
   s->in2out.addr = i2o_addr;
   s->in2out.port = i2o_port;
   s->in2out.fib_index = i2o_fib_index;
@@ -223,16 +216,16 @@ create_session_for_static_mapping (snat_main_t * sm,
   ctx0.now = now;
   ctx0.thread_index = thread_index;
   init_nat_i2o_kv (&kv0, s, thread_index,
-                  s - sm->per_thread_data[thread_index].sessions);
+                  s - nm->per_thread_data[thread_index].sessions);
   if (clib_bihash_add_or_overwrite_stale_8_8 (
-       &sm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
-    nat_elog_notice ("in2out key add failed");
+       &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
+    nat_elog_notice (nm, "in2out key add failed");
 
   init_nat_o2i_kv (&kv0, s, thread_index,
-                  s - sm->per_thread_data[thread_index].sessions);
+                  s - nm->per_thread_data[thread_index].sessions);
   if (clib_bihash_add_or_overwrite_stale_8_8 (
-       &sm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
-    nat_elog_notice ("out2in key add failed");
+       &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
+    nat_elog_notice (nm, "out2in key add failed");
 
   /* log NAT event */
   nat_ipfix_logging_nat44_ses_create (thread_index,
@@ -255,9 +248,9 @@ create_session_for_static_mapping (snat_main_t * sm,
 }
 
 #ifndef CLIB_MARCH_VARIANT
-static_always_inline snat_out2in_error_t
-icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
-             ip4_address_t * addr, u16 * port, nat_protocol_t * nat_proto)
+static_always_inline nat44_ei_out2in_error_t
+icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
+             u16 *port, nat_protocol_t *nat_proto)
 {
   icmp46_header_t *icmp0;
   icmp_echo_header_t *echo0, *inner_echo0 = 0;
@@ -293,7 +286,7 @@ icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
          *port = ((tcp_udp_header_t *) l4_header)->src_port;
          break;
        default:
-         return SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
+         return NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
        }
     }
   return -1;                   /* success */
@@ -303,7 +296,7 @@ icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
  * Get address and port values to be used for ICMP packet translation
  * and create session if needed
  *
- * @param[in,out] sm             NAT main
+ * @param[in,out] nm             NAT main
  * @param[in,out] node           NAT node runtime
  * @param[in] thread_index       thread index
  * @param[in,out] b0             buffer containing packet to be translated
@@ -315,15 +308,16 @@ icmp_get_key (vlib_buffer_t * b, ip4_header_t * ip0,
  * @param e                      optional parameter
  */
 u32
-icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
-                       u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0,
-                       ip4_address_t *addr, u16 *port, u32 *fib_index,
-                       nat_protocol_t *proto, snat_session_t **p_s0,
-                       u8 *dont_translate)
+nat44_ei_icmp_match_out2in_slow (vlib_node_runtime_t *node, u32 thread_index,
+                                vlib_buffer_t *b0, ip4_header_t *ip0,
+                                ip4_address_t *addr, u16 *port,
+                                u32 *fib_index, nat_protocol_t *proto,
+                                nat44_ei_session_t **p_s0, u8 *dont_translate)
 {
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
   u32 sw_if_index0;
-  snat_session_t *s0 = 0;
+  nat44_ei_session_t *s0 = 0;
   clib_bihash_kv_8_8_t kv0, value0;
   u8 is_addr_only;
   u32 next0 = ~0;
@@ -340,8 +334,8 @@ icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
   err = icmp_get_key (b0, ip0, addr, port, proto);
   if (err != -1)
     {
-      b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
-      next0 = SNAT_OUT2IN_NEXT_DROP;
+      b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
+      next0 = NAT44_EI_OUT2IN_NEXT_DROP;
       goto out;
     }
 
@@ -350,7 +344,7 @@ icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
   u32 mapping_fib_index;
 
   init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
-  if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
+  if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
     {
       /* Try to match static mapping by external address and port,
          destination address and port in packet */
@@ -358,17 +352,18 @@ icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
            *addr, *port, *fib_index, *proto, &mapping_addr, &mapping_port,
            &mapping_fib_index, 1, &is_addr_only, &identity_nat))
        {
-         if (!sm->forwarding_enabled)
+         if (!nm->forwarding_enabled)
            {
              /* Don't NAT packet aimed at the intfc address */
-             if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
-                                                   ip0->dst_address.as_u32)))
+             if (PREDICT_FALSE (nat44_ei_is_interface_addr (
+                   nm->ip4_main, node, sw_if_index0,
+                   ip0->dst_address.as_u32)))
                {
                  *dont_translate = 1;
                  goto out;
                }
-             b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
-             next0 = SNAT_OUT2IN_NEXT_DROP;
+             b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
+             next0 = NAT44_EI_OUT2IN_NEXT_DROP;
              goto out;
            }
          else
@@ -384,8 +379,8 @@ icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
           && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
               ICMP4_echo_request || !is_addr_only)))
        {
-         b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
-         next0 = SNAT_OUT2IN_NEXT_DROP;
+         b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
+         next0 = NAT44_EI_OUT2IN_NEXT_DROP;
          goto out;
        }
 
@@ -395,15 +390,13 @@ icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
          goto out;
        }
       /* Create session initiated by host from external network */
-      s0 =
-       create_session_for_static_mapping (sm, b0, mapping_addr, mapping_port,
-                                          mapping_fib_index, *addr, *port,
-                                          *fib_index, *proto, node,
-                                          thread_index, vlib_time_now (vm));
+      s0 = create_session_for_static_mapping (
+       nm, b0, mapping_addr, mapping_port, mapping_fib_index, *addr, *port,
+       *fib_index, *proto, node, thread_index, vlib_time_now (vm));
 
       if (!s0)
        {
-         next0 = SNAT_OUT2IN_NEXT_DROP;
+         next0 = NAT44_EI_OUT2IN_NEXT_DROP;
          goto out;
        }
     }
@@ -417,12 +410,12 @@ icmp_match_out2in_slow (snat_main_t *sm, vlib_node_runtime_t *node,
           && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
                                           reass.icmp_type_or_tcp_flags)))
        {
-         b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
-         next0 = SNAT_OUT2IN_NEXT_DROP;
+         b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
+         next0 = NAT44_EI_OUT2IN_NEXT_DROP;
          goto out;
        }
 
-      s0 = pool_elt_at_index (tsm->sessions,
+      s0 = pool_elt_at_index (tnm->sessions,
                              nat_value_get_session_index (&value0));
     }
 
@@ -440,27 +433,15 @@ out:
 #endif
 
 #ifndef CLIB_MARCH_VARIANT
-/**
- * Get address and port values to be used for ICMP packet translation
- *
- * @param[in] sm                 NAT main
- * @param[in,out] node           NAT node runtime
- * @param[in] thread_index       thread index
- * @param[in,out] b0             buffer containing packet to be translated
- * @param[in,out] ip0            ip header
- * @param[out] p_proto           protocol used for matching
- * @param[out] p_value           address and port after NAT translation
- * @param[out] p_dont_translate  if packet should not be translated
- * @param d                      optional parameter
- * @param e                      optional parameter
- */
 u32
-icmp_match_out2in_fast (snat_main_t *sm, vlib_node_runtime_t *node,
-                       u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0,
-                       ip4_address_t *mapping_addr, u16 *mapping_port,
-                       u32 *mapping_fib_index, nat_protocol_t *proto,
-                       snat_session_t **p_s0, u8 *dont_translate)
+nat44_ei_icmp_match_out2in_fast (vlib_node_runtime_t *node, u32 thread_index,
+                                vlib_buffer_t *b0, ip4_header_t *ip0,
+                                ip4_address_t *mapping_addr,
+                                u16 *mapping_port, u32 *mapping_fib_index,
+                                nat_protocol_t *proto,
+                                nat44_ei_session_t **p_s0, u8 *dont_translate)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   u32 sw_if_index0;
   u32 rx_fib_index0;
   u8 is_addr_only;
@@ -477,7 +458,7 @@ icmp_match_out2in_fast (snat_main_t *sm, vlib_node_runtime_t *node,
   if (err != -1)
     {
       b0->error = node->errors[err];
-      next0 = SNAT_OUT2IN_NEXT_DROP;
+      next0 = NAT44_EI_OUT2IN_NEXT_DROP;
       goto out;
     }
   if (nat44_ei_static_mapping_match (addr, port, rx_fib_index0, *proto,
@@ -485,13 +466,14 @@ icmp_match_out2in_fast (snat_main_t *sm, vlib_node_runtime_t *node,
                                     mapping_fib_index, 1, &is_addr_only, 0))
     {
       /* Don't NAT packet aimed at the intfc address */
-      if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
+      if (nat44_ei_is_interface_addr (nm->ip4_main, node, sw_if_index0,
+                                     ip0->dst_address.as_u32))
        {
          *dont_translate = 1;
          goto out;
        }
-      b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
-      next0 = SNAT_OUT2IN_NEXT_DROP;
+      b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
+      next0 = NAT44_EI_OUT2IN_NEXT_DROP;
       goto out;
     }
 
@@ -502,8 +484,8 @@ icmp_match_out2in_fast (snat_main_t *sm, vlib_node_runtime_t *node,
        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
                                       reass.icmp_type_or_tcp_flags)))
     {
-      b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE];
-      next0 = SNAT_OUT2IN_NEXT_DROP;
+      b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
+      next0 = NAT44_EI_OUT2IN_NEXT_DROP;
       goto out;
     }
 
@@ -512,18 +494,20 @@ out:
 }
 #endif
 
-u32 icmp_out2in (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
-                icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0,
-                vlib_node_runtime_t *node, u32 next0, u32 thread_index,
-                snat_session_t **p_s0);
+u32 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
+                         icmp46_header_t *icmp0, u32 sw_if_index0,
+                         u32 rx_fib_index0, vlib_node_runtime_t *node,
+                         u32 next0, u32 thread_index,
+                         nat44_ei_session_t **p_s0);
 
 #ifndef CLIB_MARCH_VARIANT
 u32
-icmp_out2in (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
-            icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0,
-            vlib_node_runtime_t *node, u32 next0, u32 thread_index,
-            snat_session_t **p_s0)
+nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
+                     icmp46_header_t *icmp0, u32 sw_if_index0,
+                     u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
+                     u32 thread_index, nat44_ei_session_t **p_s0)
 {
+  nat44_ei_main_t *nm = &nat44_ei_main;
   icmp_echo_header_t *echo0, *inner_echo0 = 0;
   ip4_header_t *inner_ip0 = 0;
   void *l4_header = 0;
@@ -542,12 +526,22 @@ icmp_out2in (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
 
   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
 
-  next0_tmp =
-    sm->icmp_match_out2in_cb (sm, node, thread_index, b0, ip0, &addr, &port,
-                             &fib_index, &proto, p_s0, &dont_translate);
+  if (PREDICT_TRUE (nm->pat))
+    {
+      next0_tmp = nat44_ei_icmp_match_out2in_slow (
+       node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
+       &dont_translate);
+    }
+  else
+    {
+      next0_tmp = nat44_ei_icmp_match_out2in_fast (
+       node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
+       &dont_translate);
+    }
+
   if (next0_tmp != ~0)
     next0 = next0_tmp;
-  if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate)
+  if (next0 == NAT44_EI_OUT2IN_NEXT_DROP || dont_translate)
     goto out;
 
   if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
@@ -561,7 +555,7 @@ icmp_out2in (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
       checksum0 = ~ip_csum_fold (sum0);
       if (checksum0 != 0 && checksum0 != 0xffff)
        {
-         next0 = SNAT_OUT2IN_NEXT_DROP;
+         next0 = NAT44_EI_OUT2IN_NEXT_DROP;
          goto out;
        }
     }
@@ -604,7 +598,7 @@ icmp_out2in (snat_main_t *sm, vlib_buffer_t *b0, ip4_header_t *ip0,
 
          if (!ip4_header_checksum_is_valid (inner_ip0))
            {
-             next0 = SNAT_OUT2IN_NEXT_DROP;
+             next0 = NAT44_EI_OUT2IN_NEXT_DROP;
              goto out;
            }
 
@@ -656,47 +650,42 @@ out:
 #endif
 
 static inline u32
-icmp_out2in_slow_path (snat_main_t * sm,
-                      vlib_buffer_t * b0,
-                      ip4_header_t * ip0,
-                      icmp46_header_t * icmp0,
-                      u32 sw_if_index0,
-                      u32 rx_fib_index0,
-                      vlib_node_runtime_t * node,
-                      u32 next0, f64 now,
-                      u32 thread_index, snat_session_t ** p_s0)
+nat44_ei_icmp_out2in_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
+                               ip4_header_t *ip0, icmp46_header_t *icmp0,
+                               u32 sw_if_index0, u32 rx_fib_index0,
+                               vlib_node_runtime_t *node, u32 next0, f64 now,
+                               u32 thread_index, nat44_ei_session_t **p_s0)
 {
   vlib_main_t *vm = vlib_get_main ();
 
-  next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-                      next0, thread_index, p_s0);
-  snat_session_t *s0 = *p_s0;
-  if (PREDICT_TRUE (next0 != SNAT_OUT2IN_NEXT_DROP && s0))
+  next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
+                               node, next0, thread_index, p_s0);
+  nat44_ei_session_t *s0 = *p_s0;
+  if (PREDICT_TRUE (next0 != NAT44_EI_OUT2IN_NEXT_DROP && s0))
     {
       /* Accounting */
       nat44_ei_session_update_counters (
        s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s0, thread_index);
+      nat44_ei_session_update_lru (nm, s0, thread_index);
     }
   return next0;
 }
 
 static int
-nat_out2in_sm_unknown_proto (snat_main_t * sm,
-                            vlib_buffer_t * b,
-                            ip4_header_t * ip, u32 rx_fib_index)
+nat_out2in_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
+                            ip4_header_t *ip, u32 rx_fib_index)
 {
   clib_bihash_kv_8_8_t kv, value;
-  snat_static_mapping_t *m;
+  nat44_ei_static_mapping_t *m;
   u32 old_addr, new_addr;
   ip_csum_t sum;
 
   init_nat_k (&kv, ip->dst_address, 0, 0, 0);
-  if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
+  if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
     return 1;
 
-  m = pool_elt_at_index (sm->static_mappings, value.value);
+  m = pool_elt_at_index (nm->static_mappings, value.value);
 
   old_addr = ip->dst_address.as_u32;
   new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
@@ -708,15 +697,14 @@ nat_out2in_sm_unknown_proto (snat_main_t * sm,
   return 0;
 }
 
-VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
-                                vlib_node_runtime_t * node,
-                                vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_out2in_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
   u32 n_left_from, *from;
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
   f64 now = vlib_time_now (vm);
   u32 thread_index = vm->thread_index;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+  nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -728,8 +716,8 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
   while (n_left_from >= 2)
     {
       vlib_buffer_t *b0, *b1;
-      u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
-      u32 next1 = SNAT_OUT2IN_NEXT_LOOKUP;
+      u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
+      u32 next1 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
       u32 sw_if_index0, sw_if_index1;
       ip4_header_t *ip0, *ip1;
       ip_csum_t sum0, sum1;
@@ -742,7 +730,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       icmp46_header_t *icmp0, *icmp1;
       u32 rx_fib_index0, rx_fib_index1;
       u32 proto0, proto1;
-      snat_session_t *s0 = 0, *s1 = 0;
+      nat44_ei_session_t *s0 = 0, *s1 = 0;
       clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
       u8 identity_nat0, identity_nat1;
       ip4_address_t sm_addr0, sm_addr1;
@@ -778,8 +766,8 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       icmp0 = (icmp46_header_t *) udp0;
 
       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-      rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
-                              sw_if_index0);
+      rx_fib_index0 =
+       vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
 
       if (PREDICT_FALSE (ip0->ttl == 1))
        {
@@ -787,7 +775,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
+         next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
          goto trace0;
        }
 
@@ -795,16 +783,16 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
 
       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
        {
-         if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
+         if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
            {
-             if (!sm->forwarding_enabled)
+             if (!nm->forwarding_enabled)
                {
                  b0->error =
-                   node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
-                 next0 = SNAT_OUT2IN_NEXT_DROP;
+                   node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
+                 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
                }
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.other,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
                                         thread_index, sw_if_index0, 1);
 
          goto trace0;
@@ -812,10 +800,10 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
 
       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
        {
-         next0 = icmp_out2in_slow_path
-           (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-            next0, now, thread_index, &s0);
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.icmp,
+         next0 = nat44_ei_icmp_out2in_slow_path (
+           nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
+           thread_index, &s0);
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
                                         thread_index, sw_if_index0, 1);
          goto trace0;
        }
@@ -823,7 +811,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       init_nat_k (&kv0, ip0->dst_address,
                  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
                  proto0);
-      if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
+      if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
        {
          /* Try to match static mapping by external address and port,
             destination address and port in packet */
@@ -845,10 +833,11 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  goto trace0;
                }
 
-             if (!sm->forwarding_enabled)
+             if (!nm->forwarding_enabled)
                {
-                 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
-                 next0 = SNAT_OUT2IN_NEXT_DROP;
+                 b0->error =
+                   node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
+                 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
                }
              goto trace0;
            }
@@ -857,22 +846,18 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
            goto trace0;
 
          /* Create session initiated by host from external network */
-         s0 = create_session_for_static_mapping (sm, b0,
-                                                 sm_addr0, sm_port0,
-                                                 sm_fib_index0,
-                                                 ip0->dst_address,
-                                                 vnet_buffer (b0)->ip.
-                                                 reass.l4_dst_port,
-                                                 rx_fib_index0, proto0, node,
-                                                 thread_index, now);
+         s0 = create_session_for_static_mapping (
+           nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
+           vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
+           node, thread_index, now);
          if (!s0)
            {
-             next0 = SNAT_OUT2IN_NEXT_DROP;
+             next0 = NAT44_EI_OUT2IN_NEXT_DROP;
              goto trace0;
            }
        }
       else
-       s0 = pool_elt_at_index (tsm->sessions,
+       s0 = pool_elt_at_index (tnm->sessions,
                                nat_value_get_session_index (&value0));
 
       old_addr0 = ip0->dst_address.as_u32;
@@ -901,7 +886,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                                     length /* changed member */ );
              tcp0->checksum = ip_csum_fold (sum0);
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.tcp,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
                                         thread_index, sw_if_index0, 1);
        }
       else
@@ -922,7 +907,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  udp0->checksum = ip_csum_fold (sum0);
                }
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.udp,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -930,24 +915,24 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       nat44_ei_session_update_counters (
        s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s0, thread_index);
+      nat44_ei_session_update_lru (nm, s0, thread_index);
     trace0:
 
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_out2in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+         nat44_ei_out2in_trace_t *t =
+           vlib_add_trace (vm, node, b0, sizeof (*t));
          t->sw_if_index = sw_if_index0;
          t->next_index = next0;
          t->session_index = ~0;
          if (s0)
-           t->session_index =
-             s0 - sm->per_thread_data[thread_index].sessions;
+           t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
        }
 
-      if (next0 == SNAT_OUT2IN_NEXT_DROP)
+      if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -958,8 +943,8 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       icmp1 = (icmp46_header_t *) udp1;
 
       sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
-      rx_fib_index1 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
-                              sw_if_index1);
+      rx_fib_index1 =
+       vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
 
       if (PREDICT_FALSE (ip1->ttl == 1))
        {
@@ -967,7 +952,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next1 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
+         next1 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
          goto trace1;
        }
 
@@ -975,26 +960,26 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
 
       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
        {
-         if (nat_out2in_sm_unknown_proto (sm, b1, ip1, rx_fib_index1))
+         if (nat_out2in_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
            {
-             if (!sm->forwarding_enabled)
+             if (!nm->forwarding_enabled)
                {
                  b1->error =
-                   node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
-                 next1 = SNAT_OUT2IN_NEXT_DROP;
+                   node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
+                 next1 = NAT44_EI_OUT2IN_NEXT_DROP;
                }
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.other,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
                                         thread_index, sw_if_index1, 1);
          goto trace1;
        }
 
       if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
        {
-         next1 = icmp_out2in_slow_path
-           (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node,
-            next1, now, thread_index, &s1);
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.icmp,
+         next1 = nat44_ei_icmp_out2in_slow_path (
+           nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1, now,
+           thread_index, &s1);
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
                                         thread_index, sw_if_index1, 1);
          goto trace1;
        }
@@ -1002,7 +987,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       init_nat_k (&kv1, ip1->dst_address,
                  vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1,
                  proto1);
-      if (clib_bihash_search_8_8 (&sm->out2in, &kv1, &value1))
+      if (clib_bihash_search_8_8 (&nm->out2in, &kv1, &value1))
        {
          /* Try to match static mapping by external address and port,
             destination address and port in packet */
@@ -1024,10 +1009,11 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  goto trace1;
                }
 
-             if (!sm->forwarding_enabled)
+             if (!nm->forwarding_enabled)
                {
-                 b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
-                 next1 = SNAT_OUT2IN_NEXT_DROP;
+                 b1->error =
+                   node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
+                 next1 = NAT44_EI_OUT2IN_NEXT_DROP;
                }
              goto trace1;
            }
@@ -1036,22 +1022,18 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
            goto trace1;
 
          /* Create session initiated by host from external network */
-         s1 =
-           create_session_for_static_mapping (sm, b1, sm_addr1, sm_port1,
-                                              sm_fib_index1,
-                                              ip1->dst_address,
-                                              vnet_buffer (b1)->ip.
-                                              reass.l4_dst_port,
-                                              rx_fib_index1, proto1, node,
-                                              thread_index, now);
+         s1 = create_session_for_static_mapping (
+           nm, b1, sm_addr1, sm_port1, sm_fib_index1, ip1->dst_address,
+           vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1, proto1,
+           node, thread_index, now);
          if (!s1)
            {
-             next1 = SNAT_OUT2IN_NEXT_DROP;
+             next1 = NAT44_EI_OUT2IN_NEXT_DROP;
              goto trace1;
            }
        }
       else
-       s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
+       s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
                                nat_value_get_session_index (&value1));
 
       old_addr1 = ip1->dst_address.as_u32;
@@ -1081,7 +1063,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                                     length /* changed member */ );
              tcp1->checksum = ip_csum_fold (sum1);
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.tcp,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
                                         thread_index, sw_if_index1, 1);
        }
       else
@@ -1105,7 +1087,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  udp1->checksum = ip_csum_fold (sum1);
                }
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.udp,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
                                         thread_index, sw_if_index1, 1);
        }
 
@@ -1113,24 +1095,24 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       nat44_ei_session_update_counters (
        s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s1, thread_index);
+      nat44_ei_session_update_lru (nm, s1, thread_index);
     trace1:
 
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b1->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_out2in_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t));
+         nat44_ei_out2in_trace_t *t =
+           vlib_add_trace (vm, node, b1, sizeof (*t));
          t->sw_if_index = sw_if_index1;
          t->next_index = next1;
          t->session_index = ~0;
          if (s1)
-           t->session_index =
-             s1 - sm->per_thread_data[thread_index].sessions;
+           t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
        }
 
-      if (next1 == SNAT_OUT2IN_NEXT_DROP)
+      if (next1 == NAT44_EI_OUT2IN_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
                                         thread_index, sw_if_index1, 1);
        }
 
@@ -1143,7 +1125,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
   while (n_left_from > 0)
     {
       vlib_buffer_t *b0;
-      u32 next0 = SNAT_OUT2IN_NEXT_LOOKUP;
+      u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
       u32 sw_if_index0;
       ip4_header_t *ip0;
       ip_csum_t sum0;
@@ -1154,7 +1136,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       icmp46_header_t *icmp0;
       u32 rx_fib_index0;
       u32 proto0;
-      snat_session_t *s0 = 0;
+      nat44_ei_session_t *s0 = 0;
       clib_bihash_kv_8_8_t kv0, value0;
       u8 identity_nat0;
       ip4_address_t sm_addr0;
@@ -1172,23 +1154,23 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       icmp0 = (icmp46_header_t *) udp0;
 
       sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-      rx_fib_index0 = vec_elt (sm->ip4_main->fib_index_by_sw_if_index,
-                              sw_if_index0);
+      rx_fib_index0 =
+       vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
 
       proto0 = ip_proto_to_nat_proto (ip0->protocol);
 
       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
        {
-         if (nat_out2in_sm_unknown_proto (sm, b0, ip0, rx_fib_index0))
+         if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
            {
-             if (!sm->forwarding_enabled)
+             if (!nm->forwarding_enabled)
                {
                  b0->error =
-                   node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
-                 next0 = SNAT_OUT2IN_NEXT_DROP;
+                   node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
+                 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
                }
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.other,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
                                         thread_index, sw_if_index0, 1);
          goto trace00;
        }
@@ -1199,16 +1181,16 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
+         next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
          goto trace00;
        }
 
       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
        {
-         next0 = icmp_out2in_slow_path
-           (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node,
-            next0, now, thread_index, &s0);
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.icmp,
+         next0 = nat44_ei_icmp_out2in_slow_path (
+           nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
+           thread_index, &s0);
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
                                         thread_index, sw_if_index0, 1);
          goto trace00;
        }
@@ -1217,7 +1199,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
                  proto0);
 
-      if (clib_bihash_search_8_8 (&sm->out2in, &kv0, &value0))
+      if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
        {
          /* Try to match static mapping by external address and port,
             destination address and port in packet */
@@ -1239,10 +1221,11 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  goto trace00;
                }
 
-             if (!sm->forwarding_enabled)
+             if (!nm->forwarding_enabled)
                {
-                 b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
-                 next0 = SNAT_OUT2IN_NEXT_DROP;
+                 b0->error =
+                   node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
+                 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
                }
              goto trace00;
            }
@@ -1251,22 +1234,18 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
            goto trace00;
 
          /* Create session initiated by host from external network */
-         s0 = create_session_for_static_mapping (sm, b0,
-                                                 sm_addr0, sm_port0,
-                                                 sm_fib_index0,
-                                                 ip0->dst_address,
-                                                 vnet_buffer (b0)->ip.
-                                                 reass.l4_dst_port,
-                                                 rx_fib_index0, proto0, node,
-                                                 thread_index, now);
+         s0 = create_session_for_static_mapping (
+           nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
+           vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
+           node, thread_index, now);
          if (!s0)
            {
-             next0 = SNAT_OUT2IN_NEXT_DROP;
+             next0 = NAT44_EI_OUT2IN_NEXT_DROP;
              goto trace00;
            }
        }
       else
-       s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions,
+       s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
                                nat_value_get_session_index (&value0));
 
       old_addr0 = ip0->dst_address.as_u32;
@@ -1296,7 +1275,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                                     length /* changed member */ );
              tcp0->checksum = ip_csum_fold (sum0);
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.tcp,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
                                         thread_index, sw_if_index0, 1);
        }
       else
@@ -1317,7 +1296,7 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
                  udp0->checksum = ip_csum_fold (sum0);
                }
            }
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.udp,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -1325,24 +1304,24 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
       nat44_ei_session_update_counters (
        s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
       /* Per-user LRU list maintenance */
-      nat44_session_update_lru (sm, s0, thread_index);
+      nat44_ei_session_update_lru (nm, s0, thread_index);
     trace00:
 
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_out2in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+         nat44_ei_out2in_trace_t *t =
+           vlib_add_trace (vm, node, b0, sizeof (*t));
          t->sw_if_index = sw_if_index0;
          t->next_index = next0;
          t->session_index = ~0;
          if (s0)
-           t->session_index =
-             s0 - sm->per_thread_data[thread_index].sessions;
+           t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
        }
 
-      if (next0 == SNAT_OUT2IN_NEXT_DROP)
+      if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.slowpath.out2in.drops,
+         vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
                                         thread_index, sw_if_index0, 1);
        }
 
@@ -1358,34 +1337,33 @@ VLIB_NODE_FN (snat_out2in_node) (vlib_main_t * vm,
 }
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (snat_out2in_node) = {
-  .name = "nat44-out2in",
+VLIB_REGISTER_NODE (nat44_ei_out2in_node) = {
+  .name = "nat44-ei-out2in",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_out2in_trace,
+  .format_trace = format_nat44_ei_out2in_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
-  .error_strings = snat_out2in_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
+  .error_strings = nat44_ei_out2in_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
+  .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
-    [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
-    [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
+    [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
   },
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
-                                     vlib_node_runtime_t * node,
-                                     vlib_frame_t * frame)
+VLIB_NODE_FN (nat44_ei_out2in_fast_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
 {
   u32 n_left_from, *from;
-  snat_main_t *sm = &snat_main;
+  nat44_ei_main_t *nm = &nat44_ei_main;
 
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
@@ -1396,7 +1374,7 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
   while (n_left_from > 0)
     {
       vlib_buffer_t *b0;
-      u32 next0 = SNAT_OUT2IN_NEXT_DROP;
+      u32 next0 = NAT44_EI_OUT2IN_NEXT_DROP;
       u32 sw_if_index0;
       ip4_header_t *ip0;
       ip_csum_t sum0;
@@ -1430,7 +1408,7 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
          icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
                                       ICMP4_time_exceeded_ttl_exceeded_in_transit,
                                       0);
-         next0 = SNAT_OUT2IN_NEXT_ICMP_ERROR;
+         next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
          goto trace00;
        }
 
@@ -1441,8 +1419,8 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
 
       if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
        {
-         next0 = icmp_out2in (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
-                              node, next0, ~0, 0);
+         next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
+                                       rx_fib_index0, node, next0, ~0, 0);
          goto trace00;
        }
 
@@ -1450,7 +1428,7 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
                                         rx_fib_index0, proto0, &sm_addr0,
                                         &sm_port0, &sm_fib_index0, 1, 0, 0))
        {
-         b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
+         b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
          goto trace00;
        }
 
@@ -1518,14 +1496,15 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
       if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
                         && (b0->flags & VLIB_BUFFER_IS_TRACED)))
        {
-         snat_out2in_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+         nat44_ei_out2in_trace_t *t =
+           vlib_add_trace (vm, node, b0, sizeof (*t));
          t->sw_if_index = sw_if_index0;
          t->next_index = next0;
        }
 
-      if (next0 == SNAT_OUT2IN_NEXT_DROP)
+      if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
        {
-         vlib_increment_simple_counter (&sm->counters.fastpath.out2in.drops,
+         vlib_increment_simple_counter (&nm->counters.fastpath.out2in.drops,
                                         vm->thread_index, sw_if_index0, 1);
        }
 
@@ -1541,24 +1520,24 @@ VLIB_NODE_FN (snat_out2in_fast_node) (vlib_main_t * vm,
 }
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (snat_out2in_fast_node) = {
-  .name = "nat44-out2in-fast",
+VLIB_REGISTER_NODE (nat44_ei_out2in_fast_node) = {
+  .name = "nat44-ei-out2in-fast",
   .vector_size = sizeof (u32),
-  .format_trace = format_snat_out2in_fast_trace,
+  .format_trace = format_nat44_ei_out2in_fast_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(snat_out2in_error_strings),
-  .error_strings = snat_out2in_error_strings,
+  .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
+  .error_strings = nat44_ei_out2in_error_strings,
 
-  .runtime_data_bytes = sizeof (snat_runtime_t),
+  .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
 
-  .n_next_nodes = SNAT_OUT2IN_N_NEXT,
+  .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
 
   /* edit / add dispositions here */
   .next_nodes = {
-    [SNAT_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
-    [SNAT_OUT2IN_NEXT_DROP] = "error-drop",
-    [SNAT_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
+    [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
+    [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
+    [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
   },
 };
 /* *INDENT-ON* */
diff --git a/src/plugins/nat/nat44/ed_inlines.h b/src/plugins/nat/nat44/ed_inlines.h
deleted file mode 100644 (file)
index 87de25e..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * simple nat plugin
- *
- * Copyright (c) 2020 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __included_ed_inlines_h__
-#define __included_ed_inlines_h__
-
-#include <float.h>
-#include <vppinfra/clib.h>
-#include <nat/nat.h>
-#include <nat/nat_inlines.h>
-
-static_always_inline int
-nat_ed_lru_insert (snat_main_per_thread_data_t * tsm,
-                  snat_session_t * s, f64 now, u8 proto)
-{
-  dlist_elt_t *lru_list_elt;
-  pool_get (tsm->lru_pool, lru_list_elt);
-  s->lru_index = lru_list_elt - tsm->lru_pool;
-  switch (proto)
-    {
-    case IP_PROTOCOL_UDP:
-      s->lru_head_index = tsm->udp_lru_head_index;
-      break;
-    case IP_PROTOCOL_TCP:
-      s->lru_head_index = tsm->tcp_trans_lru_head_index;
-      break;
-    case IP_PROTOCOL_ICMP:
-      s->lru_head_index = tsm->icmp_lru_head_index;
-      break;
-    default:
-      s->lru_head_index = tsm->unk_proto_lru_head_index;
-      break;
-    }
-  clib_dlist_addtail (tsm->lru_pool, s->lru_head_index, s->lru_index);
-  lru_list_elt->value = s - tsm->sessions;
-  s->last_lru_update = now;
-  return 1;
-}
-
-static_always_inline void
-nat_6t_flow_to_ed_k (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f)
-{
-  init_ed_k (kv, f->match.saddr, f->match.sport, f->match.daddr,
-            f->match.dport, f->match.fib_index, f->match.proto);
-}
-
-static_always_inline void
-nat_6t_flow_to_ed_kv (clib_bihash_kv_16_8_t *kv, nat_6t_flow_t *f,
-                     u32 thread_idx, u32 session_idx)
-{
-  init_ed_kv (kv, f->match.saddr, f->match.sport, f->match.daddr,
-             f->match.dport, f->match.fib_index, f->match.proto, thread_idx,
-             session_idx);
-}
-
-static_always_inline int
-nat_ed_ses_i2o_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
-                                 snat_session_t *s, int is_add)
-{
-  snat_main_per_thread_data_t *tsm =
-    vec_elt_at_index (sm->per_thread_data, thread_idx);
-  clib_bihash_kv_16_8_t kv;
-  if (0 == is_add)
-    {
-      nat_6t_flow_to_ed_k (&kv, &s->i2o);
-    }
-  else
-    {
-      nat_6t_flow_to_ed_kv (&kv, &s->i2o, thread_idx, s - tsm->sessions);
-      nat_6t_l3_l4_csum_calc (&s->i2o);
-    }
-  return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
-}
-
-static_always_inline int
-nat_ed_ses_o2i_flow_hash_add_del (snat_main_t *sm, u32 thread_idx,
-                                 snat_session_t *s, int is_add)
-{
-  snat_main_per_thread_data_t *tsm =
-    vec_elt_at_index (sm->per_thread_data, thread_idx);
-  clib_bihash_kv_16_8_t kv;
-  if (0 == is_add)
-    {
-      nat_6t_flow_to_ed_k (&kv, &s->o2i);
-    }
-  else
-    {
-      nat_6t_flow_to_ed_kv (&kv, &s->o2i, thread_idx, s - tsm->sessions);
-      nat_6t_l3_l4_csum_calc (&s->o2i);
-    }
-  return clib_bihash_add_del_16_8 (&sm->flow_hash, &kv, is_add);
-}
-
-always_inline void
-nat_ed_session_delete (snat_main_t * sm, snat_session_t * ses,
-                      u32 thread_index, int lru_delete
-                      /* delete from global LRU list */ )
-{
-  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
-                                                      thread_index);
-
-  if (lru_delete)
-    {
-      clib_dlist_remove (tsm->lru_pool, ses->lru_index);
-    }
-  pool_put_index (tsm->lru_pool, ses->lru_index);
-  if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, ses, 0))
-    nat_elog_warn ("flow hash del failed");
-  if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, ses, 0))
-    nat_elog_warn ("flow hash del failed");
-  pool_put (tsm->sessions, ses);
-  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
-                          pool_elts (tsm->sessions));
-
-}
-
-static_always_inline int
-nat_lru_free_one_with_head (snat_main_t * sm, int thread_index,
-                           f64 now, u32 head_index)
-{
-  snat_session_t *s = NULL;
-  dlist_elt_t *oldest_elt;
-  f64 sess_timeout_time;
-  u32 oldest_index;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  oldest_index = clib_dlist_remove_head (tsm->lru_pool, head_index);
-  if (~0 != oldest_index)
-    {
-      oldest_elt = pool_elt_at_index (tsm->lru_pool, oldest_index);
-      s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
-
-      sess_timeout_time =
-       s->last_heard + (f64) nat44_session_get_timeout (sm, s);
-      if (now >= sess_timeout_time
-         || (s->tcp_closed_timestamp && now >= s->tcp_closed_timestamp))
-       {
-         nat_free_session_data (sm, s, thread_index, 0);
-         nat_ed_session_delete (sm, s, thread_index, 0);
-         return 1;
-       }
-      else
-       {
-         clib_dlist_addhead (tsm->lru_pool, head_index, oldest_index);
-       }
-    }
-  return 0;
-}
-
-static_always_inline int
-nat_lru_free_one (snat_main_t * sm, int thread_index, f64 now)
-{
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  int rc = 0;
-#define _(p)                                                       \
-  if ((rc = nat_lru_free_one_with_head (sm, thread_index, now,     \
-                                        tsm->p##_lru_head_index))) \
-    {                                                              \
-      return rc;                                                   \
-    }
-  _(tcp_trans);
-  _(udp);
-  _(unk_proto);
-  _(icmp);
-  _(tcp_estab);
-#undef _
-  return 0;
-}
-
-static_always_inline snat_session_t *
-nat_ed_session_alloc (snat_main_t * sm, u32 thread_index, f64 now, u8 proto)
-{
-  snat_session_t *s;
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-
-  nat_lru_free_one (sm, thread_index, now);
-
-  pool_get (tsm->sessions, s);
-  clib_memset (s, 0, sizeof (*s));
-
-  nat_ed_lru_insert (tsm, s, now, proto);
-
-  s->ha_last_refreshed = now;
-  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
-                          pool_elts (tsm->sessions));
-  return s;
-}
-
-// slow path
-static_always_inline void
-per_vrf_sessions_cleanup (u32 thread_index)
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm =
-    vec_elt_at_index (sm->per_thread_data, thread_index);
-  per_vrf_sessions_t *per_vrf_sessions;
-  u32 *to_free = 0, *i;
-
-  vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
-  {
-    if (per_vrf_sessions->expired)
-      {
-       if (per_vrf_sessions->ses_count == 0)
-         {
-           vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec);
-         }
-      }
-  }
-
-  if (vec_len (to_free))
-    {
-      vec_foreach (i, to_free)
-      {
-       vec_del1 (tsm->per_vrf_sessions_vec, *i);
-      }
-    }
-
-  vec_free (to_free);
-}
-
-// slow path
-static_always_inline void
-per_vrf_sessions_register_session (snat_session_t * s, u32 thread_index)
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm =
-    vec_elt_at_index (sm->per_thread_data, thread_index);
-  per_vrf_sessions_t *per_vrf_sessions;
-
-  per_vrf_sessions_cleanup (thread_index);
-
-  // s->per_vrf_sessions_index == ~0 ... reuse of old session
-
-  vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
-  {
-    // ignore already expired registrations
-    if (per_vrf_sessions->expired)
-      continue;
-
-    if ((s->in2out.fib_index == per_vrf_sessions->rx_fib_index) &&
-       (s->out2in.fib_index == per_vrf_sessions->tx_fib_index))
-      {
-       goto done;
-      }
-    if ((s->in2out.fib_index == per_vrf_sessions->tx_fib_index) &&
-       (s->out2in.fib_index == per_vrf_sessions->rx_fib_index))
-      {
-       goto done;
-      }
-  }
-
-  // create a new registration
-  vec_add2 (tsm->per_vrf_sessions_vec, per_vrf_sessions, 1);
-  clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions));
-
-  per_vrf_sessions->rx_fib_index = s->in2out.fib_index;
-  per_vrf_sessions->tx_fib_index = s->out2in.fib_index;
-
-done:
-  s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec;
-  per_vrf_sessions->ses_count++;
-}
-
-// fast path
-static_always_inline void
-per_vrf_sessions_unregister_session (snat_session_t * s, u32 thread_index)
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
-  per_vrf_sessions_t *per_vrf_sessions;
-
-  ASSERT (s->per_vrf_sessions_index != ~0);
-
-  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
-  per_vrf_sessions =
-    vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
-
-  ASSERT (per_vrf_sessions->ses_count != 0);
-
-  per_vrf_sessions->ses_count--;
-  s->per_vrf_sessions_index = ~0;
-}
-
-// fast path
-static_always_inline u8
-per_vrf_sessions_is_expired (snat_session_t * s, u32 thread_index)
-{
-  snat_main_t *sm = &snat_main;
-  snat_main_per_thread_data_t *tsm;
-  per_vrf_sessions_t *per_vrf_sessions;
-
-  ASSERT (s->per_vrf_sessions_index != ~0);
-
-  tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
-  per_vrf_sessions =
-    vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index);
-  return per_vrf_sessions->expired;
-}
-
-static_always_inline void
-nat_6t_flow_init (nat_6t_flow_t *f, u32 thread_idx, ip4_address_t saddr,
-                 u16 sport, ip4_address_t daddr, u16 dport, u32 fib_index,
-                 u8 proto, u32 session_idx)
-{
-  clib_memset (f, 0, sizeof (*f));
-  f->match.saddr = saddr;
-  f->match.sport = sport;
-  f->match.daddr = daddr;
-  f->match.dport = dport;
-  f->match.proto = proto;
-  f->match.fib_index = fib_index;
-}
-
-static_always_inline void
-nat_6t_i2o_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
-                     ip4_address_t saddr, u16 sport, ip4_address_t daddr,
-                     u16 dport, u32 fib_index, u8 proto)
-{
-  snat_main_per_thread_data_t *tsm =
-    vec_elt_at_index (sm->per_thread_data, thread_idx);
-  nat_6t_flow_init (&s->i2o, thread_idx, saddr, sport, daddr, dport, fib_index,
-                   proto, s - tsm->sessions);
-}
-
-static_always_inline void
-nat_6t_o2i_flow_init (snat_main_t *sm, u32 thread_idx, snat_session_t *s,
-                     ip4_address_t saddr, u16 sport, ip4_address_t daddr,
-                     u16 dport, u32 fib_index, u8 proto)
-{
-  snat_main_per_thread_data_t *tsm =
-    vec_elt_at_index (sm->per_thread_data, thread_idx);
-  nat_6t_flow_init (&s->o2i, thread_idx, saddr, sport, daddr, dport, fib_index,
-                   proto, s - tsm->sessions);
-}
-
-static_always_inline int
-nat_6t_flow_match (nat_6t_flow_t *f, vlib_buffer_t *b, ip4_address_t saddr,
-                  u16 sport, ip4_address_t daddr, u16 dport, u8 protocol,
-                  u32 fib_index)
-{
-  return f->match.daddr.as_u32 == daddr.as_u32 &&
-        f->match.dport == vnet_buffer (b)->ip.reass.l4_dst_port &&
-        f->match.proto == protocol && f->match.fib_index == fib_index &&
-        f->match.saddr.as_u32 == saddr.as_u32 &&
-        f->match.sport == vnet_buffer (b)->ip.reass.l4_src_port;
-}
-
-#endif
diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h
deleted file mode 100644 (file)
index fde228e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2020 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @brief The NAT44 inline functions
- */
-
-#ifndef included_nat44_inlines_h__
-#define included_nat44_inlines_h__
-
-#include <vnet/fib/ip4_fib.h>
-#include <nat/nat.h>
-
-static_always_inline u8
-nat44_ed_maximum_sessions_exceeded (snat_main_t * sm,
-                                   u32 fib_index, u32 thread_index)
-{
-  u32 translations;
-  translations = pool_elts (sm->per_thread_data[thread_index].sessions);
-  if (vec_len (sm->max_translations_per_fib) <= fib_index)
-    fib_index = 0;
-  return translations >= sm->max_translations_per_fib[fib_index];
-}
-
-#endif /* included_nat44_inlines_h__ */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
index 5fc4129..21d3592 100644 (file)
@@ -16,7 +16,7 @@
 option version = "1.0.0";
 import "vnet/ip/ip_types.api";
 import "vnet/interface_types.api";
-import "plugins/nat/nat_types.api";
+import "plugins/nat/lib/nat_types.api";
 
 /**
  * @file nat64.api
index 6906e41..bbadf07 100644 (file)
@@ -16,7 +16,7 @@
 option version = "1.0.0";
 import "vnet/ip/ip_types.api";
 import "vnet/interface_types.api";
-import "plugins/nat/nat_types.api";
+import "plugins/nat/lib/nat_types.api";
 
 /** \brief Enable/disable NAT66 feature on the interface
     @param client_index - opaque cookie to identify the sender
diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h
deleted file mode 100644 (file)
index d53e245..0000000
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @brief The NAT inline functions
- */
-
-#ifndef __included_nat_inlines_h__
-#define __included_nat_inlines_h__
-
-#include <vnet/fib/ip4_fib.h>
-#include <nat/nat.h>
-//#include <nat/nat44-ei/nat44_ei_ha.h>
-
-always_inline u64
-calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto)
-{
-  ASSERT (fib_index <= (1 << 14) - 1);
-  ASSERT (proto <= (1 << 3) - 1);
-  return (u64) addr.as_u32 << 32 | (u64) port << 16 | fib_index << 3 |
-        (proto & 0x7);
-}
-
-always_inline void
-split_nat_key (u64 key, ip4_address_t * addr, u16 * port,
-              u32 * fib_index, nat_protocol_t * proto)
-{
-  if (addr)
-    {
-      addr->as_u32 = key >> 32;
-    }
-  if (port)
-    {
-      *port = (key >> 16) & (u16) ~ 0;
-    }
-  if (fib_index)
-    {
-      *fib_index = key >> 3 & ((1 << 13) - 1);
-    }
-  if (proto)
-    {
-      *proto = key & 0x7;
-    }
-}
-
-always_inline void
-init_nat_k (clib_bihash_kv_8_8_t * kv, ip4_address_t addr, u16 port,
-           u32 fib_index, nat_protocol_t proto)
-{
-  kv->key = calc_nat_key (addr, port, fib_index, proto);
-  kv->value = ~0ULL;
-}
-
-always_inline void
-init_nat_kv (clib_bihash_kv_8_8_t *kv, ip4_address_t addr, u16 port,
-            u32 fib_index, nat_protocol_t proto, u32 thread_index,
-            u32 session_index)
-{
-  init_nat_k (kv, addr, port, fib_index, proto);
-  kv->value = (u64) thread_index << 32 | session_index;
-}
-
-always_inline void
-init_nat_i2o_k (clib_bihash_kv_8_8_t * kv, snat_session_t * s)
-{
-  return init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
-                    s->nat_proto);
-}
-
-always_inline void
-init_nat_i2o_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index,
-                u32 session_index)
-{
-  init_nat_k (kv, s->in2out.addr, s->in2out.port, s->in2out.fib_index,
-             s->nat_proto);
-  kv->value = (u64) thread_index << 32 | session_index;
-}
-
-always_inline void
-init_nat_o2i_k (clib_bihash_kv_8_8_t * kv, snat_session_t * s)
-{
-  return init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
-                    s->nat_proto);
-}
-
-always_inline void
-init_nat_o2i_kv (clib_bihash_kv_8_8_t *kv, snat_session_t *s, u32 thread_index,
-                u32 session_index)
-{
-  init_nat_k (kv, s->out2in.addr, s->out2in.port, s->out2in.fib_index,
-             s->nat_proto);
-  kv->value = (u64) thread_index << 32 | session_index;
-}
-
-always_inline u32
-nat_value_get_thread_index (clib_bihash_kv_8_8_t *value)
-{
-  return value->value >> 32;
-}
-
-always_inline u32
-nat_value_get_session_index (clib_bihash_kv_8_8_t *value)
-{
-  return value->value & ~(u32) 0;
-}
-
-static inline uword
-nat_pre_node_fn_inline (vlib_main_t * vm,
-                       vlib_node_runtime_t * node,
-                       vlib_frame_t * frame, u32 def_next)
-{
-  u32 n_left_from, *from;
-
-  from = vlib_frame_vector_args (frame);
-  n_left_from = frame->n_vectors;
-
-  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
-  u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
-  vlib_get_buffers (vm, from, b, n_left_from);
-
-  while (n_left_from >= 2)
-    {
-      u32 next0, next1;
-      u32 arc_next0, arc_next1;
-      vlib_buffer_t *b0, *b1;
-
-      b0 = *b;
-      b++;
-      b1 = *b;
-      b++;
-
-      /* Prefetch next iteration. */
-      if (PREDICT_TRUE (n_left_from >= 4))
-       {
-         vlib_buffer_t *p2, *p3;
-
-         p2 = *b;
-         p3 = *(b + 1);
-
-         vlib_prefetch_buffer_header (p2, LOAD);
-         vlib_prefetch_buffer_header (p3, LOAD);
-
-         CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
-         CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
-       }
-
-      next0 = def_next;
-      next1 = def_next;
-
-      vnet_feature_next (&arc_next0, b0);
-      vnet_feature_next (&arc_next1, b1);
-
-      vnet_buffer2 (b0)->nat.arc_next = arc_next0;
-      vnet_buffer2 (b1)->nat.arc_next = arc_next1;
-
-      if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
-       {
-         if (b0->flags & VLIB_BUFFER_IS_TRACED)
-           {
-             nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->next_index = next0;
-             t->arc_next_index = arc_next0;
-           }
-         if (b1->flags & VLIB_BUFFER_IS_TRACED)
-           {
-             nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
-             t->next_index = next1;
-             t->arc_next_index = arc_next1;
-           }
-       }
-
-      n_left_from -= 2;
-      next[0] = next0;
-      next[1] = next1;
-      next += 2;
-    }
-
-  while (n_left_from > 0)
-    {
-      u32 next0;
-      u32 arc_next0;
-      vlib_buffer_t *b0;
-
-      b0 = *b;
-      b++;
-
-      next0 = def_next;
-      vnet_feature_next (&arc_next0, b0);
-      vnet_buffer2 (b0)->nat.arc_next = arc_next0;
-
-      if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
-                        && (b0->flags & VLIB_BUFFER_IS_TRACED)))
-       {
-         nat_pre_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
-         t->next_index = next0;
-         t->arc_next_index = arc_next0;
-       }
-
-      n_left_from--;
-      next[0] = next0;
-      next++;
-    }
-  vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
-                              frame->n_vectors);
-
-  return frame->n_vectors;
-}
-
-always_inline u8
-is_interface_addr (snat_main_t * sm, vlib_node_runtime_t * node,
-                  u32 sw_if_index0, u32 ip4_addr)
-{
-  snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data;
-  ip4_address_t *first_int_addr;
-
-  if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0))
-    {
-      first_int_addr =
-       ip4_interface_first_address (sm->ip4_main, sw_if_index0,
-                                    0 /* just want the address */ );
-      rt->cached_sw_if_index = sw_if_index0;
-      if (first_int_addr)
-       rt->cached_ip4_address = first_int_addr->as_u32;
-      else
-       rt->cached_ip4_address = 0;
-    }
-
-  if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address))
-    return 1;
-  else
-    return 0;
-}
-
-always_inline void
-user_session_increment (snat_main_t * sm, snat_user_t * u, u8 is_static)
-{
-  if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user)
-    {
-      if (is_static)
-       u->nstaticsessions++;
-      else
-       u->nsessions++;
-    }
-}
-
-always_inline void
-nat44_delete_user_with_no_session (snat_main_t * sm, snat_user_t * u,
-                                  u32 thread_index)
-{
-  clib_bihash_kv_8_8_t kv;
-  snat_user_key_t u_key;
-  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
-                                                      thread_index);
-
-  if (u->nstaticsessions == 0 && u->nsessions == 0)
-    {
-      u_key.addr.as_u32 = u->addr.as_u32;
-      u_key.fib_index = u->fib_index;
-      kv.key = u_key.as_u64;
-      pool_put_index (tsm->list_pool, u->sessions_per_user_list_head_index);
-      pool_put (tsm->users, u);
-      clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
-      vlib_set_simple_counter (&sm->total_users, thread_index, 0,
-                              pool_elts (tsm->users));
-    }
-}
-
-always_inline void
-nat44_delete_session (snat_main_t * sm, snat_session_t * ses,
-                     u32 thread_index)
-{
-  snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data,
-                                                      thread_index);
-  clib_bihash_kv_8_8_t kv, value;
-  snat_user_t *u;
-  const snat_user_key_t u_key = {
-    .addr = ses->in2out.addr,
-    .fib_index = ses->in2out.fib_index
-  };
-  const u8 u_static = snat_is_session_static (ses);
-
-  clib_dlist_remove (tsm->list_pool, ses->per_user_index);
-  pool_put_index (tsm->list_pool, ses->per_user_index);
-  if (sm->endpoint_dependent)
-    {
-      clib_dlist_remove (tsm->lru_pool, ses->lru_index);
-      pool_put_index (tsm->lru_pool, ses->lru_index);
-    }
-  pool_put (tsm->sessions, ses);
-  vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
-                          pool_elts (tsm->sessions));
-
-  kv.key = u_key.as_u64;
-  if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
-    {
-      u = pool_elt_at_index (tsm->users, value.value);
-      if (u_static)
-       u->nstaticsessions--;
-      else
-       u->nsessions--;
-
-      nat44_delete_user_with_no_session (sm, u, thread_index);
-    }
-}
-
-always_inline void
-nat44_set_tcp_session_state_i2o (snat_main_t * sm, f64 now,
-                                snat_session_t * ses, vlib_buffer_t * b,
-                                u32 thread_index)
-{
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags;
-  u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number;
-  u32 tcp_seq_number = vnet_buffer (b)->ip.reass.tcp_seq_number;
-  if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
-    ses->state = NAT44_SES_RST;
-  if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
-    ses->state = 0;
-  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
-      (ses->state & NAT44_SES_O2I_SYN))
-    ses->state = 0;
-  if (tcp_flags & TCP_FLAG_SYN)
-    ses->state |= NAT44_SES_I2O_SYN;
-  if (tcp_flags & TCP_FLAG_FIN)
-    {
-      ses->i2o_fin_seq = clib_net_to_host_u32 (tcp_seq_number);
-      ses->state |= NAT44_SES_I2O_FIN;
-    }
-  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN))
-    {
-      if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq)
-       {
-         ses->state |= NAT44_SES_O2I_FIN_ACK;
-         if (nat44_is_ses_closed (ses))
-           {                   // if session is now closed, save the timestamp
-             ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory;
-             ses->last_lru_update = now;
-           }
-       }
-    }
-
-  // move the session to proper LRU
-  if (ses->state)
-    {
-      ses->lru_head_index = tsm->tcp_trans_lru_head_index;
-    }
-  else
-    {
-      ses->lru_head_index = tsm->tcp_estab_lru_head_index;
-    }
-  clib_dlist_remove (tsm->lru_pool, ses->lru_index);
-  clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
-}
-
-always_inline void
-nat44_set_tcp_session_state_o2i (snat_main_t * sm, f64 now,
-                                snat_session_t * ses, u8 tcp_flags,
-                                u32 tcp_ack_number, u32 tcp_seq_number,
-                                u32 thread_index)
-{
-  snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
-  if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST))
-    ses->state = NAT44_SES_RST;
-  if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST))
-    ses->state = 0;
-  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) &&
-      (ses->state & NAT44_SES_O2I_SYN))
-    ses->state = 0;
-  if (tcp_flags & TCP_FLAG_SYN)
-    ses->state |= NAT44_SES_O2I_SYN;
-  if (tcp_flags & TCP_FLAG_FIN)
-    {
-      ses->o2i_fin_seq = clib_net_to_host_u32 (tcp_seq_number);
-      ses->state |= NAT44_SES_O2I_FIN;
-    }
-  if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN))
-    {
-      if (clib_net_to_host_u32 (tcp_ack_number) > ses->i2o_fin_seq)
-       ses->state |= NAT44_SES_I2O_FIN_ACK;
-      if (nat44_is_ses_closed (ses))
-       {                       // if session is now closed, save the timestamp
-         ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory;
-         ses->last_lru_update = now;
-       }
-    }
-  // move the session to proper LRU
-  if (ses->state)
-    {
-      ses->lru_head_index = tsm->tcp_trans_lru_head_index;
-    }
-  else
-    {
-      ses->lru_head_index = tsm->tcp_estab_lru_head_index;
-    }
-  clib_dlist_remove (tsm->lru_pool, ses->lru_index);
-  clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index);
-}
-
-always_inline u32
-nat44_session_get_timeout (snat_main_t * sm, snat_session_t * s)
-{
-  switch (s->nat_proto)
-    {
-    case NAT_PROTOCOL_ICMP:
-      return sm->timeouts.icmp;
-    case NAT_PROTOCOL_UDP:
-      return sm->timeouts.udp;
-    case NAT_PROTOCOL_TCP:
-      {
-       if (s->state)
-         return sm->timeouts.tcp.transitory;
-       else
-         return sm->timeouts.tcp.established;
-      }
-    default:
-      return sm->timeouts.udp;
-    }
-
-  return 0;
-}
-
-always_inline void
-nat44_session_update_counters (snat_session_t * s, f64 now, uword bytes,
-                              u32 thread_index)
-{
-  s->last_heard = now;
-  s->total_pkts++;
-  s->total_bytes += bytes;
-#if 0
-  nat_ha_sref (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
-              s->ext_host_port, s->nat_proto, s->out2in.fib_index,
-              s->total_pkts, s->total_bytes, thread_index,
-              &s->ha_last_refreshed, now);
-#endif
-}
-
-/** \brief Per-user LRU list maintenance */
-always_inline void
-nat44_session_update_lru (snat_main_t * sm, snat_session_t * s,
-                         u32 thread_index)
-{
-  /* don't update too often - timeout is in magnitude of seconds anyway */
-  if (s->last_heard > s->last_lru_update + 1)
-    {
-      if (!sm->endpoint_dependent)
-       {
-         clib_dlist_remove (sm->per_thread_data[thread_index].list_pool,
-                            s->per_user_index);
-         clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool,
-                             s->per_user_list_head_index, s->per_user_index);
-       }
-      else
-       {
-         clib_dlist_remove (sm->per_thread_data[thread_index].lru_pool,
-                            s->lru_index);
-         clib_dlist_addtail (sm->per_thread_data[thread_index].lru_pool,
-                             s->lru_head_index, s->lru_index);
-       }
-      s->last_lru_update = s->last_heard;
-    }
-}
-
-always_inline void
-init_ed_k (clib_bihash_kv_16_8_t * kv, ip4_address_t l_addr, u16 l_port,
-          ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto)
-{
-  kv->key[0] = (u64) r_addr.as_u32 << 32 | l_addr.as_u32;
-  kv->key[1] =
-    (u64) r_port << 48 | (u64) l_port << 32 | fib_index << 8 | proto;
-}
-
-always_inline void
-init_ed_kv (clib_bihash_kv_16_8_t * kv, ip4_address_t l_addr, u16 l_port,
-           ip4_address_t r_addr, u16 r_port, u32 fib_index, u8 proto,
-           u32 thread_index, u32 session_index)
-{
-  init_ed_k (kv, l_addr, l_port, r_addr, r_port, fib_index, proto);
-  kv->value = (u64) thread_index << 32 | session_index;
-}
-
-always_inline u32
-ed_value_get_thread_index (clib_bihash_kv_16_8_t * value)
-{
-  return value->value >> 32;
-}
-
-always_inline u32
-ed_value_get_session_index (clib_bihash_kv_16_8_t * value)
-{
-  return value->value & ~(u32) 0;
-}
-
-always_inline void
-split_ed_kv (clib_bihash_kv_16_8_t * kv,
-            ip4_address_t * l_addr, ip4_address_t * r_addr, u8 * proto,
-            u32 * fib_index, u16 * l_port, u16 * r_port)
-{
-  if (l_addr)
-    {
-      l_addr->as_u32 = kv->key[0] & (u32) ~ 0;
-    }
-  if (r_addr)
-    {
-      r_addr->as_u32 = kv->key[0] >> 32;
-    }
-  if (r_port)
-    {
-      *r_port = kv->key[1] >> 48;
-    }
-  if (l_port)
-    {
-      *l_port = (kv->key[1] >> 32) & (u16) ~ 0;
-    }
-  if (fib_index)
-    {
-      *fib_index = (kv->key[1] >> 8) & ((1 << 24) - 1);
-    }
-  if (proto)
-    {
-      *proto = kv->key[1] & (u8) ~ 0;
-    }
-}
-
-static_always_inline int
-nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0,
-                                   ip4_address_t *lookup_saddr,
-                                   u16 *lookup_sport,
-                                   ip4_address_t *lookup_daddr,
-                                   u16 *lookup_dport, u8 *lookup_protocol)
-{
-  icmp46_header_t *icmp0;
-  icmp_echo_header_t *echo0, *inner_echo0 = 0;
-  ip4_header_t *inner_ip0 = 0;
-  void *l4_header = 0;
-  icmp46_header_t *inner_icmp0;
-
-  icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
-  echo0 = (icmp_echo_header_t *) (icmp0 + 1);
-
-  // avoid warning about unused variables in caller by setting to bogus values
-  *lookup_sport = 0;
-  *lookup_dport = 0;
-
-  if (!icmp_type_is_error_message
-      (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
-    {
-      *lookup_protocol = IP_PROTOCOL_ICMP;
-      lookup_saddr->as_u32 = ip0->src_address.as_u32;
-      *lookup_sport = vnet_buffer (b)->ip.reass.l4_src_port;
-      lookup_daddr->as_u32 = ip0->dst_address.as_u32;
-      *lookup_dport = vnet_buffer (b)->ip.reass.l4_dst_port;
-    }
-  else
-    {
-      inner_ip0 = (ip4_header_t *) (echo0 + 1);
-      l4_header = ip4_next_header (inner_ip0);
-      *lookup_protocol = inner_ip0->protocol;
-      lookup_saddr->as_u32 = inner_ip0->dst_address.as_u32;
-      lookup_daddr->as_u32 = inner_ip0->src_address.as_u32;
-      switch (ip_proto_to_nat_proto (inner_ip0->protocol))
-       {
-       case NAT_PROTOCOL_ICMP:
-         inner_icmp0 = (icmp46_header_t *) l4_header;
-         inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
-         *lookup_sport = inner_echo0->identifier;
-         *lookup_dport = inner_echo0->identifier;
-         break;
-       case NAT_PROTOCOL_UDP:
-       case NAT_PROTOCOL_TCP:
-         *lookup_sport = ((tcp_udp_header_t *) l4_header)->dst_port;
-         *lookup_dport = ((tcp_udp_header_t *) l4_header)->src_port;
-         break;
-       default:
-         return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL;
-       }
-    }
-  return 0;
-}
-
-/**
- * @brief Check if packet should be translated
- *
- * Packets aimed at outside interface and external address with active session
- * should be translated.
- *
- * @param sm            NAT main
- * @param rt            NAT runtime data
- * @param sw_if_index0  index of the inside interface
- * @param ip0           IPv4 header
- * @param proto0        NAT protocol
- * @param rx_fib_index0 RX FIB index
- *
- * @returns 0 if packet should be translated otherwise 1
- */
-static inline int
-snat_not_translate_fast (snat_main_t * sm, vlib_node_runtime_t * node,
-                        u32 sw_if_index0, ip4_header_t * ip0, u32 proto0,
-                        u32 rx_fib_index0)
-{
-  if (sm->out2in_dpo)
-    return 0;
-
-  fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
-  nat_outside_fib_t *outside_fib;
-  fib_prefix_t pfx = {
-    .fp_proto = FIB_PROTOCOL_IP4,
-    .fp_len = 32,
-    .fp_addr = {
-               .ip4.as_u32 = ip0->dst_address.as_u32,
-               }
-    ,
-  };
-
-  /* Don't NAT packet aimed at the intfc address */
-  if (PREDICT_FALSE (is_interface_addr (sm, node, sw_if_index0,
-                                       ip0->dst_address.as_u32)))
-    return 1;
-
-  fei = fib_table_lookup (rx_fib_index0, &pfx);
-  if (FIB_NODE_INDEX_INVALID != fei)
-    {
-      u32 sw_if_index = fib_entry_get_resolving_interface (fei);
-      if (sw_if_index == ~0)
-       {
-         vec_foreach (outside_fib, sm->outside_fibs)
-         {
-           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
-           if (FIB_NODE_INDEX_INVALID != fei)
-             {
-               sw_if_index = fib_entry_get_resolving_interface (fei);
-               if (sw_if_index != ~0)
-                 break;
-             }
-         }
-       }
-      if (sw_if_index == ~0)
-       return 1;
-
-      snat_interface_t *i;
-      /* *INDENT-OFF* */
-      pool_foreach (i, sm->interfaces)  {
-        /* NAT packet aimed at outside interface */
-       if ((nat_interface_is_outside (i)) && (sw_if_index == i->sw_if_index))
-          return 0;
-      }
-      /* *INDENT-ON* */
-    }
-
-  return 1;
-}
-
-static_always_inline u16
-snat_random_port (u16 min, u16 max)
-{
-  snat_main_t *sm = &snat_main;
-  u32 rwide;
-  u16 r;
-
-  rwide = random_u32 (&sm->random_seed);
-  r = rwide & 0xFFFF;
-  if (r >= min && r <= max)
-    return r;
-
-  return min + (rwide % (max - min + 1));
-}
-
-#endif /* __included_nat_inlines_h__ */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
index 5133ae3..3980f69 100644 (file)
@@ -48,7 +48,6 @@ class NAT44EDTestCase(VppTestCase):
 
     def plugin_enable(self):
         self.vapi.nat44_plugin_enable_disable(
-            flags=self.nat44_config_flags.NAT44_IS_ENDPOINT_DEPENDENT,
             sessions=self.max_sessions, enable=1)
 
     def plugin_disable(self):
@@ -150,7 +149,6 @@ class NAT44EDTestCase(VppTestCase):
     @classmethod
     def setUpClass(cls):
         super(NAT44EDTestCase, cls).setUpClass()
-        cls.vapi.cli("set log class nat level debug")
 
         cls.create_pg_interfaces(range(12))
         cls.interfaces = list(cls.pg_interfaces[:4])
@@ -874,7 +872,7 @@ class NAT44EDTestCase(VppTestCase):
                             self.config_flags.NAT_IS_EXT_HOST_VALID)
             self.assertTrue(sessions[0].flags &
                             self.config_flags.NAT_IS_TWICE_NAT)
-            self.logger.info(self.vapi.cli("show nat44 sessions detail"))
+            self.logger.info(self.vapi.cli("show nat44 sessions"))
             self.vapi.nat44_del_session(
                 address=sessions[0].inside_ip_address,
                 port=sessions[0].inside_port,
@@ -1978,10 +1976,10 @@ class TestNAT44EDMW(TestNAT44ED):
         self.nat_add_outside_interface(self.pg1)
 
         # in2out
-        tc1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/tcp')
-        uc1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/udp')
-        ic1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/icmp')
-        dc1 = self.get_stats_counter('/nat44/ed/in2out/slowpath/drops')
+        tc1 = self.get_stats_counter('/nat44-ed/in2out/slowpath/tcp')
+        uc1 = self.get_stats_counter('/nat44-ed/in2out/slowpath/udp')
+        ic1 = self.get_stats_counter('/nat44-ed/in2out/slowpath/icmp')
+        dc1 = self.get_stats_counter('/nat44-ed/in2out/slowpath/drops')
 
         pkts = self.create_stream_in(self.pg0, self.pg1)
         # TODO: specify worker=idx, also stats have to
@@ -1993,10 +1991,10 @@ class TestNAT44EDMW(TestNAT44ED):
         self.verify_capture_out(capture, ignore_port=True)
 
         if_idx = self.pg0.sw_if_index
-        tc2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/tcp')
-        uc2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/udp')
-        ic2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/icmp')
-        dc2 = self.get_stats_counter('/nat44/ed/in2out/slowpath/drops')
+        tc2 = self.get_stats_counter('/nat44-ed/in2out/slowpath/tcp')
+        uc2 = self.get_stats_counter('/nat44-ed/in2out/slowpath/udp')
+        ic2 = self.get_stats_counter('/nat44-ed/in2out/slowpath/icmp')
+        dc2 = self.get_stats_counter('/nat44-ed/in2out/slowpath/drops')
 
         self.assertEqual(tc2[if_idx] - tc1[if_idx], 2)
         self.assertEqual(uc2[if_idx] - uc1[if_idx], 1)
@@ -2004,10 +2002,10 @@ class TestNAT44EDMW(TestNAT44ED):
         self.assertEqual(dc2[if_idx] - dc1[if_idx], 0)
 
         # out2in
-        tc1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/tcp')
-        uc1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/udp')
-        ic1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/icmp')
-        dc1 = self.get_stats_counter('/nat44/ed/out2in/fastpath/drops')
+        tc1 = self.get_stats_counter('/nat44-ed/out2in/fastpath/tcp')
+        uc1 = self.get_stats_counter('/nat44-ed/out2in/fastpath/udp')
+        ic1 = self.get_stats_counter('/nat44-ed/out2in/fastpath/icmp')
+        dc1 = self.get_stats_counter('/nat44-ed/out2in/fastpath/drops')
 
         pkts = self.create_stream_out(self.pg1)
         self.pg1.add_stream(pkts)
@@ -2017,17 +2015,17 @@ class TestNAT44EDMW(TestNAT44ED):
         self.verify_capture_in(capture, self.pg0)
 
         if_idx = self.pg1.sw_if_index
-        tc2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/tcp')
-        uc2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/udp')
-        ic2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/icmp')
-        dc2 = self.get_stats_counter('/nat44/ed/out2in/fastpath/drops')
+        tc2 = self.get_stats_counter('/nat44-ed/out2in/fastpath/tcp')
+        uc2 = self.get_stats_counter('/nat44-ed/out2in/fastpath/udp')
+        ic2 = self.get_stats_counter('/nat44-ed/out2in/fastpath/icmp')
+        dc2 = self.get_stats_counter('/nat44-ed/out2in/fastpath/drops')
 
         self.assertEqual(tc2[if_idx] - tc1[if_idx], 2)
         self.assertEqual(uc2[if_idx] - uc1[if_idx], 1)
         self.assertEqual(ic2[if_idx] - ic1[if_idx], 1)
         self.assertEqual(dc2[if_idx] - dc1[if_idx], 0)
 
-        sc = self.get_stats_counter('/nat44/total-sessions')
+        sc = self.get_stats_counter('/nat44-ed/total-sessions')
         self.assertEqual(sc[0], 3)
 
     def test_frag_in_order(self):
@@ -2221,28 +2219,6 @@ class TestNAT44EDMW(TestNAT44ED):
 
         capture = outside.get_capture(len(stream))
 
-    def test_clear_sessions(self):
-        """ NAT44ED session clearing test """
-
-        self.nat_add_address(self.nat_addr)
-        self.nat_add_inside_interface(self.pg0)
-        self.nat_add_outside_interface(self.pg1)
-
-        pkts = self.create_stream_in(self.pg0, self.pg1)
-        self.pg0.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        capture = self.pg1.get_capture(len(pkts))
-        self.verify_capture_out(capture, ignore_port=True)
-
-        sessions = self.get_stats_counter('/nat44/total-sessions')
-        self.assertTrue(sessions[0] > 0)
-
-        self.vapi.cli("clear nat44 sessions")
-
-        sessions = self.get_stats_counter('/nat44/total-sessions')
-        self.assertEqual(sessions[0], 0)
-
     def test_show_max_translations(self):
         """ NAT44ED API test - max translations per thread """
         nat_config = self.vapi.nat_show_config_2()
@@ -3331,13 +3307,13 @@ class TestNAT44EDMW(TestNAT44ED):
 
             # in2out
             tcpn = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/tcp')
+                '/nat44-ed/in2out/slowpath/tcp')
             udpn = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/udp')
+                '/nat44-ed/in2out/slowpath/udp')
             icmpn = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/icmp')
+                '/nat44-ed/in2out/slowpath/icmp')
             drops = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/drops')
+                '/nat44-ed/in2out/slowpath/drops')
 
             pkts = self.create_stream_in(self.pg7, self.pg8)
             self.pg7.add_stream(pkts)
@@ -3348,27 +3324,27 @@ class TestNAT44EDMW(TestNAT44ED):
 
             if_idx = self.pg7.sw_if_index
             cnt = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/tcp')
+                '/nat44-ed/in2out/slowpath/tcp')
             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
             cnt = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/udp')
+                '/nat44-ed/in2out/slowpath/udp')
             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
             cnt = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/icmp')
+                '/nat44-ed/in2out/slowpath/icmp')
             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
             cnt = self.get_stats_counter(
-                '/nat44/ed/in2out/slowpath/drops')
+                '/nat44-ed/in2out/slowpath/drops')
             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
 
             # out2in
             tcpn = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/tcp')
+                '/nat44-ed/out2in/fastpath/tcp')
             udpn = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/udp')
+                '/nat44-ed/out2in/fastpath/udp')
             icmpn = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/icmp')
+                '/nat44-ed/out2in/fastpath/icmp')
             drops = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/drops')
+                '/nat44-ed/out2in/fastpath/drops')
 
             pkts = self.create_stream_out(self.pg8)
             self.pg8.add_stream(pkts)
@@ -3379,19 +3355,19 @@ class TestNAT44EDMW(TestNAT44ED):
 
             if_idx = self.pg8.sw_if_index
             cnt = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/tcp')
+                '/nat44-ed/out2in/fastpath/tcp')
             self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
             cnt = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/udp')
+                '/nat44-ed/out2in/fastpath/udp')
             self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
             cnt = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/icmp')
+                '/nat44-ed/out2in/fastpath/icmp')
             self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
             cnt = self.get_stats_counter(
-                '/nat44/ed/out2in/fastpath/drops')
+                '/nat44-ed/out2in/fastpath/drops')
             self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
 
-            sessions = self.get_stats_counter('/nat44/total-sessions')
+            sessions = self.get_stats_counter('/nat44-ed/total-sessions')
             self.assertEqual(sessions[0], 3)
 
         finally:
index 999f91e..da6ca42 100644 (file)
@@ -70,11 +70,7 @@ class MethodHolder(VppTestCase):
 
     @property
     def config_flags(self):
-        return VppEnum.vl_api_nat_config_flags_t
-
-    @property
-    def nat44_config_flags(self):
-        return VppEnum.vl_api_nat44_config_flags_t
+        return VppEnum.vl_api_nat44_ei_config_flags_t
 
     @property
     def SYSLOG_SEVERITY(self):
@@ -100,9 +96,9 @@ class MethodHolder(VppTestCase):
         """
 
         if not (local_port and external_port):
-            flags |= self.config_flags.NAT_IS_ADDR_ONLY
+            flags |= self.config_flags.NAT44_EI_ADDR_ONLY_MAPPING
 
-        self.vapi.nat44_add_del_static_mapping(
+        self.vapi.nat44_ei_add_del_static_mapping(
             is_add=is_add,
             local_ip_address=local_ip,
             external_ip_address=external_ip,
@@ -113,20 +109,17 @@ class MethodHolder(VppTestCase):
             flags=flags,
             tag=tag)
 
-    def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF, twice_nat=0):
+    def nat44_add_address(self, ip, is_add=1, vrf_id=0xFFFFFFFF):
         """
         Add/delete NAT44EI address
 
         :param ip: IP address
         :param is_add: 1 if add, 0 if delete (Default add)
-        :param twice_nat: twice NAT address for external hosts
         """
-        flags = self.config_flags.NAT_IS_TWICE_NAT if twice_nat else 0
-        self.vapi.nat44_add_del_address_range(first_ip_address=ip,
-                                              last_ip_address=ip,
-                                              vrf_id=vrf_id,
-                                              is_add=is_add,
-                                              flags=flags)
+        self.vapi.nat44_ei_add_del_address_range(first_ip_address=ip,
+                                                 last_ip_address=ip,
+                                                 vrf_id=vrf_id,
+                                                 is_add=is_add)
 
     def create_routes_and_neigbors(self):
         r1 = VppIpRoute(self, self.pg7.remote_ip4, 32,
@@ -637,11 +630,11 @@ class MethodHolder(VppTestCase):
 
     def verify_no_nat44_user(self):
         """ Verify that there is no NAT44EI user """
-        users = self.vapi.nat44_user_dump()
+        users = self.vapi.nat44_ei_user_dump()
         self.assertEqual(len(users), 0)
-        users = self.statistics.get_counter('/nat44/total-users')
+        users = self.statistics.get_counter('/nat44-ei/total-users')
         self.assertEqual(users[0][0], 0)
-        sessions = self.statistics.get_counter('/nat44/total-sessions')
+        sessions = self.statistics.get_counter('/nat44-ei/total-sessions')
         self.assertEqual(sessions[0][0], 0)
 
     def verify_syslog_apmap(self, data, is_add=True):
@@ -859,33 +852,6 @@ class MethodHolder(VppTestCase):
             self.assertEqual(data, p[Raw].load)
 
 
-class TestNAT44EIAPI(MethodHolder):
-    """ NAT44EI API Test Cases """
-
-    fq_nelts = 512
-
-    def setUp(self):
-        super(TestNAT44EIAPI, self).setUp()
-        self.vapi.nat_set_fq_options(frame_queue_nelts=self.fq_nelts)
-        self.vapi.nat44_plugin_enable_disable(enable=1)
-
-    def tearDown(self):
-        super(TestNAT44EIAPI, self).tearDown()
-        if not self.vpp_dead:
-            self.vapi.nat44_plugin_enable_disable(enable=0)
-            self.vapi.cli("clear logging")
-
-    def test_show_frame_queue_nelts(self):
-        """ API test - worker handoff frame queue elements """
-        nat_config = self.vapi.nat_show_fq_options()
-        self.assertEqual(self.fq_nelts, nat_config.frame_queue_nelts)
-        self.vapi.nat44_plugin_enable_disable(enable=0)
-        self.vapi.cli("set nat frame-queue-nelts 256")
-        self.vapi.nat44_plugin_enable_disable(enable=1)
-        nat_config = self.vapi.nat_show_fq_options()
-        self.assertEqual(256, nat_config.frame_queue_nelts)
-
-
 @tag_fixme_vpp_workers
 class TestNAT44EI(MethodHolder):
     """ NAT44EI Test Cases """
@@ -896,7 +862,7 @@ class TestNAT44EI(MethodHolder):
     @classmethod
     def setUpClass(cls):
         super(TestNAT44EI, cls).setUpClass()
-        cls.vapi.cli("set log class nat level debug")
+        cls.vapi.cli("set log class nat44-ei level debug")
 
         cls.tcp_port_in = 6303
         cls.tcp_port_out = 6303
@@ -957,39 +923,39 @@ class TestNAT44EI(MethodHolder):
         cls.pg4._remote_ip4 = cls.pg9._remote_hosts[0]._ip4 = "10.0.0.2"
         cls.pg9.resolve_arp()
 
-    def setUp(self):
-        super(TestNAT44EI, self).setUp()
-        self.vapi.nat44_plugin_enable_disable(
+    def plugin_enable(self):
+        self.vapi.nat44_ei_plugin_enable_disable(
             sessions=self.max_translations,
             users=self.max_users, enable=1)
 
+    def setUp(self):
+        super(TestNAT44EI, self).setUp()
+        self.plugin_enable()
+
     def tearDown(self):
         super(TestNAT44EI, self).tearDown()
         if not self.vpp_dead:
-            self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                               src_port=self.ipfix_src_port,
-                                               enable=0)
+            self.vapi.nat44_ei_ipfix_enable_disable(
+                domain_id=self.ipfix_domain_id, src_port=self.ipfix_src_port,
+                enable=0)
             self.ipfix_src_port = 4739
             self.ipfix_domain_id = 1
 
-            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.nat44_ei_plugin_enable_disable(enable=0)
             self.vapi.cli("clear logging")
 
     def test_clear_sessions(self):
         """ NAT44EI session clearing test """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
-        nat_config = self.vapi.nat_show_config()
-        self.assertEqual(0, nat_config.endpoint_dependent)
-
         pkts = self.create_stream_in(self.pg0, self.pg1)
         self.pg0.add_stream(pkts)
         self.pg_enable_capture(self.pg_interfaces)
@@ -997,32 +963,34 @@ class TestNAT44EI(MethodHolder):
         capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture)
 
-        sessions = self.statistics.get_counter('/nat44/total-sessions')
+        sessions = self.statistics.get_counter('/nat44-ei/total-sessions')
         self.assertTrue(sessions[0][0] > 0)
         self.logger.info("sessions before clearing: %s" % sessions[0][0])
 
-        self.vapi.cli("clear nat44 sessions")
+        self.vapi.cli("clear nat44 ei sessions")
 
-        sessions = self.statistics.get_counter('/nat44/total-sessions')
+        sessions = self.statistics.get_counter('/nat44-ei/total-sessions')
         self.assertEqual(sessions[0][0], 0)
         self.logger.info("sessions after clearing: %s" % sessions[0][0])
 
     def test_dynamic(self):
         """ NAT44EI dynamic translation test """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
         # in2out
-        tcpn = self.statistics.get_counter('/nat44/in2out/slowpath/tcp')[0]
-        udpn = self.statistics.get_counter('/nat44/in2out/slowpath/udp')[0]
-        icmpn = self.statistics.get_counter('/nat44/in2out/slowpath/icmp')[0]
-        drops = self.statistics.get_counter('/nat44/in2out/slowpath/drops')[0]
+        tcpn = self.statistics.get_counter('/nat44-ei/in2out/slowpath/tcp')[0]
+        udpn = self.statistics.get_counter('/nat44-ei/in2out/slowpath/udp')[0]
+        icmpn = self.statistics.get_counter(
+            '/nat44-ei/in2out/slowpath/icmp')[0]
+        drops = self.statistics.get_counter(
+            '/nat44-ei/in2out/slowpath/drops')[0]
 
         pkts = self.create_stream_in(self.pg0, self.pg1)
         self.pg0.add_stream(pkts)
@@ -1032,20 +1000,22 @@ class TestNAT44EI(MethodHolder):
         self.verify_capture_out(capture)
 
         if_idx = self.pg0.sw_if_index
-        cnt = self.statistics.get_counter('/nat44/in2out/slowpath/tcp')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/in2out/slowpath/tcp')[0]
         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
-        cnt = self.statistics.get_counter('/nat44/in2out/slowpath/udp')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/in2out/slowpath/udp')[0]
         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
-        cnt = self.statistics.get_counter('/nat44/in2out/slowpath/icmp')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/in2out/slowpath/icmp')[0]
         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
-        cnt = self.statistics.get_counter('/nat44/in2out/slowpath/drops')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/in2out/slowpath/drops')[0]
         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
 
         # out2in
-        tcpn = self.statistics.get_counter('/nat44/out2in/slowpath/tcp')[0]
-        udpn = self.statistics.get_counter('/nat44/out2in/slowpath/udp')[0]
-        icmpn = self.statistics.get_counter('/nat44/out2in/slowpath/icmp')[0]
-        drops = self.statistics.get_counter('/nat44/out2in/slowpath/drops')[0]
+        tcpn = self.statistics.get_counter('/nat44-ei/out2in/slowpath/tcp')[0]
+        udpn = self.statistics.get_counter('/nat44-ei/out2in/slowpath/udp')[0]
+        icmpn = self.statistics.get_counter(
+            '/nat44-ei/out2in/slowpath/icmp')[0]
+        drops = self.statistics.get_counter(
+            '/nat44-ei/out2in/slowpath/drops')[0]
 
         pkts = self.create_stream_out(self.pg1)
         self.pg1.add_stream(pkts)
@@ -1055,29 +1025,29 @@ class TestNAT44EI(MethodHolder):
         self.verify_capture_in(capture, self.pg0)
 
         if_idx = self.pg1.sw_if_index
-        cnt = self.statistics.get_counter('/nat44/out2in/slowpath/tcp')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/out2in/slowpath/tcp')[0]
         self.assertEqual(cnt[if_idx] - tcpn[if_idx], 2)
-        cnt = self.statistics.get_counter('/nat44/out2in/slowpath/udp')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/out2in/slowpath/udp')[0]
         self.assertEqual(cnt[if_idx] - udpn[if_idx], 1)
-        cnt = self.statistics.get_counter('/nat44/out2in/slowpath/icmp')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/out2in/slowpath/icmp')[0]
         self.assertEqual(cnt[if_idx] - icmpn[if_idx], 1)
-        cnt = self.statistics.get_counter('/nat44/out2in/slowpath/drops')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/out2in/slowpath/drops')[0]
         self.assertEqual(cnt[if_idx] - drops[if_idx], 0)
 
-        users = self.statistics.get_counter('/nat44/total-users')
+        users = self.statistics.get_counter('/nat44-ei/total-users')
         self.assertEqual(users[0][0], 1)
-        sessions = self.statistics.get_counter('/nat44/total-sessions')
+        sessions = self.statistics.get_counter('/nat44-ei/total-sessions')
         self.assertEqual(sessions[0][0], 3)
 
     def test_dynamic_icmp_errors_in2out_ttl_1(self):
         """ NAT44EI handling of client packets with TTL=1 """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1095,11 +1065,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI handling of server packets with TTL=1 """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1127,11 +1097,11 @@ class TestNAT44EI(MethodHolder):
         """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1159,11 +1129,11 @@ class TestNAT44EI(MethodHolder):
         """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1198,11 +1168,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI ping out interface from outside network """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1229,11 +1199,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI ping internal host from outside network """
 
         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1262,23 +1232,23 @@ class TestNAT44EI(MethodHolder):
     def test_forwarding(self):
         """ NAT44EI forwarding test """
 
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        self.vapi.nat44_forwarding_enable_disable(enable=1)
+        self.vapi.nat44_ei_forwarding_enable_disable(enable=1)
 
         real_ip = self.pg0.remote_ip4
         alias_ip = self.nat_addr
-        flags = self.config_flags.NAT_IS_ADDR_ONLY
-        self.vapi.nat44_add_del_static_mapping(is_add=1,
-                                               local_ip_address=real_ip,
-                                               external_ip_address=alias_ip,
-                                               external_sw_if_index=0xFFFFFFFF,
-                                               flags=flags)
+        flags = self.config_flags.NAT44_EI_ADDR_ONLY_MAPPING
+        self.vapi.nat44_ei_add_del_static_mapping(
+            is_add=1, local_ip_address=real_ip,
+            external_ip_address=alias_ip,
+            external_sw_if_index=0xFFFFFFFF,
+            flags=flags)
 
         try:
             # static mapping match
@@ -1322,9 +1292,9 @@ class TestNAT44EI(MethodHolder):
                 self.pg0.remote_hosts[0] = host0
 
         finally:
-            self.vapi.nat44_forwarding_enable_disable(enable=0)
-            flags = self.config_flags.NAT_IS_ADDR_ONLY
-            self.vapi.nat44_add_del_static_mapping(
+            self.vapi.nat44_ei_forwarding_enable_disable(enable=0)
+            flags = self.config_flags.NAT44_EI_ADDR_ONLY_MAPPING
+            self.vapi.nat44_ei_add_del_static_mapping(
                 is_add=0,
                 local_ip_address=real_ip,
                 external_ip_address=alias_ip,
@@ -1340,14 +1310,14 @@ class TestNAT44EI(MethodHolder):
         self.icmp_id_out = 6305
 
         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        sm = self.vapi.nat44_static_mapping_dump()
+        sm = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(len(sm), 1)
         self.assertEqual(sm[0].tag, '')
         self.assertEqual(sm[0].protocol, 0)
@@ -1380,14 +1350,14 @@ class TestNAT44EI(MethodHolder):
         tag = "testTAG"
 
         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip, tag=tag)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        sm = self.vapi.nat44_static_mapping_dump()
+        sm = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(len(sm), 1)
         self.assertEqual(sm[0].tag, tag)
 
@@ -1424,11 +1394,11 @@ class TestNAT44EI(MethodHolder):
         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
                                       self.icmp_id_in, self.icmp_id_out,
                                       proto=IP_PROTOS.icmp)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1465,11 +1435,11 @@ class TestNAT44EI(MethodHolder):
         self.nat44_add_static_mapping(self.pg0.remote_ip4, self.nat_addr,
                                       self.icmp_id_in, self.icmp_id_out,
                                       proto=IP_PROTOS.icmp)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1502,14 +1472,14 @@ class TestNAT44EI(MethodHolder):
                                       vrf_id=10)
         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip2,
                                       vrf_id=10)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg3.sw_if_index,
             is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg4.sw_if_index,
             flags=flags, is_add=1)
 
@@ -1537,11 +1507,11 @@ class TestNAT44EI(MethodHolder):
         self.icmp_id_out = 6305
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1555,7 +1525,7 @@ class TestNAT44EI(MethodHolder):
 
         # 1:1NAT
         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
-        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
+        sessions = self.vapi.nat44_ei_user_session_dump(self.pg0.remote_ip4, 0)
         self.assertEqual(len(sessions), 0)
         pkts = self.create_stream_in(self.pg0, self.pg1)
         self.pg0.add_stream(pkts)
@@ -1566,15 +1536,15 @@ class TestNAT44EI(MethodHolder):
 
     def test_identity_nat(self):
         """ NAT44EI Identity NAT """
-        flags = self.config_flags.NAT_IS_ADDR_ONLY
-        self.vapi.nat44_add_del_identity_mapping(
+        flags = self.config_flags.NAT44_EI_ADDR_ONLY_MAPPING
+        self.vapi.nat44_ei_add_del_identity_mapping(
             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
             flags=flags, is_add=1)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1598,13 +1568,13 @@ class TestNAT44EI(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
+        sessions = self.vapi.nat44_ei_user_session_dump(self.pg0.remote_ip4, 0)
         self.assertEqual(len(sessions), 0)
-        flags = self.config_flags.NAT_IS_ADDR_ONLY
-        self.vapi.nat44_add_del_identity_mapping(
+        flags = self.config_flags.NAT44_EI_ADDR_ONLY_MAPPING
+        self.vapi.nat44_ei_add_del_identity_mapping(
             ip_address=self.pg0.remote_ip4, sw_if_index=0xFFFFFFFF,
             flags=flags, vrf_id=1, is_add=1)
-        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        identity_mappings = self.vapi.nat44_ei_identity_mapping_dump()
         self.assertEqual(len(identity_mappings), 2)
 
     def test_multiple_inside_interfaces(self):
@@ -1612,14 +1582,14 @@ class TestNAT44EI(MethodHolder):
         """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg3.sw_if_index,
             is_add=1)
 
@@ -1677,17 +1647,17 @@ class TestNAT44EI(MethodHolder):
 
         static_nat_ip = "10.0.0.10"
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg3.sw_if_index,
             is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg4.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg5.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg6.sw_if_index,
             flags=flags, is_add=1)
         self.nat44_add_static_mapping(self.pg6.remote_ip4, static_nat_ip,
@@ -1754,12 +1724,14 @@ class TestNAT44EI(MethodHolder):
         self.verify_capture_in(capture, self.pg5)
 
         # pg5 session dump
-        addresses = self.vapi.nat44_address_dump()
+        addresses = self.vapi.nat44_ei_address_dump()
         self.assertEqual(len(addresses), 1)
-        sessions = self.vapi.nat44_user_session_dump(self.pg5.remote_ip4, 10)
+        sessions = self.vapi.nat44_ei_user_session_dump(
+            self.pg5.remote_ip4, 10)
         self.assertEqual(len(sessions), 3)
         for session in sessions:
-            self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
+            self.assertFalse(session.flags &
+                             self.config_flags.NAT44_EI_STATIC_MAPPING)
             self.assertEqual(str(session.inside_ip_address),
                              self.pg5.remote_ip4)
             self.assertEqual(session.outside_ip_address,
@@ -1791,37 +1763,39 @@ class TestNAT44EI(MethodHolder):
         self.verify_capture_in(capture, self.pg6)
 
         # general user and session dump verifications
-        users = self.vapi.nat44_user_dump()
+        users = self.vapi.nat44_ei_user_dump()
         self.assertGreaterEqual(len(users), 3)
-        addresses = self.vapi.nat44_address_dump()
+        addresses = self.vapi.nat44_ei_address_dump()
         self.assertEqual(len(addresses), 1)
         for user in users:
-            sessions = self.vapi.nat44_user_session_dump(user.ip_address,
-                                                         user.vrf_id)
+            sessions = self.vapi.nat44_ei_user_session_dump(user.ip_address,
+                                                            user.vrf_id)
             for session in sessions:
                 self.assertEqual(user.ip_address, session.inside_ip_address)
                 self.assertTrue(session.total_bytes > session.total_pkts > 0)
                 self.assertTrue(session.protocol in
                                 [IP_PROTOS.tcp, IP_PROTOS.udp,
                                  IP_PROTOS.icmp])
-                self.assertFalse(session.flags &
-                                 self.config_flags.NAT_IS_EXT_HOST_VALID)
 
         # pg4 session dump
-        sessions = self.vapi.nat44_user_session_dump(self.pg4.remote_ip4, 10)
+        sessions = self.vapi.nat44_ei_user_session_dump(
+            self.pg4.remote_ip4, 10)
         self.assertGreaterEqual(len(sessions), 4)
         for session in sessions:
-            self.assertFalse(session.flags & self.config_flags.NAT_IS_STATIC)
+            self.assertFalse(
+                session.flags & self.config_flags.NAT44_EI_STATIC_MAPPING)
             self.assertEqual(str(session.inside_ip_address),
                              self.pg4.remote_ip4)
             self.assertEqual(session.outside_ip_address,
                              addresses[0].ip_address)
 
         # pg6 session dump
-        sessions = self.vapi.nat44_user_session_dump(self.pg6.remote_ip4, 20)
+        sessions = self.vapi.nat44_ei_user_session_dump(
+            self.pg6.remote_ip4, 20)
         self.assertGreaterEqual(len(sessions), 3)
         for session in sessions:
-            self.assertTrue(session.flags & self.config_flags.NAT_IS_STATIC)
+            self.assertTrue(
+                session.flags & self.config_flags.NAT44_EI_STATIC_MAPPING)
             self.assertEqual(str(session.inside_ip_address),
                              self.pg6.remote_ip4)
             self.assertEqual(str(session.outside_ip_address),
@@ -1841,11 +1815,11 @@ class TestNAT44EI(MethodHolder):
         server_out_port = 8765
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -1854,7 +1828,7 @@ class TestNAT44EI(MethodHolder):
                                       server_in_port, server_out_port,
                                       proto=IP_PROTOS.tcp)
 
-        cnt = self.statistics.get_counter('/nat44/hairpinning')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/hairpinning')[0]
         # send packet from host to server
         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
              IP(src=host.ip4, dst=self.nat_addr) /
@@ -1877,7 +1851,7 @@ class TestNAT44EI(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        after = self.statistics.get_counter('/nat44/hairpinning')[0]
+        after = self.statistics.get_counter('/nat44-ei/hairpinning')[0]
         if_idx = self.pg0.sw_if_index
         self.assertEqual(after[if_idx] - cnt[if_idx], 1)
 
@@ -1902,7 +1876,7 @@ class TestNAT44EI(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        after = self.statistics.get_counter('/nat44/hairpinning')[0]
+        after = self.statistics.get_counter('/nat44-ei/hairpinning')[0]
         if_idx = self.pg0.sw_if_index
         self.assertEqual(after[if_idx] - cnt[if_idx], 2)
 
@@ -1918,11 +1892,11 @@ class TestNAT44EI(MethodHolder):
         server_udp_port = 20
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -2077,7 +2051,7 @@ class TestNAT44EI(MethodHolder):
                 raise
 
     def test_hairpinning_avoid_inf_loop(self):
-        """ NAT44 hairpinning - 1:1 NAPT avoid infinite loop """
+        """ NAT44EI hairpinning - 1:1 NAPT avoid infinite loop """
 
         host = self.pg0.remote_hosts[0]
         server = self.pg0.remote_hosts[1]
@@ -2087,11 +2061,11 @@ class TestNAT44EI(MethodHolder):
         server_out_port = 8765
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -2112,7 +2086,7 @@ class TestNAT44EI(MethodHolder):
         self.pg_start()
         # Here VPP used to crash due to an infinite loop
 
-        cnt = self.statistics.get_counter('/nat44/hairpinning')[0]
+        cnt = self.statistics.get_counter('/nat44-ei/hairpinning')[0]
         # send packet from host to server
         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
              IP(src=host.ip4, dst=self.nat_addr) /
@@ -2135,7 +2109,7 @@ class TestNAT44EI(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        after = self.statistics.get_counter('/nat44/hairpinning')[0]
+        after = self.statistics.get_counter('/nat44-ei/hairpinning')[0]
         if_idx = self.pg0.sw_if_index
         self.assertEqual(after[if_idx] - cnt[if_idx], 1)
 
@@ -2160,36 +2134,36 @@ class TestNAT44EI(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        after = self.statistics.get_counter('/nat44/hairpinning')[0]
+        after = self.statistics.get_counter('/nat44-ei/hairpinning')[0]
         if_idx = self.pg0.sw_if_index
         self.assertEqual(after[if_idx] - cnt[if_idx], 2)
 
     def test_interface_addr(self):
         """ NAT44EI acquire addresses from interface """
-        self.vapi.nat44_add_del_interface_addr(
+        self.vapi.nat44_ei_add_del_interface_addr(
             is_add=1,
             sw_if_index=self.pg7.sw_if_index)
 
         # no address in NAT pool
-        addresses = self.vapi.nat44_address_dump()
+        addresses = self.vapi.nat44_ei_address_dump()
         self.assertEqual(0, len(addresses))
 
         # configure interface address and check NAT address pool
         self.pg7.config_ip4()
-        addresses = self.vapi.nat44_address_dump()
+        addresses = self.vapi.nat44_ei_address_dump()
         self.assertEqual(1, len(addresses))
         self.assertEqual(str(addresses[0].ip_address), self.pg7.local_ip4)
 
         # remove interface address and check NAT address pool
         self.pg7.unconfig_ip4()
-        addresses = self.vapi.nat44_address_dump()
+        addresses = self.vapi.nat44_ei_address_dump()
         self.assertEqual(0, len(addresses))
 
     def test_interface_addr_static_mapping(self):
         """ NAT44EI Static mapping with addresses from interface """
         tag = "testTAG"
 
-        self.vapi.nat44_add_del_interface_addr(
+        self.vapi.nat44_ei_add_del_interface_addr(
             is_add=1,
             sw_if_index=self.pg7.sw_if_index)
         self.nat44_add_static_mapping(
@@ -2198,7 +2172,7 @@ class TestNAT44EI(MethodHolder):
             tag=tag)
 
         # static mappings with external interface
-        static_mappings = self.vapi.nat44_static_mapping_dump()
+        static_mappings = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(1, len(static_mappings))
         self.assertEqual(self.pg7.sw_if_index,
                          static_mappings[0].external_sw_if_index)
@@ -2206,7 +2180,7 @@ class TestNAT44EI(MethodHolder):
 
         # configure interface address and check static mappings
         self.pg7.config_ip4()
-        static_mappings = self.vapi.nat44_static_mapping_dump()
+        static_mappings = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(2, len(static_mappings))
         resolved = False
         for sm in static_mappings:
@@ -2219,7 +2193,7 @@ class TestNAT44EI(MethodHolder):
 
         # remove interface address and check static mappings
         self.pg7.unconfig_ip4()
-        static_mappings = self.vapi.nat44_static_mapping_dump()
+        static_mappings = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(1, len(static_mappings))
         self.assertEqual(self.pg7.sw_if_index,
                          static_mappings[0].external_sw_if_index)
@@ -2227,7 +2201,7 @@ class TestNAT44EI(MethodHolder):
 
         # configure interface address again and check static mappings
         self.pg7.config_ip4()
-        static_mappings = self.vapi.nat44_static_mapping_dump()
+        static_mappings = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(2, len(static_mappings))
         resolved = False
         for sm in static_mappings:
@@ -2244,17 +2218,17 @@ class TestNAT44EI(MethodHolder):
             external_sw_if_index=self.pg7.sw_if_index,
             tag=tag,
             is_add=0)
-        static_mappings = self.vapi.nat44_static_mapping_dump()
+        static_mappings = self.vapi.nat44_ei_static_mapping_dump()
         self.assertEqual(0, len(static_mappings))
 
     def test_interface_addr_identity_nat(self):
         """ NAT44EI Identity NAT with addresses from interface """
 
         port = 53053
-        self.vapi.nat44_add_del_interface_addr(
+        self.vapi.nat44_ei_add_del_interface_addr(
             is_add=1,
             sw_if_index=self.pg7.sw_if_index)
-        self.vapi.nat44_add_del_identity_mapping(
+        self.vapi.nat44_ei_add_del_identity_mapping(
             ip_address=b'0',
             sw_if_index=self.pg7.sw_if_index,
             port=port,
@@ -2262,14 +2236,14 @@ class TestNAT44EI(MethodHolder):
             is_add=1)
 
         # identity mappings with external interface
-        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        identity_mappings = self.vapi.nat44_ei_identity_mapping_dump()
         self.assertEqual(1, len(identity_mappings))
         self.assertEqual(self.pg7.sw_if_index,
                          identity_mappings[0].sw_if_index)
 
         # configure interface address and check identity mappings
         self.pg7.config_ip4()
-        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        identity_mappings = self.vapi.nat44_ei_identity_mapping_dump()
         resolved = False
         self.assertEqual(2, len(identity_mappings))
         for sm in identity_mappings:
@@ -2283,7 +2257,7 @@ class TestNAT44EI(MethodHolder):
 
         # remove interface address and check identity mappings
         self.pg7.unconfig_ip4()
-        identity_mappings = self.vapi.nat44_identity_mapping_dump()
+        identity_mappings = self.vapi.nat44_ei_identity_mapping_dump()
         self.assertEqual(1, len(identity_mappings))
         self.assertEqual(self.pg7.sw_if_index,
                          identity_mappings[0].sw_if_index)
@@ -2295,11 +2269,11 @@ class TestNAT44EI(MethodHolder):
         collector_port = 30303
         bind_layers(UDP, IPFIX, dport=30303)
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
@@ -2307,9 +2281,9 @@ class TestNAT44EI(MethodHolder):
                                      path_mtu=512,
                                      template_interval=10,
                                      collector_port=collector_port)
-        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                           src_port=self.ipfix_src_port,
-                                           enable=1)
+        self.vapi.nat44_ei_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
+                                                src_port=self.ipfix_src_port,
+                                                enable=1)
 
         pkts = self.create_stream_in(self.pg0, self.pg1)
         self.pg0.add_stream(pkts)
@@ -2340,20 +2314,20 @@ class TestNAT44EI(MethodHolder):
 
     def test_ipfix_addr_exhausted(self):
         """ NAT44EI IPFIX logging NAT addresses exhausted """
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
         self.vapi.set_ipfix_exporter(collector_address=self.pg3.remote_ip4,
                                      src_address=self.pg3.local_ip4,
                                      path_mtu=512,
                                      template_interval=10)
-        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                           src_port=self.ipfix_src_port,
-                                           enable=1)
+        self.vapi.nat44_ei_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
+                                                src_port=self.ipfix_src_port,
+                                                enable=1)
 
         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
@@ -2386,11 +2360,11 @@ class TestNAT44EI(MethodHolder):
     def test_ipfix_max_sessions(self):
         """ NAT44EI IPFIX logging maximum session entries exceeded """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -2412,9 +2386,9 @@ class TestNAT44EI(MethodHolder):
                                      src_address=self.pg3.local_ip4,
                                      path_mtu=512,
                                      template_interval=10)
-        self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                           src_port=self.ipfix_src_port,
-                                           enable=1)
+        self.vapi.nat44_ei_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
+                                                src_port=self.ipfix_src_port,
+                                                enable=1)
 
         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
@@ -2450,11 +2424,11 @@ class TestNAT44EI(MethodHolder):
             self.SYSLOG_SEVERITY.SYSLOG_API_SEVERITY_INFO)
         self.vapi.syslog_set_sender(self.pg3.local_ip4, self.pg3.remote_ip4)
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -2479,11 +2453,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI add pool addresses to FIB """
         static_addr = '10.0.0.10'
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
         self.nat44_add_static_mapping(self.pg0.remote_ip4, static_addr)
@@ -2561,14 +2535,14 @@ class TestNAT44EI(MethodHolder):
 
         self.nat44_add_address(nat_ip1, vrf_id=vrf_id1)
         self.nat44_add_address(nat_ip2, vrf_id=vrf_id2)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg2.sw_if_index,
             is_add=1)
 
@@ -2609,14 +2583,14 @@ class TestNAT44EI(MethodHolder):
 
         self.nat44_add_address(nat_ip1)
         self.nat44_add_address(nat_ip2, vrf_id=99)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg2.sw_if_index,
             is_add=1)
 
@@ -2640,11 +2614,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI interfaces without configured IP address """
         self.create_routes_and_neigbors()
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg7.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg8.sw_if_index,
             is_add=1)
 
@@ -2669,11 +2643,11 @@ class TestNAT44EI(MethodHolder):
 
         self.create_routes_and_neigbors()
         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg7.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg8.sw_if_index,
             is_add=1)
 
@@ -2711,11 +2685,11 @@ class TestNAT44EI(MethodHolder):
         self.nat44_add_static_mapping(self.pg7.remote_ip4, self.nat_addr,
                                       self.icmp_id_in, self.icmp_id_out,
                                       proto=IP_PROTOS.icmp)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg7.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg8.sw_if_index,
             is_add=1)
 
@@ -2739,11 +2713,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI 1:1 translate packet with unknown protocol """
         nat_ip = "10.0.0.10"
         self.nat44_add_static_mapping(self.pg0.remote_ip4, nat_ip)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -2799,11 +2773,11 @@ class TestNAT44EI(MethodHolder):
 
         self.nat44_add_static_mapping(host.ip4, host_nat_ip)
         self.nat44_add_static_mapping(server.ip4, server_nat_ip)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -2850,14 +2824,14 @@ class TestNAT44EI(MethodHolder):
     def test_output_feature(self):
         """ NAT44EI output feature (in2out postrouting) """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_output_feature(
+        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_interface_add_del_output_feature(
+        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_interface_add_del_output_feature(
+        self.vapi.nat44_ei_interface_add_del_output_feature(
             is_add=1,
             sw_if_index=self.pg3.sw_if_index)
 
@@ -2903,14 +2877,14 @@ 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.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_output_feature(
+        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_interface_add_del_output_feature(
+        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_interface_add_del_output_feature(
+        self.vapi.nat44_ei_interface_add_del_output_feature(
             is_add=1,
             sw_if_index=self.pg3.sw_if_index)
 
@@ -2956,11 +2930,11 @@ class TestNAT44EI(MethodHolder):
         server_out_port = 8765
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_output_feature(
+        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_interface_add_del_output_feature(
+        self.vapi.nat44_ei_interface_add_del_output_feature(
             is_add=1,
             sw_if_index=self.pg1.sw_if_index)
 
@@ -3019,11 +2993,11 @@ class TestNAT44EI(MethodHolder):
         external_port = 0
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg9.sw_if_index,
             is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg9.sw_if_index,
             flags=flags, is_add=1)
 
@@ -3071,20 +3045,20 @@ class TestNAT44EI(MethodHolder):
             raise
 
         err = self.statistics.get_err_counter(
-            '/err/nat44-classify/next in2out')
+            '/err/nat44-ei-classify/next in2out')
         self.assertEqual(err, 1)
         err = self.statistics.get_err_counter(
-            '/err/nat44-classify/next out2in')
+            '/err/nat44-ei-classify/next out2in')
         self.assertEqual(err, 1)
 
     def test_del_session(self):
         """ NAT44EI delete session """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -3094,24 +3068,28 @@ class TestNAT44EI(MethodHolder):
         self.pg_start()
         self.pg1.get_capture(len(pkts))
 
-        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
+        sessions = self.vapi.nat44_ei_user_session_dump(self.pg0.remote_ip4, 0)
         nsessions = len(sessions)
 
-        self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
-                                    port=sessions[0].inside_port,
-                                    protocol=sessions[0].protocol,
-                                    flags=self.config_flags.NAT_IS_INSIDE)
-        self.vapi.nat44_del_session(address=sessions[1].outside_ip_address,
-                                    port=sessions[1].outside_port,
-                                    protocol=sessions[1].protocol)
+        self.vapi.nat44_ei_del_session(
+            address=sessions[0].inside_ip_address,
+            port=sessions[0].inside_port,
+            protocol=sessions[0].protocol,
+            flags=self.config_flags.NAT44_EI_IF_INSIDE)
 
-        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0)
+        self.vapi.nat44_ei_del_session(
+            address=sessions[1].outside_ip_address,
+            port=sessions[1].outside_port,
+            protocol=sessions[1].protocol)
+
+        sessions = self.vapi.nat44_ei_user_session_dump(self.pg0.remote_ip4, 0)
         self.assertEqual(nsessions - len(sessions), 2)
 
-        self.vapi.nat44_del_session(address=sessions[0].inside_ip_address,
-                                    port=sessions[0].inside_port,
-                                    protocol=sessions[0].protocol,
-                                    flags=self.config_flags.NAT_IS_INSIDE)
+        self.vapi.nat44_ei_del_session(
+            address=sessions[0].inside_ip_address,
+            port=sessions[0].inside_port,
+            protocol=sessions[0].protocol,
+            flags=self.config_flags.NAT44_EI_IF_INSIDE)
 
         self.verify_no_nat44_user()
 
@@ -3119,11 +3097,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI translate fragments arriving in order """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -3133,17 +3111,17 @@ class TestNAT44EI(MethodHolder):
 
     def test_frag_forwarding(self):
         """ NAT44EI forwarding fragment test """
-        self.vapi.nat44_add_del_interface_addr(
+        self.vapi.nat44_ei_add_del_interface_addr(
             is_add=1,
             sw_if_index=self.pg1.sw_if_index)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        self.vapi.nat44_forwarding_enable_disable(enable=1)
+        self.vapi.nat44_ei_forwarding_enable_disable(enable=1)
 
         data = b"A" * 16 + b"B" * 16 + b"C" * 3
         pkts = self.create_stream_frag(self.pg1,
@@ -3172,11 +3150,11 @@ class TestNAT44EI(MethodHolder):
         server_out_port = random.randint(1025, 65535)
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
         # add static mapping for server
@@ -3201,11 +3179,11 @@ class TestNAT44EI(MethodHolder):
         """ NAT44EI translate fragments arriving out of order """
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -3216,17 +3194,17 @@ class TestNAT44EI(MethodHolder):
     def test_port_restricted(self):
         """ NAT44EI Port restricted NAT44EI (MAP-E CE) """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        self.vapi.nat_set_addr_and_port_alloc_alg(alg=1,
-                                                  psid_offset=6,
-                                                  psid_length=6,
-                                                  psid=10)
+        self.vapi.nat44_ei_set_addr_and_port_alloc_alg(alg=1,
+                                                       psid_offset=6,
+                                                       psid_length=6,
+                                                       psid=10)
 
         p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
              IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
@@ -3252,16 +3230,16 @@ class TestNAT44EI(MethodHolder):
     def test_port_range(self):
         """ NAT44EI External address port range """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        self.vapi.nat_set_addr_and_port_alloc_alg(alg=2,
-                                                  start_port=1025,
-                                                  end_port=1027)
+        self.vapi.nat44_ei_set_addr_and_port_alloc_alg(alg=2,
+                                                       start_port=1025,
+                                                       end_port=1027)
 
         pkts = []
         for port in range(0, 5):
@@ -3295,14 +3273,14 @@ class TestNAT44EI(MethodHolder):
         self.pg2.resolve_arp()
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg2.sw_if_index,
             is_add=1)
 
@@ -3355,11 +3333,11 @@ class TestNAT44EI(MethodHolder):
     def test_mss_clamping(self):
         """ NAT44EI TCP MSS clamping """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -3368,7 +3346,7 @@ class TestNAT44EI(MethodHolder):
              TCP(sport=self.tcp_port_in, dport=self.tcp_external_port,
                  flags="S", options=[('MSS', 1400)]))
 
-        self.vapi.nat_set_mss_clamping(enable=1, mss_value=1000)
+        self.vapi.nat44_ei_set_mss_clamping(enable=1, mss_value=1000)
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -3376,7 +3354,7 @@ class TestNAT44EI(MethodHolder):
         # Negotiated MSS value greater than configured - changed
         self.verify_mss_value(capture[0], 1000)
 
-        self.vapi.nat_set_mss_clamping(enable=0, mss_value=1500)
+        self.vapi.nat44_ei_set_mss_clamping(enable=0, mss_value=1500)
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -3384,7 +3362,7 @@ class TestNAT44EI(MethodHolder):
         # MSS clamping disabled - negotiated MSS unchanged
         self.verify_mss_value(capture[0], 1400)
 
-        self.vapi.nat_set_mss_clamping(enable=1, mss_value=1500)
+        self.vapi.nat44_ei_set_mss_clamping(enable=1, mss_value=1500)
         self.pg0.add_stream(p)
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
@@ -3394,20 +3372,20 @@ class TestNAT44EI(MethodHolder):
 
     def test_ha_send(self):
         """ NAT44EI Send HA session synchronization events (active) """
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
         self.nat44_add_address(self.nat_addr)
 
-        self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
-                                      port=12345,
-                                      path_mtu=512)
-        self.vapi.nat_ha_set_failover(ip_address=self.pg3.remote_ip4,
-                                      port=12346, session_refresh_interval=10)
+        self.vapi.nat44_ei_ha_set_listener(
+            ip_address=self.pg3.local_ip4, port=12345, path_mtu=512)
+        self.vapi.nat44_ei_ha_set_failover(
+            ip_address=self.pg3.remote_ip4, port=12346,
+            session_refresh_interval=10)
         bind_layers(UDP, HANATStateSync, sport=12345)
 
         # create sessions
@@ -3418,8 +3396,8 @@ class TestNAT44EI(MethodHolder):
         capture = self.pg1.get_capture(len(pkts))
         self.verify_capture_out(capture)
         # active send HA events
-        self.vapi.nat_ha_flush()
-        stats = self.statistics.get_counter('/nat44/ha/add-event-send')
+        self.vapi.nat44_ei_ha_flush()
+        stats = self.statistics.get_counter('/nat44-ei/ha/add-event-send')
         self.assertEqual(stats[0][0], 3)
         capture = self.pg3.get_capture(1)
         p = capture[0]
@@ -3453,17 +3431,16 @@ class TestNAT44EI(MethodHolder):
                HANATStateSync(sequence_number=seq, flags='ACK'))
         self.pg3.add_stream(ack)
         self.pg_start()
-        stats = self.statistics.get_counter('/nat44/ha/ack-recv')
+        stats = self.statistics.get_counter('/nat44-ei/ha/ack-recv')
         self.assertEqual(stats[0][0], 1)
 
         # delete one session
         self.pg_enable_capture(self.pg_interfaces)
-        self.vapi.nat44_del_session(address=self.pg0.remote_ip4,
-                                    port=self.tcp_port_in,
-                                    protocol=IP_PROTOS.tcp,
-                                    flags=self.config_flags.NAT_IS_INSIDE)
-        self.vapi.nat_ha_flush()
-        stats = self.statistics.get_counter('/nat44/ha/del-event-send')
+        self.vapi.nat44_ei_del_session(
+            address=self.pg0.remote_ip4, port=self.tcp_port_in,
+            protocol=IP_PROTOS.tcp, flags=self.config_flags.NAT44_EI_IF_INSIDE)
+        self.vapi.nat44_ei_ha_flush()
+        stats = self.statistics.get_counter('/nat44-ei/ha/del-event-send')
         self.assertEqual(stats[0][0], 1)
         capture = self.pg3.get_capture(1)
         p = capture[0]
@@ -3478,9 +3455,9 @@ class TestNAT44EI(MethodHolder):
         # do not send ACK, active retry send HA event again
         self.pg_enable_capture(self.pg_interfaces)
         sleep(12)
-        stats = self.statistics.get_counter('/nat44/ha/retry-count')
+        stats = self.statistics.get_counter('/nat44-ei/ha/retry-count')
         self.assertEqual(stats[0][0], 3)
-        stats = self.statistics.get_counter('/nat44/ha/missed-count')
+        stats = self.statistics.get_counter('/nat44-ei/ha/missed-count')
         self.assertEqual(stats[0][0], 1)
         capture = self.pg3.get_capture(3)
         for packet in capture:
@@ -3492,8 +3469,8 @@ class TestNAT44EI(MethodHolder):
         self.pg_enable_capture(self.pg_interfaces)
         self.pg_start()
         self.pg0.get_capture(2)
-        self.vapi.nat_ha_flush()
-        stats = self.statistics.get_counter('/nat44/ha/refresh-event-send')
+        self.vapi.nat44_ei_ha_flush()
+        stats = self.statistics.get_counter('/nat44-ei/ha/refresh-event-send')
         self.assertEqual(stats[0][0], 2)
         capture = self.pg3.get_capture(1)
         p = capture[0]
@@ -3526,22 +3503,21 @@ class TestNAT44EI(MethodHolder):
                HANATStateSync(sequence_number=seq, flags='ACK'))
         self.pg3.add_stream(ack)
         self.pg_start()
-        stats = self.statistics.get_counter('/nat44/ha/ack-recv')
+        stats = self.statistics.get_counter('/nat44-ei/ha/ack-recv')
         self.assertEqual(stats[0][0], 2)
 
     def test_ha_recv(self):
         """ NAT44EI Receive HA session synchronization events (passive) """
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
-        self.vapi.nat_ha_set_listener(ip_address=self.pg3.local_ip4,
-                                      port=12345,
-                                      path_mtu=512)
+        self.vapi.nat44_ei_ha_set_listener(ip_address=self.pg3.local_ip4,
+                                           port=12345, path_mtu=512)
         bind_layers(UDP, HANATStateSync, sport=12345)
 
         self.tcp_port_out = random.randint(1025, 65535)
@@ -3583,21 +3559,21 @@ class TestNAT44EI(MethodHolder):
             self.assertEqual(hanat.flags, 'ACK')
             self.assertEqual(hanat.version, 1)
             self.assertEqual(hanat.thread_index, 0)
-        stats = self.statistics.get_counter('/nat44/ha/ack-send')
+        stats = self.statistics.get_counter('/nat44-ei/ha/ack-send')
         self.assertEqual(stats[0][0], 1)
-        stats = self.statistics.get_counter('/nat44/ha/add-event-recv')
+        stats = self.statistics.get_counter('/nat44-ei/ha/add-event-recv')
         self.assertEqual(stats[0][0], 2)
-        users = self.statistics.get_counter('/nat44/total-users')
+        users = self.statistics.get_counter('/nat44-ei/total-users')
         self.assertEqual(users[0][0], 1)
-        sessions = self.statistics.get_counter('/nat44/total-sessions')
+        sessions = self.statistics.get_counter('/nat44-ei/total-sessions')
         self.assertEqual(sessions[0][0], 2)
-        users = self.vapi.nat44_user_dump()
+        users = self.vapi.nat44_ei_user_dump()
         self.assertEqual(len(users), 1)
         self.assertEqual(str(users[0].ip_address),
                          self.pg0.remote_ip4)
         # there should be 2 sessions created by HA
-        sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
-                                                     users[0].vrf_id)
+        sessions = self.vapi.nat44_ei_user_session_dump(
+            users[0].ip_address, users[0].vrf_id)
         self.assertEqual(len(sessions), 2)
         for session in sessions:
             self.assertEqual(str(session.inside_ip_address),
@@ -3638,18 +3614,19 @@ class TestNAT44EI(MethodHolder):
             self.assertEqual(hanat.sequence_number, 2)
             self.assertEqual(hanat.flags, 'ACK')
             self.assertEqual(hanat.version, 1)
-        users = self.vapi.nat44_user_dump()
+        users = self.vapi.nat44_ei_user_dump()
         self.assertEqual(len(users), 1)
         self.assertEqual(str(users[0].ip_address),
                          self.pg0.remote_ip4)
         # now we should have only 1 session, 1 deleted by HA
-        sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
-                                                     users[0].vrf_id)
+        sessions = self.vapi.nat44_ei_user_session_dump(users[0].ip_address,
+                                                        users[0].vrf_id)
         self.assertEqual(len(sessions), 1)
-        stats = self.statistics.get_counter('/nat44/ha/del-event-recv')
+        stats = self.statistics.get_counter('/nat44-ei/ha/del-event-recv')
         self.assertEqual(stats[0][0], 1)
 
-        stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
+        stats = self.statistics.get_err_counter(
+            '/err/nat44-ei-ha/pkts-processed')
         self.assertEqual(stats, 2)
 
         # send HA session refresh event to failover/passive
@@ -3680,20 +3657,22 @@ class TestNAT44EI(MethodHolder):
             self.assertEqual(hanat.sequence_number, 3)
             self.assertEqual(hanat.flags, 'ACK')
             self.assertEqual(hanat.version, 1)
-        users = self.vapi.nat44_user_dump()
+        users = self.vapi.nat44_ei_user_dump()
         self.assertEqual(len(users), 1)
         self.assertEqual(str(users[0].ip_address),
                          self.pg0.remote_ip4)
-        sessions = self.vapi.nat44_user_session_dump(users[0].ip_address,
-                                                     users[0].vrf_id)
+        sessions = self.vapi.nat44_ei_user_session_dump(
+            users[0].ip_address, users[0].vrf_id)
         self.assertEqual(len(sessions), 1)
         session = sessions[0]
         self.assertEqual(session.total_bytes, 1024)
         self.assertEqual(session.total_pkts, 2)
-        stats = self.statistics.get_counter('/nat44/ha/refresh-event-recv')
+        stats = self.statistics.get_counter(
+            '/nat44-ei/ha/refresh-event-recv')
         self.assertEqual(stats[0][0], 1)
 
-        stats = self.statistics.get_err_counter('/err/nat-ha/pkts-processed')
+        stats = self.statistics.get_err_counter(
+            '/err/nat44-ei-ha/pkts-processed')
         self.assertEqual(stats, 3)
 
         # send packet to test session created by HA
@@ -3717,17 +3696,28 @@ class TestNAT44EI(MethodHolder):
             self.assertEqual(tcp.sport, self.tcp_external_port)
             self.assertEqual(tcp.dport, self.tcp_port_in)
 
+    def reconfigure_frame_queue_nelts(self, frame_queue_nelts):
+        self.vapi.nat44_ei_plugin_enable_disable(enable=0)
+        self.vapi.nat44_ei_set_fq_options(frame_queue_nelts=frame_queue_nelts)
+        # keep plugin configuration persistent
+        self.plugin_enable()
+        return self.vapi.nat44_ei_show_fq_options().frame_queue_nelts
+
+    def test_set_frame_queue_nelts(self):
+        """ NAT44 EI API test - worker handoff frame queue elements """
+        self.assertEqual(self.reconfigure_frame_queue_nelts(512), 512)
+
     def show_commands_at_teardown(self):
-        self.logger.info(self.vapi.cli("show nat44 addresses"))
-        self.logger.info(self.vapi.cli("show nat44 interfaces"))
-        self.logger.info(self.vapi.cli("show nat44 static mappings"))
-        self.logger.info(self.vapi.cli("show nat44 interface address"))
-        self.logger.info(self.vapi.cli("show nat44 sessions detail"))
-        self.logger.info(self.vapi.cli("show nat44 hash tables detail"))
-        self.logger.info(self.vapi.cli("show nat timeouts"))
+        self.logger.info(self.vapi.cli("show nat44 ei timeouts"))
+        self.logger.info(self.vapi.cli("show nat44 ei addresses"))
+        self.logger.info(self.vapi.cli("show nat44 ei interfaces"))
+        self.logger.info(self.vapi.cli("show nat44 ei static mappings"))
+        self.logger.info(self.vapi.cli("show nat44 ei interface address"))
+        self.logger.info(self.vapi.cli("show nat44 ei sessions detail"))
+        self.logger.info(self.vapi.cli("show nat44 ei hash tables detail"))
+        self.logger.info(self.vapi.cli("show nat44 ei ha"))
         self.logger.info(
-            self.vapi.cli("show nat addr-port-assignment-alg"))
-        self.logger.info(self.vapi.cli("show nat ha"))
+            self.vapi.cli("show nat44 ei addr-port-assignment-alg"))
 
 
 class TestNAT44Out2InDPO(MethodHolder):
@@ -3736,7 +3726,7 @@ class TestNAT44Out2InDPO(MethodHolder):
     @classmethod
     def setUpClass(cls):
         super(TestNAT44Out2InDPO, cls).setUpClass()
-        cls.vapi.cli("set log class nat level debug")
+        cls.vapi.cli("set log class nat44-ei level debug")
 
         cls.tcp_port_in = 6303
         cls.tcp_port_out = 6303
@@ -3765,13 +3755,13 @@ class TestNAT44Out2InDPO(MethodHolder):
 
     def setUp(self):
         super(TestNAT44Out2InDPO, self).setUp()
-        flags = self.nat44_config_flags.NAT44_API_IS_OUT2IN_DPO
-        self.vapi.nat44_plugin_enable_disable(enable=1, flags=flags)
+        flags = self.config_flags.NAT44_EI_OUT2IN_DPO
+        self.vapi.nat44_ei_plugin_enable_disable(enable=1, flags=flags)
 
     def tearDown(self):
         super(TestNAT44Out2InDPO, self).tearDown()
         if not self.vpp_dead:
-            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.nat44_ei_plugin_enable_disable(enable=0)
             self.vapi.cli("clear logging")
 
     def configure_xlat(self):
@@ -3791,18 +3781,16 @@ class TestNAT44Out2InDPO(MethodHolder):
     def test_464xlat_ce(self):
         """ Test 464XLAT CE with NAT44EI """
 
-        nat_config = self.vapi.nat_show_config()
-        self.assertEqual(1, nat_config.out2in_dpo)
-
         self.configure_xlat()
 
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_add_del_address_range(first_ip_address=self.nat_addr_n,
-                                              last_ip_address=self.nat_addr_n,
-                                              vrf_id=0xFFFFFFFF, is_add=1)
+        self.vapi.nat44_ei_add_del_address_range(
+            first_ip_address=self.nat_addr_n,
+            last_ip_address=self.nat_addr_n,
+            vrf_id=0xFFFFFFFF, is_add=1)
 
         out_src_ip6 = self.compose_ip6(self.dst_ip4, self.dst_ip6_pfx,
                                        self.dst_ip6_pfx_len)
@@ -3826,10 +3814,10 @@ class TestNAT44Out2InDPO(MethodHolder):
             capture = self.pg0.get_capture(len(pkts))
             self.verify_capture_in(capture, self.pg0)
         finally:
-            self.vapi.nat44_interface_add_del_feature(
+            self.vapi.nat44_ei_interface_add_del_feature(
                 sw_if_index=self.pg0.sw_if_index,
                 flags=flags)
-            self.vapi.nat44_add_del_address_range(
+            self.vapi.nat44_ei_add_del_address_range(
                 first_ip_address=self.nat_addr_n,
                 last_ip_address=self.nat_addr_n,
                 vrf_id=0xFFFFFFFF)
@@ -3935,20 +3923,21 @@ class TestNAT44EIMW(MethodHolder):
 
     def setUp(self):
         super(TestNAT44EIMW, self).setUp()
-        self.vapi.nat44_plugin_enable_disable(
+        self.vapi.nat44_ei_plugin_enable_disable(
             sessions=self.max_translations,
             users=self.max_users, enable=1)
 
     def tearDown(self):
         super(TestNAT44EIMW, self).tearDown()
         if not self.vpp_dead:
-            self.vapi.nat_ipfix_enable_disable(domain_id=self.ipfix_domain_id,
-                                               src_port=self.ipfix_src_port,
-                                               enable=0)
+            self.vapi.nat44_ei_ipfix_enable_disable(
+                domain_id=self.ipfix_domain_id,
+                src_port=self.ipfix_src_port,
+                enable=0)
             self.ipfix_src_port = 4739
             self.ipfix_domain_id = 1
 
-            self.vapi.nat44_plugin_enable_disable(enable=0)
+            self.vapi.nat44_ei_plugin_enable_disable(enable=0)
             self.vapi.cli("clear logging")
 
     def test_hairpinning(self):
@@ -3964,11 +3953,11 @@ class TestNAT44EIMW(MethodHolder):
         worker_2 = 2
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -3977,7 +3966,7 @@ class TestNAT44EIMW(MethodHolder):
                                       server_in_port, server_out_port,
                                       proto=IP_PROTOS.tcp)
 
-        cnt = self.statistics.get_counter('/nat44/hairpinning')
+        cnt = self.statistics.get_counter('/nat44-ei/hairpinning')
         # send packet from host to server
         p = (Ether(src=host.mac, dst=self.pg0.local_mac) /
              IP(src=host.ip4, dst=self.nat_addr) /
@@ -4000,7 +3989,7 @@ class TestNAT44EIMW(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        after = self.statistics.get_counter('/nat44/hairpinning')
+        after = self.statistics.get_counter('/nat44-ei/hairpinning')
 
         if_idx = self.pg0.sw_if_index
         self.assertEqual(after[worker_2][if_idx] - cnt[worker_1][if_idx], 1)
@@ -4026,7 +4015,7 @@ class TestNAT44EIMW(MethodHolder):
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
-        after = self.statistics.get_counter('/nat44/hairpinning')
+        after = self.statistics.get_counter('/nat44-ei/hairpinning')
         if_idx = self.pg0.sw_if_index
         self.assertEqual(after[worker_1][if_idx] - cnt[worker_1][if_idx], 1)
         self.assertEqual(after[worker_2][if_idx] - cnt[worker_2][if_idx], 2)
@@ -4043,11 +4032,11 @@ class TestNAT44EIMW(MethodHolder):
         server_udp_port = 20
 
         self.nat44_add_address(self.nat_addr)
-        flags = self.config_flags.NAT_IS_INSIDE
-        self.vapi.nat44_interface_add_del_feature(
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg0.sw_if_index,
             flags=flags, is_add=1)
-        self.vapi.nat44_interface_add_del_feature(
+        self.vapi.nat44_ei_interface_add_del_feature(
             sw_if_index=self.pg1.sw_if_index,
             is_add=1)
 
@@ -4201,5 +4190,6 @@ class TestNAT44EIMW(MethodHolder):
                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
                 raise
 
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)