NAT44: do not create session record for identity mapping (VPP-1439)

Change-Id: I39a3146a4e4ba8eadf50af7113b9ae6b1c1d688f
Signed-off-by: Matus Fabian <matfabia@cisco.com>
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index b610650..b99aef3 100755
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -135,7 +135,7 @@
 			      &value0))
     {
       /* or is static mappings */
-      if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+      if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
 	return 0;
     }
   else
@@ -236,13 +236,14 @@
 	   vlib_node_runtime_t * node, u32 next0, u32 thread_index, f64 now)
 {
   snat_user_t *u;
-  snat_session_t *s;
+  snat_session_t *s = 0;
   clib_bihash_kv_8_8_t kv0;
   snat_session_key_t key1;
   udp_header_t *udp0 = ip4_next_header (ip0);
   u8 is_sm = 0;
   nat_outside_fib_t *outside_fib;
   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+  u8 identity_nat;
   fib_prefix_t pfx = {
     .fp_proto = FIB_PROTOCOL_IP4,
     .fp_len = 32,
@@ -263,7 +264,8 @@
   key1.protocol = key0->protocol;
 
   /* First try to match static mapping by local address and port */
-  if (snat_static_mapping_match (sm, *key0, &key1, 0, 0, 0, 0, 0))
+  if (snat_static_mapping_match
+      (sm, *key0, &key1, 0, 0, 0, 0, 0, &identity_nat))
     {
       /* Try to create dynamic translation */
       if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index0,
@@ -277,7 +279,15 @@
 	}
     }
   else
-    is_sm = 1;
+    {
+      if (PREDICT_FALSE (identity_nat))
+	{
+	  *sessionp = s;
+	  return next0;
+	}
+
+      is_sm = 1;
+    }
 
   u = nat_user_get_or_create (sm, &ip0->src_address, rx_fib_index0,
 			      thread_index);
@@ -489,6 +499,12 @@
 
       if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
 	goto out;
+
+      if (!s0)
+	{
+	  dont_translate = 1;
+	  goto out;
+	}
     }
   else
     {
@@ -558,7 +574,8 @@
     }
   key0.fib_index = rx_fib_index0;
 
-  if (snat_static_mapping_match (sm, key0, &sm0, 0, &is_addr_only, 0, 0, 0))
+  if (snat_static_mapping_match
+      (sm, key0, &sm0, 0, &is_addr_only, 0, 0, 0, 0))
     {
       if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
 						  IP_PROTOCOL_ICMP,
@@ -987,6 +1004,9 @@
 				     &s0, node, next0, thread_index, now);
 		  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
 		    goto trace00;
+
+		  if (PREDICT_FALSE (!s0))
+		    goto trace00;
 		}
 	      else
 		{
@@ -1163,6 +1183,9 @@
 				     &s1, node, next1, thread_index, now);
 		  if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP))
 		    goto trace01;
+
+		  if (PREDICT_FALSE (!s1))
+		    goto trace01;
 		}
 	      else
 		{
@@ -1374,6 +1397,9 @@
 
 		  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
 		    goto trace0;
+
+		  if (PREDICT_FALSE (!s0))
+		    goto trace0;
 		}
 	      else
 		{
@@ -1717,6 +1743,9 @@
 		  if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP))
 		    goto trace0;
 
+		  if (PREDICT_FALSE (!s0))
+		    goto trace0;
+
 		  reass0->sess_index = s0 - per_thread_data->sessions;
 		}
 	      else
@@ -1971,7 +2000,7 @@
 	  key0.port = udp0->src_port;
 	  key0.fib_index = rx_fib_index0;
 
-	  if (snat_static_mapping_match (sm, key0, &sm0, 0, 0, 0, 0, 0))
+	  if (snat_static_mapping_match (sm, key0, &sm0, 0, 0, 0, 0, 0, 0))
 	    {
 	      b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION];
 	      next0 = SNAT_IN2OUT_NEXT_DROP;
diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c
index adf0ff3..8db53c0 100644
--- a/src/plugins/nat/in2out_ed.c
+++ b/src/plugins/nat/in2out_ed.c
@@ -256,7 +256,7 @@
 	      snat_session_t ** sessionp,
 	      vlib_node_runtime_t * node, u32 next, u32 thread_index, f64 now)
 {
-  snat_session_t *s;
+  snat_session_t *s = 0;
   snat_user_t *u;
   snat_session_key_t key0, key1;
   lb_nat_type_t lb = 0, is_sm = 0;
@@ -265,6 +265,7 @@
   u32 proto = ip_proto_to_snat_proto (key->proto);
   nat_outside_fib_t *outside_fib;
   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+  u8 identity_nat;
   fib_prefix_t pfx = {
     .fp_proto = FIB_PROTOCOL_IP4,
     .fp_len = 32,
@@ -288,7 +289,8 @@
   key0.fib_index = rx_fib_index;
   key1.fib_index = sm->outside_fib_index;
   /* First try to match static mapping by local address and port */
-  if (snat_static_mapping_match (sm, key0, &key1, 0, 0, 0, &lb, 0))
+  if (snat_static_mapping_match
+      (sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat))
     {
       /* Try to create dynamic translation */
       if (snat_alloc_outside_address_and_port (sm->addresses, rx_fib_index,
@@ -302,7 +304,15 @@
 	}
     }
   else
-    is_sm = 1;
+    {
+      if (PREDICT_FALSE (identity_nat))
+	{
+	  *sessionp = s;
+	  return next;
+	}
+
+      is_sm = 1;
+    }
 
   u = nat_user_get_or_create (sm, &key->l_addr, rx_fib_index, thread_index);
   if (!u)
@@ -413,7 +423,7 @@
       key0.protocol = proto;
       key0.fib_index = sm->outside_fib_index;
       /* or is static mappings */
-      if (!snat_static_mapping_match (sm, key0, &key1, 1, 0, 0, 0, 0))
+      if (!snat_static_mapping_match (sm, key0, &key1, 1, 0, 0, 0, 0, 0))
 	return 0;
     }
   else
@@ -607,6 +617,12 @@
 
       if (PREDICT_FALSE (next == NAT_IN2OUT_ED_NEXT_DROP))
 	goto out;
+
+      if (!s)
+	{
+	  dont_translate = 1;
+	  goto out;
+	}
     }
   else
     {
@@ -1011,6 +1027,9 @@
 
 		  if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
 		    goto trace00;
+
+		  if (PREDICT_FALSE (!s0))
+		    goto trace00;
 		}
 	      else
 		{
@@ -1212,6 +1231,9 @@
 
 		  if (PREDICT_FALSE (next1 == NAT_IN2OUT_ED_NEXT_DROP))
 		    goto trace01;
+
+		  if (PREDICT_FALSE (!s1))
+		    goto trace01;
 		}
 	      else
 		{
@@ -1442,6 +1464,9 @@
 
 		  if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
 		    goto trace0;
+
+		  if (PREDICT_FALSE (!s0))
+		    goto trace0;
 		}
 	      else
 		{
@@ -1839,6 +1864,12 @@
 		  if (PREDICT_FALSE (next0 == NAT_IN2OUT_ED_NEXT_DROP))
 		    goto trace0;
 
+		  if (PREDICT_FALSE (!s0))
+		    {
+		      reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
+		      goto trace0;
+		    }
+
 		  reass0->sess_index = s0 - per_thread_data->sessions;
 		}
 	      else
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index 0818332..ae2e64e 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -583,7 +583,9 @@
 				       u16 e_port,
 				       u32 vrf_id,
 				       snat_protocol_t proto,
-				       int addr_only, int is_add, u8 * tag)
+				       int addr_only, int is_add, u8 * tag,
+				       int twice_nat, int out2in_only,
+				       int identity_nat)
 {
   snat_static_map_resolve_t *rp;
 
@@ -596,6 +598,9 @@
   rp->proto = proto;
   rp->addr_only = addr_only;
   rp->is_add = is_add;
+  rp->twice_nat = twice_nat;
+  rp->out2in_only = out2in_only;
+  rp->identity_nat = identity_nat;
   rp->tag = vec_dup (tag);
 }
 
@@ -613,34 +618,12 @@
   return thread_idx;
 }
 
-/**
- * @brief Add static mapping.
- *
- * Create static mapping between local addr+port and external addr+port.
- *
- * @param l_addr Local IPv4 address.
- * @param e_addr External IPv4 address.
- * @param l_port Local port number.
- * @param e_port External port number.
- * @param vrf_id VRF ID.
- * @param addr_only If 0 address port and pair mapping, otherwise address only.
- * @param sw_if_index External port instead of specific IP address.
- * @param is_add If 0 delete static mapping, otherwise add.
- * @param twice_nat If value is TWICE_NAT then translate external host address
- *                  and port.
- *                  If value is TWICE_NAT_SELF then translate external host
- *                  address and port whenever external host address equals
- *                  local address of internal host.
- * @param out2in_only If 1 rule match only out2in direction
- * @param tag - opaque string tag
- *
- * @returns
- */
 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, snat_protocol_t proto, int is_add,
-			 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag)
+			 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
+			 u8 identity_nat)
 {
   snat_main_t *sm = &snat_main;
   snat_static_mapping_t *m;
@@ -702,7 +685,7 @@
 
 	  snat_add_static_mapping_when_resolved
 	    (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
-	     addr_only, is_add, tag);
+	     addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
 
 	  /* DHCP resolution required? */
 	  if (first_int_addr == 0)
@@ -842,11 +825,15 @@
       m->tag = vec_dup (tag);
       m->local_addr = l_addr;
       m->external_addr = e_addr;
-      m->addr_only = addr_only;
       m->vrf_id = vrf_id;
       m->fib_index = fib_index;
       m->twice_nat = twice_nat;
-      m->out2in_only = out2in_only;
+      if (out2in_only)
+	m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
+      if (addr_only)
+	m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
+      if (identity_nat)
+	m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
       if (!addr_only)
 	{
 	  m->local_port = l_port;
@@ -1147,11 +1134,11 @@
       memset (m, 0, sizeof (*m));
       m->tag = vec_dup (tag);
       m->external_addr = e_addr;
-      m->addr_only = 0;
       m->external_port = e_port;
       m->proto = proto;
       m->twice_nat = twice_nat;
-      m->out2in_only = out2in_only;
+      if (out2in_only)
+	m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
       m->affinity = affinity;
 
       if (affinity)
@@ -1368,9 +1355,9 @@
           if (m->external_addr.as_u32 == addr.as_u32)
             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
                                             m->local_port, m->external_port,
-                                            m->vrf_id, m->addr_only, ~0,
+                                            m->vrf_id, is_addr_only_static_mapping(m), ~0,
                                             m->proto, 0, m->twice_nat,
-                                            m->out2in_only, m->tag);
+                                            is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
       }));
       /* *INDENT-ON* */
     }
@@ -1682,7 +1669,7 @@
 
   pool_foreach (m, sm->static_mappings,
   ({
-    if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
+    if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
       continue;
 
     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
@@ -1810,7 +1797,7 @@
 
   pool_foreach (m, sm->static_mappings,
   ({
-    if (!(m->addr_only)  || (m->local_addr.as_u32 == m->external_addr.as_u32))
+    if (!((is_addr_only_static_mapping(m)))  || (m->local_addr.as_u32 == m->external_addr.as_u32))
       continue;
 
     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
@@ -2017,7 +2004,8 @@
 			   u8 by_external,
 			   u8 * is_addr_only,
 			   twice_nat_type_t * twice_nat,
-			   lb_nat_type_t * lb, ip4_address_t * ext_host_addr)
+			   lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
+			   u8 * is_identity_nat)
 {
   clib_bihash_kv_8_8_t kv, value;
   snat_static_mapping_t *m;
@@ -2108,7 +2096,7 @@
 	  mapping->fib_index = m->fib_index;
 	  mapping->addr = m->local_addr;
 	  /* Address only mapping doesn't change port */
-	  mapping->port = m->addr_only ? match.port
+	  mapping->port = is_addr_only_static_mapping (m) ? match.port
 	    : clib_host_to_net_u16 (m->local_port);
 	}
       mapping->protocol = m->proto;
@@ -2117,18 +2105,21 @@
     {
       mapping->addr = m->external_addr;
       /* Address only mapping doesn't change port */
-      mapping->port = m->addr_only ? match.port
+      mapping->port = is_addr_only_static_mapping (m) ? match.port
 	: clib_host_to_net_u16 (m->external_port);
       mapping->fib_index = sm->outside_fib_index;
     }
 
 end:
   if (PREDICT_FALSE (is_addr_only != 0))
-    *is_addr_only = m->addr_only;
+    *is_addr_only = is_addr_only_static_mapping (m);
 
   if (PREDICT_FALSE (twice_nat != 0))
     *twice_nat = m->twice_nat;
 
+  if (PREDICT_FALSE (is_identity_nat != 0))
+    *is_identity_nat = is_identity_static_mapping (m);
+
   return 0;
 }
 
@@ -2919,7 +2910,8 @@
 				rp->e_port,
 				rp->vrf_id,
 				rp->addr_only, ~0 /* sw_if_index */ ,
-				rp->proto, !is_delete, 0, 0, rp->tag);
+				rp->proto, !is_delete, rp->twice_nat,
+				rp->out2in_only, rp->tag, rp->identity_nat);
   if (rv)
     nat_log_notice ("snat_add_static_mapping returned %d", rv);
 }
@@ -2988,7 +2980,9 @@
 					    rp->addr_only,
 					    ~0 /* sw_if_index */ ,
 					    rp->proto,
-					    rp->is_add, 0, 0, rp->tag);
+					    rp->is_add, rp->twice_nat,
+					    rp->out2in_only, rp->tag,
+					    rp->identity_nat);
 	      if (rv)
 		nat_log_notice ("snat_add_static_mapping returned %d", rv);
 	    }
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index 1baf10f..0549acd 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -179,6 +179,11 @@
 #define NAT_INTERFACE_FLAG_IS_INSIDE 1
 #define NAT_INTERFACE_FLAG_IS_OUTSIDE 2
 
+/* Static mapping flags */
+#define NAT_STATIC_MAPPING_FLAG_ADDR_ONLY    1
+#define NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY  2
+#define NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT 4
+
 /* *INDENT-OFF* */
 typedef CLIB_PACKED(struct
 {
@@ -321,12 +326,8 @@
   u16 local_port;
   /* external port */
   u16 external_port;
-  /* 1 = 1:1NAT, 0 = 1:1NAPT */
-  u8 addr_only;
   /* is twice-nat */
   twice_nat_type_t twice_nat;
-  /* 1 = rule match only out2in direction */
-  u8 out2in_only;
   /* local FIB table */
   u32 vrf_id;
   u32 fib_index;
@@ -342,6 +343,8 @@
   nat44_lb_addr_port_t *locals;
   /* affinity per service lis */
   u32 affinity_per_service_list_head_index;
+  /* flags */
+  u32 flags;
 } snat_static_mapping_t;
 
 typedef struct
@@ -358,9 +361,12 @@
   u32 sw_if_index;
   u32 vrf_id;
   snat_protocol_t proto;
+  u32 flags;
   int addr_only;
   int twice_nat;
   int is_add;
+  int out2in_only;
+  int identity_nat;
   u8 *tag;
 } snat_static_map_resolve_t;
 
@@ -642,6 +648,24 @@
 */
 #define nat44_is_ses_closed(s) s->state == 0xf
 
+/** \brief Check if NAT static mapping is address only (1:1NAT).
+    @param sm NAT static mapping
+    @return 1 if 1:1NAT, 0 if 1:1NAPT
+*/
+#define is_addr_only_static_mapping(sm) (sm->flags & NAT_STATIC_MAPPING_FLAG_ADDR_ONLY)
+
+/** \brief Check if NAT static mapping match only out2in direction.
+    @param sm NAT static mapping
+    @return 1 if rule match only out2in direction
+*/
+#define is_out2in_only_static_mapping(sm) (sm->flags & NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY)
+
+/** \brief Check if NAT static mapping is identity NAT.
+    @param sm NAT static mapping
+    @return 1 if identity NAT
+*/
+#define is_identity_static_mapping(sm) (sm->flags & NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT)
+
 /* logging */
 #define nat_log_err(...) \
   vlib_log(VLIB_LOG_LEVEL_ERR, snat_main.log_class, __VA_ARGS__)
@@ -773,18 +797,19 @@
 /**
  * @brief Add/delete NAT44 static mapping
  *
- * @param l_addr      local IPv4 address
- * @param e_addr      external IPv4 address
- * @param l_port      local port number
- * @param e_port      external port number
- * @param vrf_id      local VRF ID
- * @param addr_only   1 = 1:1NAT, 0 = 1:1NAPT
- * @param sw_if_index use interface address as external IPv4 address
- * @param proto       L4 protocol
- * @param is_add      1 = add, 0 = delete
- * @param twice_nat   twice-nat mode
- * @param out2in_only if 1 rule match only out2in direction
- * @param tagi        opaque string tag
+ * @param l_addr       local IPv4 address
+ * @param e_addr       external IPv4 address
+ * @param l_port       local port number
+ * @param e_port       external port number
+ * @param vrf_id       local VRF ID
+ * @param addr_only    1 = 1:1NAT, 0 = 1:1NAPT
+ * @param sw_if_index  use interface address as external IPv4 address
+ * @param proto        L4 protocol
+ * @param is_add       1 = add, 0 = delete
+ * @param twice_nat    twice-nat mode
+ * @param out2in_only  if 1 rule match only out2in direction
+ * @param tag          opaque string tag
+ * @param identity_nat identity NAT
  *
  * @return 0 on success, non-zero value otherwise
  */
@@ -793,7 +818,7 @@
 			     int addr_only, u32 sw_if_index,
 			     snat_protocol_t proto, int is_add,
 			     twice_nat_type_t twice_nat, u8 out2in_only,
-			     u8 * tag);
+			     u8 * tag, u8 identity_nat);
 
 /**
  * @brief Add/delete static mapping with load-balancing (multiple backends)
@@ -1009,7 +1034,8 @@
 			       u8 * is_addr_only,
 			       twice_nat_type_t * twice_nat,
 			       lb_nat_type_t * lb,
-			       ip4_address_t * ext_host_addr);
+			       ip4_address_t * ext_host_addr,
+			       u8 * is_identity_nat);
 
 /**
  * @brief Add/del NAT address to FIB.
diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c
index bebc6a0..0a3379a 100644
--- a/src/plugins/nat/nat44_cli.c
+++ b/src/plugins/nat/nat44_cli.c
@@ -718,7 +718,7 @@
 
   rv = snat_add_static_mapping (l_addr, e_addr, (u16) l_port, (u16) e_port,
 				vrf_id, addr_only, sw_if_index, proto, is_add,
-				twice_nat, out2in_only, 0);
+				twice_nat, out2in_only, 0, 0);
 
   switch (rv)
     {
@@ -802,7 +802,7 @@
 
   rv = snat_add_static_mapping (addr, addr, (u16) port, (u16) port,
 				vrf_id, addr_only, sw_if_index, proto, is_add,
-				0, 0, 0);
+				0, 0, 0, 1);
 
   switch (rv)
     {
diff --git a/src/plugins/nat/nat44_hairpinning.c b/src/plugins/nat/nat44_hairpinning.c
index 9d49dc2..c07427d 100644
--- a/src/plugins/nat/nat44_hairpinning.c
+++ b/src/plugins/nat/nat44_hairpinning.c
@@ -114,7 +114,7 @@
   kv0.key = key0.as_u64;
 
   /* Check if destination is static mappings */
-  if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+  if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
     {
       new_dst_addr0 = sm0.addr.as_u32;
       new_dst_port0 = sm0.port;
@@ -444,7 +444,7 @@
   udp0 = ip4_next_header (ip0);
 
   /* Check if destination is static mappings */
-  if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+  if (!snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
     {
       new_dst_addr0 = sm0.addr.as_u32;
       new_dst_port0 = sm0.port;
diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c
index e642edd..8ad5c665 100644
--- a/src/plugins/nat/nat_api.c
+++ b/src/plugins/nat/nat_api.c
@@ -980,7 +980,7 @@
   rv = snat_add_static_mapping (local_addr, external_addr, local_port,
 				external_port, vrf_id, mp->addr_only,
 				external_sw_if_index, proto, mp->is_add,
-				twice_nat, mp->out2in_only, tag);
+				twice_nat, mp->out2in_only, tag, 0);
 
   vec_free (tag);
 
@@ -1027,7 +1027,7 @@
   memset (rmp, 0, sizeof (*rmp));
   rmp->_vl_msg_id =
     ntohs (VL_API_NAT44_STATIC_MAPPING_DETAILS + sm->msg_id_base);
-  rmp->addr_only = m->addr_only;
+  rmp->addr_only = is_addr_only_static_mapping (m);
   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;
@@ -1037,8 +1037,8 @@
     rmp->twice_nat = 1;
   else if (m->twice_nat == TWICE_NAT_SELF)
     rmp->self_twice_nat = 1;
-  rmp->out2in_only = m->out2in_only;
-  if (m->addr_only == 0)
+  rmp->out2in_only = is_out2in_only_static_mapping (m);
+  if (rmp->addr_only == 0)
     {
       rmp->protocol = snat_proto_to_ip_proto (m->proto);
       rmp->external_port = htons (m->external_port);
@@ -1100,9 +1100,7 @@
   /* *INDENT-OFF* */
   pool_foreach (m, sm->static_mappings,
   ({
-      if (!vec_len (m->locals) &&
-          ((m->local_port != m->external_port)
-           || (m->local_addr.as_u32 != m->external_addr.as_u32)))
+      if (!is_identity_static_mapping(m) && !vec_len (m->locals))
         send_nat44_static_mapping_details (m, reg, mp->context);
   }));
   /* *INDENT-ON* */
@@ -1110,7 +1108,7 @@
   for (j = 0; j < vec_len (sm->to_resolve); j++)
     {
       rp = sm->to_resolve + j;
-      if (rp->l_addr.as_u32 != 0)
+      if (!rp->identity_nat)
 	send_nat44_static_map_resolve_details (rp, reg, mp->context);
     }
 }
@@ -1162,7 +1160,7 @@
 
   rv =
     snat_add_static_mapping (addr, addr, port, port, vrf_id, mp->addr_only,
-			     sw_if_index, proto, mp->is_add, 0, 0, tag);
+			     sw_if_index, proto, mp->is_add, 0, 0, tag, 1);
 
   vec_free (tag);
 
@@ -1203,7 +1201,7 @@
   memset (rmp, 0, sizeof (*rmp));
   rmp->_vl_msg_id =
     ntohs (VL_API_NAT44_IDENTITY_MAPPING_DETAILS + sm->msg_id_base);
-  rmp->addr_only = m->addr_only;
+  rmp->addr_only = is_addr_only_static_mapping (m);
   clib_memcpy (rmp->ip_address, &(m->local_addr), 4);
   rmp->port = htons (m->local_port);
   rmp->sw_if_index = ~0;
@@ -1260,8 +1258,7 @@
   /* *INDENT-OFF* */
   pool_foreach (m, sm->static_mappings,
   ({
-      if (!vec_len (m->locals) && (m->local_port == m->external_port)
-          && (m->local_addr.as_u32 == m->external_addr.as_u32))
+      if (is_identity_static_mapping(m) && !vec_len (m->locals))
         send_nat44_identity_mapping_details (m, reg, mp->context);
   }));
   /* *INDENT-ON* */
@@ -1269,7 +1266,7 @@
   for (j = 0; j < vec_len (sm->to_resolve); j++)
     {
       rp = sm->to_resolve + j;
-      if (rp->l_addr.as_u32 == 0)
+      if (rp->identity_nat)
 	send_nat44_identity_map_resolve_details (rp, reg, mp->context);
     }
 }
@@ -1656,7 +1653,7 @@
     rmp->twice_nat = 1;
   else if (m->twice_nat == TWICE_NAT_SELF)
     rmp->self_twice_nat = 1;
-  rmp->out2in_only = m->out2in_only;
+  rmp->out2in_only = is_out2in_only_static_mapping (m);
   if (m->tag)
     strncpy ((char *) rmp->tag, (char *) m->tag, vec_len (m->tag));
 
diff --git a/src/plugins/nat/nat_format.c b/src/plugins/nat/nat_format.c
index 279d666..a4b62b6 100644
--- a/src/plugins/nat/nat_format.c
+++ b/src/plugins/nat/nat_format.c
@@ -220,14 +220,14 @@
   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
   nat44_lb_addr_port_t *local;
 
-  if (m->addr_only)
+  if (is_addr_only_static_mapping (m))
     s = format (s, "local %U external %U vrf %d %s %s",
 		format_ip4_address, &m->local_addr,
 		format_ip4_address, &m->external_addr,
 		m->vrf_id,
 		m->twice_nat == TWICE_NAT ? "twice-nat" :
 		m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
-		m->out2in_only ? "out2in-only" : "");
+		is_out2in_only_static_mapping (m) ? "out2in-only" : "");
   else
     {
       if (vec_len (m->locals))
@@ -237,7 +237,7 @@
 		      format_ip4_address, &m->external_addr, m->external_port,
 		      m->twice_nat == TWICE_NAT ? "twice-nat" :
 		      m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
-		      m->out2in_only ? "out2in-only" : "");
+		      is_out2in_only_static_mapping (m) ? "out2in-only" : "");
 	  vec_foreach (local, m->locals)
 	    s = format (s, "\n  local %U:%d vrf %d probability %d\%",
 			format_ip4_address, &local->addr, local->port,
@@ -251,7 +251,7 @@
 		    m->vrf_id,
 		    m->twice_nat == TWICE_NAT ? "twice-nat" :
 		    m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "",
-		    m->out2in_only ? "out2in-only" : "");
+		    is_out2in_only_static_mapping (m) ? "out2in-only" : "");
     }
   return s;
 }
diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c
index 67d831a..eeecf16 100755
--- a/src/plugins/nat/out2in.c
+++ b/src/plugins/nat/out2in.c
@@ -309,6 +309,7 @@
   u8 is_addr_only;
   u32 next0 = ~0;
   int err;
+  u8 identity_nat;
 
   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
@@ -333,7 +334,7 @@
       /* Try to match static mapping by external address and port,
          destination address and port in packet */
       if (snat_static_mapping_match
-	  (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
+	  (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, &identity_nat))
 	{
 	  if (!sm->forwarding_enabled)
 	    {
@@ -364,6 +365,11 @@
 	  goto out;
 	}
 
+      if (PREDICT_FALSE (identity_nat))
+	{
+	  dont_translate = 1;
+	  goto out;
+	}
       /* Create session initiated by host from external network */
       s0 = create_session_for_static_mapping (sm, b0, sm0, key0,
 					      node, thread_index,
@@ -443,7 +449,8 @@
     }
   key0.fib_index = rx_fib_index0;
 
-  if (snat_static_mapping_match (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0))
+  if (snat_static_mapping_match
+      (sm, key0, &sm0, 1, &is_addr_only, 0, 0, 0, 0))
     {
       /* Don't NAT packet aimed at the intfc address */
       if (is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))
@@ -703,6 +710,7 @@
 	  u32 proto0, proto1;
 	  snat_session_t *s0 = 0, *s1 = 0;
 	  clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
+	  u8 identity_nat0, identity_nat1;
 
 	  /* Prefetch next iteration. */
 	  {
@@ -793,7 +801,8 @@
 	    {
 	      /* Try to match static mapping by external address and port,
 	         destination address and port in packet */
-	      if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+	      if (snat_static_mapping_match
+		  (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
 		{
 		  /*
 		   * Send DHCP packets to the ipv4 stack, or we won't
@@ -817,6 +826,9 @@
 		  goto trace0;
 		}
 
+	      if (PREDICT_FALSE (identity_nat0))
+		goto trace0;
+
 	      /* Create session initiated by host from external network */
 	      s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
 						      thread_index, now);
@@ -950,7 +962,8 @@
 	    {
 	      /* Try to match static mapping by external address and port,
 	         destination address and port in packet */
-	      if (snat_static_mapping_match (sm, key1, &sm1, 1, 0, 0, 0, 0))
+	      if (snat_static_mapping_match
+		  (sm, key1, &sm1, 1, 0, 0, 0, 0, &identity_nat1))
 		{
 		  /*
 		   * Send DHCP packets to the ipv4 stack, or we won't
@@ -974,6 +987,9 @@
 		  goto trace1;
 		}
 
+	      if (PREDICT_FALSE (identity_nat1))
+		goto trace1;
+
 	      /* Create session initiated by host from external network */
 	      s1 = create_session_for_static_mapping (sm, b1, sm1, key1, node,
 						      thread_index, now);
@@ -1069,6 +1085,7 @@
 	  u32 proto0;
 	  snat_session_t *s0 = 0;
 	  clib_bihash_kv_8_8_t kv0, value0;
+	  u8 identity_nat0;
 
 	  /* speculatively enqueue b0 to the current next frame */
 	  bi0 = from[0];
@@ -1143,7 +1160,8 @@
 	    {
 	      /* Try to match static mapping by external address and port,
 	         destination address and port in packet */
-	      if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+	      if (snat_static_mapping_match
+		  (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
 		{
 		  /*
 		   * Send DHCP packets to the ipv4 stack, or we won't
@@ -1167,6 +1185,9 @@
 		  goto trace00;
 		}
 
+	      if (PREDICT_FALSE (identity_nat0))
+		goto trace00;
+
 	      /* Create session initiated by host from external network */
 	      s0 = create_session_for_static_mapping (sm, b0, sm0, key0, node,
 						      thread_index, now);
@@ -1320,6 +1341,7 @@
 	  snat_session_t *s0 = 0;
 	  u16 old_port0, new_port0;
 	  ip_csum_t sum0;
+	  u8 identity_nat0;
 
 	  /* speculatively enqueue b0 to the current next frame */
 	  bi0 = from[0];
@@ -1377,7 +1399,7 @@
 		  /* Try to match static mapping by external address and port,
 		     destination address and port in packet */
 		  if (snat_static_mapping_match
-		      (sm, key0, &sm0, 1, 0, 0, 0, 0))
+		      (sm, key0, &sm0, 1, 0, 0, 0, 0, &identity_nat0))
 		    {
 		      /*
 		       * Send DHCP packets to the ipv4 stack, or we won't
@@ -1402,6 +1424,9 @@
 		      goto trace0;
 		    }
 
+		  if (PREDICT_FALSE (identity_nat0))
+		    goto trace0;
+
 		  /* Create session initiated by host from external network */
 		  s0 =
 		    create_session_for_static_mapping (sm, b0, sm0, key0,
@@ -1663,7 +1688,7 @@
 	  key0.port = udp0->dst_port;
 	  key0.fib_index = rx_fib_index0;
 
-	  if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0))
+	  if (snat_static_mapping_match (sm, key0, &sm0, 1, 0, 0, 0, 0, 0))
 	    {
 	      b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION];
 	      goto trace00;
diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c
index dce6c56..b2dbc51 100644
--- a/src/plugins/nat/out2in_ed.c
+++ b/src/plugins/nat/out2in_ed.c
@@ -471,7 +471,7 @@
   clib_bihash_kv_16_8_t kv, value;
   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
   snat_session_t *s = 0;
-  u8 dont_translate = 0, is_addr_only;
+  u8 dont_translate = 0, is_addr_only, identity_nat;
   snat_session_key_t e_key, l_key;
 
   icmp = (icmp46_header_t *) ip4_next_header (ip);
@@ -496,7 +496,7 @@
       e_key.protocol = ip_proto_to_snat_proto (key.proto);
       e_key.fib_index = rx_fib_index;
       if (snat_static_mapping_match
-	  (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0))
+	  (sm, e_key, &l_key, 1, &is_addr_only, 0, 0, 0, &identity_nat))
 	{
 	  if (!sm->forwarding_enabled)
 	    {
@@ -533,6 +533,12 @@
 	  goto out;
 	}
 
+      if (PREDICT_FALSE (identity_nat))
+	{
+	  dont_translate = 1;
+	  goto out;
+	}
+
       /* Create session initiated by host from external network */
       s = create_session_for_static_mapping_ed (sm, b, l_key, e_key, node,
 						thread_index, 0, 0,
@@ -717,6 +723,7 @@
 	  snat_session_key_t e_key0, l_key0, e_key1, l_key1;
 	  lb_nat_type_t lb_nat0, lb_nat1;
 	  twice_nat_type_t twice_nat0, twice_nat1;
+	  u8 identity_nat0, identity_nat1;
 
 	  /* Prefetch next iteration. */
 	  {
@@ -828,7 +835,8 @@
 		  e_key0.fib_index = rx_fib_index0;
 		  if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
 						 &twice_nat0, &lb_nat0,
-						 &ip0->src_address))
+						 &ip0->src_address,
+						 &identity_nat0))
 		    {
 		      /*
 		       * Send DHCP packets to the ipv4 stack, or we won't
@@ -864,6 +872,9 @@
 		      goto trace00;
 		    }
 
+		  if (PREDICT_FALSE (identity_nat0))
+		    goto trace00;
+
 		  /* Create session initiated by host from external network */
 		  s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
 							     e_key0, node,
@@ -1046,7 +1057,8 @@
 		  e_key1.fib_index = rx_fib_index1;
 		  if (snat_static_mapping_match (sm, e_key1, &l_key1, 1, 0,
 						 &twice_nat1, &lb_nat1,
-						 &ip1->src_address))
+						 &ip1->src_address,
+						 &identity_nat1))
 		    {
 		      /*
 		       * Send DHCP packets to the ipv4 stack, or we won't
@@ -1082,6 +1094,9 @@
 		      goto trace01;
 		    }
 
+		  if (PREDICT_FALSE (identity_nat1))
+		    goto trace01;
+
 		  /* Create session initiated by host from external network */
 		  s1 = create_session_for_static_mapping_ed (sm, b1, l_key1,
 							     e_key1, node,
@@ -1202,6 +1217,7 @@
 	  snat_session_key_t e_key0, l_key0;
 	  lb_nat_type_t lb_nat0;
 	  twice_nat_type_t twice_nat0;
+	  u8 identity_nat0;
 
 	  /* speculatively enqueue b0 to the current next frame */
 	  bi0 = from[0];
@@ -1297,7 +1313,8 @@
 		  e_key0.fib_index = rx_fib_index0;
 		  if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
 						 &twice_nat0, &lb_nat0,
-						 &ip0->src_address))
+						 &ip0->src_address,
+						 &identity_nat0))
 		    {
 		      /*
 		       * Send DHCP packets to the ipv4 stack, or we won't
@@ -1333,6 +1350,9 @@
 		      goto trace0;
 		    }
 
+		  if (PREDICT_FALSE (identity_nat0))
+		    goto trace0;
+
 		  /* Create session initiated by host from external network */
 		  s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
 							     e_key0, node,
@@ -1554,6 +1574,7 @@
 	  snat_session_key_t e_key0, l_key0;
 	  lb_nat_type_t lb0;
 	  twice_nat_type_t twice_nat0;
+	  u8 identity_nat0;
 
 	  /* speculatively enqueue b0 to the current next frame */
 	  bi0 = from[0];
@@ -1634,7 +1655,8 @@
 		  e_key0.protocol = proto0;
 		  e_key0.fib_index = rx_fib_index0;
 		  if (snat_static_mapping_match (sm, e_key0, &l_key0, 1, 0,
-						 &twice_nat0, &lb0, 0))
+						 &twice_nat0, &lb0, 0,
+						 &identity_nat0))
 		    {
 		      /*
 		       * Send DHCP packets to the ipv4 stack, or we won't
@@ -1674,6 +1696,12 @@
 		      goto trace0;
 		    }
 
+		  if (PREDICT_FALSE (identity_nat0))
+		    {
+		      reass0->flags |= NAT_REASS_FLAG_ED_DONT_TRANSLATE;
+		      goto trace0;
+		    }
+
 		  /* Create session initiated by host from external network */
 		  s0 = create_session_for_static_mapping_ed (sm, b0, l_key0,
 							     e_key0, node,
diff --git a/test/test_nat.py b/test/test_nat.py
index 9092b47..3b9007f 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -1935,6 +1935,9 @@
             self.logger.error(ppp("Unexpected or invalid packet:", p))
             raise
 
+        sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0)
+        self.assertEqual(len(sessions), 0)
+
     def test_multiple_inside_interfaces(self):
         """ NAT44 multiple non-overlapping address space inside interfaces """