NAT: syslog - sessions logging (VPP-1139)

Change-Id: I6e0b7cf37c1a9ac66f8ac011db29504e57844ee9
Signed-off-by: Matus Fabian <matfabia@cisco.com>
diff --git a/src/plugins/nat/CMakeLists.txt b/src/plugins/nat/CMakeLists.txt
index 76662f9..134aafe 100644
--- a/src/plugins/nat/CMakeLists.txt
+++ b/src/plugins/nat/CMakeLists.txt
@@ -47,6 +47,7 @@
   nat66_out2in.c
   nat_affinity.c
   nat_format.c
+  nat_syslog.c
 
   API_FILES
   nat.api
diff --git a/src/plugins/nat/dslite_in2out.c b/src/plugins/nat/dslite_in2out.c
index e7a3028..5c1de19 100644
--- a/src/plugins/nat/dslite_in2out.c
+++ b/src/plugins/nat/dslite_in2out.c
@@ -14,6 +14,7 @@
  */
 #include <nat/dslite.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat_syslog.h>
 
 vlib_node_registration_t dslite_in2out_node;
 vlib_node_registration_t dslite_in2out_slowpath_node;
@@ -45,6 +46,7 @@
   u32 oldest_index;
   dslite_session_t *s;
   snat_session_key_t out2in_key;
+  u32 b4_index;
 
   out2in_key.protocol = in2out_key->proto;
   out2in_key.fib_index = 0;
@@ -66,12 +68,13 @@
       clib_dlist_init (dm->per_thread_data[thread_index].list_pool,
 		       b4->sessions_per_b4_list_head_index);
 
-      b4_kv.value = b4 - dm->per_thread_data[thread_index].b4s;
+      b4_index = b4_kv.value = b4 - dm->per_thread_data[thread_index].b4s;
       clib_bihash_add_del_16_8 (&dm->per_thread_data[thread_index].b4_hash,
 				&b4_kv, 1);
     }
   else
     {
+      b4_index = b4_value.value;
       b4 =
 	pool_elt_at_index (dm->per_thread_data[thread_index].b4s,
 			   b4_value.value);
@@ -104,6 +107,11 @@
       snat_free_outside_address_and_port (dm->addr_pool, thread_index,
 					  &s->out2in);
 
+      nat_syslog_dslite_apmdel (b4_index, &s->in2out.softwire_id,
+				&s->in2out.addr, s->in2out.port,
+				&s->out2in.addr, s->out2in.port,
+				s->in2out.proto);
+
       if (snat_alloc_outside_address_and_port
 	  (dm->addr_pool, 0, thread_index, &out2in_key,
 	   dm->port_per_thread, thread_index))
@@ -147,6 +155,10 @@
   clib_bihash_add_del_8_8 (&dm->per_thread_data[thread_index].out2in,
 			   &out2in_kv, 1);
 
+  nat_syslog_dslite_apmadd (b4_index, &s->in2out.softwire_id, &s->in2out.addr,
+			    s->in2out.port, &s->out2in.addr, s->out2in.port,
+			    s->in2out.proto);
+
   return next;
 }
 
diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c
index d4432d9..786d821 100755
--- a/src/plugins/nat/in2out.c
+++ b/src/plugins/nat/in2out.c
@@ -28,6 +28,7 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_reass.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat_syslog.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
@@ -216,6 +217,11 @@
 					   s->out2in.port,
 					   s->in2out.fib_index);
 
+      nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
+			       &s->in2out.addr, s->in2out.port,
+			       &s->out2in.addr, s->out2in.port,
+			       s->in2out.protocol);
+
       if (!snat_is_session_static (s))
 	snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
 					    &s->out2in);
@@ -365,6 +371,11 @@
 				       s->in2out.protocol,
 				       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->in2out.protocol);
+
   return next0;
 }
 
diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c
index c42d4e7..ab253e8 100644
--- a/src/plugins/nat/in2out_ed.c
+++ b/src/plugins/nat/in2out_ed.c
@@ -28,6 +28,7 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_reass.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat_syslog.h>
 
 #define foreach_nat_in2out_ed_error                       \
 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol")         \
@@ -197,6 +198,13 @@
 					   s->out2in.port,
 					   s->in2out.fib_index);
 
+      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->in2out.protocol, is_twice_nat_session (s));
+
       if (is_twice_nat_session (s))
 	{
 	  for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
@@ -409,6 +417,14 @@
 				       s->in2out.protocol,
 				       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->in2out.protocol, 0);
+
   return next;
 }
 
diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c
index b7ade88..6bfea3c 100755
--- a/src/plugins/nat/nat.c
+++ b/src/plugins/nat/nat.c
@@ -29,6 +29,7 @@
 #include <nat/nat_reass.h>
 #include <nat/nat_inlines.h>
 #include <nat/nat_affinity.h>
+#include <nat/nat_syslog.h>
 #include <vnet/fib/fib_table.h>
 #include <vnet/fib/ip4_fib.h>
 
@@ -236,6 +237,13 @@
       ed_kv.key[1] = ed_key.as_u64[1];
       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
 	nat_log_warn ("in2out_ed key del failed");
+
+      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->in2out.protocol, is_twice_nat_session (s));
     }
   else
     {
@@ -245,6 +253,11 @@
       kv.key = s->out2in.as_u64;
       if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
 	nat_log_warn ("out2in key del failed");
+
+      nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
+			       &s->in2out.addr, s->in2out.port,
+			       &s->out2in.addr, s->out2in.port,
+			       s->in2out.protocol);
     }
 
   if (snat_is_unk_proto_session (s))
@@ -382,6 +395,8 @@
       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;
     }
 
   return s;
diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h
index 3162e41..3ce83ea 100644
--- a/src/plugins/nat/nat.h
+++ b/src/plugins/nat/nat.h
@@ -222,6 +222,9 @@
   u8 state;
   u32 i2o_fin_seq;
   u32 o2i_fin_seq;
+
+  /* user index */
+  u32 user_index;
 }) snat_session_t;
 /* *INDENT-ON* */
 
diff --git a/src/plugins/nat/nat64_db.c b/src/plugins/nat/nat64_db.c
index bb327a5..ca8358e 100644
--- a/src/plugins/nat/nat64_db.c
+++ b/src/plugins/nat/nat64_db.c
@@ -19,6 +19,7 @@
 #include <nat/nat64_db.h>
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat_syslog.h>
 #include <vnet/fib/fib_table.h>
 
 int
@@ -456,7 +457,9 @@
 				   &ste->in_r_addr, &ste->out_r_addr,
 				   ste->r_port, ste->r_port, fib->ft_table_id,
 				   1);
-
+  nat_syslog_nat64_sadd (bibe->fib_index, &bibe->in_addr, bibe->in_port,
+			 &bibe->out_addr, bibe->out_port, &ste->out_r_addr,
+			 ste->r_port, bibe->proto);
   return ste;
 }
 
@@ -528,6 +531,9 @@
 				   &ste->in_r_addr, &ste->out_r_addr,
 				   ste->r_port, ste->r_port, fib->ft_table_id,
 				   0);
+  nat_syslog_nat64_sdel (bibe->fib_index, &bibe->in_addr, bibe->in_port,
+			 &bibe->out_addr, bibe->out_port, &ste->out_r_addr,
+			 ste->r_port, bibe->proto);
 
   /* delete from pool */
   pool_put (st, ste);
diff --git a/src/plugins/nat/nat_syslog.c b/src/plugins/nat/nat_syslog.c
new file mode 100644
index 0000000..07fe2ea
--- /dev/null
+++ b/src/plugins/nat/nat_syslog.c
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief NAT syslog logging
+ */
+
+#include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip.h>
+#include <vnet/syslog/syslog.h>
+
+#include <nat/nat_syslog.h>
+#include <nat/nat_inlines.h>
+
+
+#define NAT_FACILITY SYSLOG_FACILITY_LOCAL0
+
+#define NAT_APPNAME "NAT"
+
+#define SADD_SDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL
+#define APMADD_APMDEL_SEVERITY SYSLOG_SEVERITY_INFORMATIONAL
+
+#define SADD_MSGID "SADD"
+#define SDEL_MSGID "SDEL"
+#define APMADD_MSGID "APMADD"
+#define APMDEL_MSGID "APMDEL"
+
+#define NSESS_SDID "nsess"
+#define NAPMAP_SDID "napmap"
+
+#define SSUBIX_SDPARAM_NAME "SSUBIX"
+#define SVLAN_SDPARAM_NAME "SVLAN"
+#define IATYP_SDPARAM_NAME "IATYP"
+#define ISADDR_SDPARAM_NAME "ISADDR"
+#define ISPORT_SDPARAM_NAME "ISPORT"
+#define IDADDR_SDPARAM_NAME "IDADDR"
+#define IDPORT_SDPARAM_NAME "IDPORT"
+#define XATYP_SDPARAM_NAME "XATYP"
+#define XSADDR_SDPARAM_NAME "XSADDR"
+#define XSPORT_SDPARAM_NAME "XSPORT"
+#define XDADDR_SDPARAM_NAME "XDADDR"
+#define XDPORT_SDPARAM_NAME "XDPORT"
+#define PROTO_SDPARAM_NAME "PROTO"
+#define SV6ENC_SDPARAM_NAME "SV6ENC"
+
+#define IATYP_IPV4 "IPv4"
+#define IATYP_IPV6 "IPv6"
+
+static inline void
+nat_syslog_nat44_apmap (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			u16 isport, ip4_address_t * xsaddr, u16 xsport,
+			snat_protocol_t proto, u8 is_add,
+			ip6_address_t * sv6enc)
+{
+  syslog_msg_t syslog_msg;
+  fib_table_t *fib;
+
+  if (!syslog_is_enabled ())
+    return;
+
+  if (syslog_severity_filter_block (APMADD_APMDEL_SEVERITY))
+    return;
+
+  syslog_msg_init (&syslog_msg, NAT_FACILITY, APMADD_APMDEL_SEVERITY,
+		   NAT_APPNAME, is_add ? APMADD_MSGID : APMDEL_MSGID);
+
+  syslog_msg_sd_init (&syslog_msg, NAPMAP_SDID);
+  syslog_msg_add_sd_param (&syslog_msg, SSUBIX_SDPARAM_NAME, "%d", ssubix);
+  if (sv6enc)
+    {
+      syslog_msg_add_sd_param (&syslog_msg, SV6ENC_SDPARAM_NAME, "%U",
+			       format_ip6_address, sv6enc);
+    }
+  else
+    {
+      fib = fib_table_get (sfibix, FIB_PROTOCOL_IP4);
+      syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d",
+			       fib->ft_table_id);
+    }
+  syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV4);
+  syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, isaddr);
+  syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (isport));
+  syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4);
+  syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, xsaddr);
+  syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (xsport));
+  syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d",
+			   snat_proto_to_ip_proto (proto));
+
+  syslog_msg_send (&syslog_msg);
+}
+
+void
+nat_syslog_nat44_apmadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			 u16 isport, ip4_address_t * xsaddr, u16 xsport,
+			 snat_protocol_t proto)
+{
+  nat_syslog_nat44_apmap (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+			  proto, 1, 0);
+}
+
+void
+nat_syslog_nat44_apmdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			 u16 isport, ip4_address_t * xsaddr, u16 xsport,
+			 snat_protocol_t proto)
+{
+  nat_syslog_nat44_apmap (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+			  proto, 0, 0);
+}
+
+void
+nat_syslog_dslite_apmadd (u32 ssubix, ip6_address_t * sv6enc,
+			  ip4_address_t * isaddr, u16 isport,
+			  ip4_address_t * xsaddr, u16 xsport,
+			  snat_protocol_t proto)
+{
+  nat_syslog_nat44_apmap (ssubix, 0, isaddr, isport, xsaddr, xsport,
+			  proto, 1, sv6enc);
+}
+
+void
+nat_syslog_dslite_apmdel (u32 ssubix, ip6_address_t * sv6enc,
+			  ip4_address_t * isaddr, u16 isport,
+			  ip4_address_t * xsaddr, u16 xsport,
+			  snat_protocol_t proto)
+{
+  nat_syslog_nat44_apmap (ssubix, 0, isaddr, isport, xsaddr, xsport,
+			  proto, 0, sv6enc);
+}
+
+static inline void
+nat_syslog_nat44_sess (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+		       u16 isport, ip4_address_t * xsaddr, u16 xsport,
+		       ip4_address_t * idaddr, u16 idport,
+		       ip4_address_t * xdaddr, u16 xdport,
+		       snat_protocol_t proto, u8 is_add, u8 is_twicenat)
+{
+  syslog_msg_t syslog_msg;
+  fib_table_t *fib;
+
+  if (!syslog_is_enabled ())
+    return;
+
+  if (syslog_severity_filter_block (SADD_SDEL_SEVERITY))
+    return;
+
+  fib = fib_table_get (sfibix, FIB_PROTOCOL_IP4);
+
+  syslog_msg_init (&syslog_msg, NAT_FACILITY, SADD_SDEL_SEVERITY, NAT_APPNAME,
+		   is_add ? SADD_MSGID : SDEL_MSGID);
+
+  syslog_msg_sd_init (&syslog_msg, NSESS_SDID);
+  syslog_msg_add_sd_param (&syslog_msg, SSUBIX_SDPARAM_NAME, "%d", ssubix);
+  syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d",
+			   fib->ft_table_id);
+  syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV4);
+  syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, isaddr);
+  syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (isport));
+  syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4);
+  syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, xsaddr);
+  syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (xsport));
+  syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d",
+			   snat_proto_to_ip_proto (proto));
+  syslog_msg_add_sd_param (&syslog_msg, XDADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, xdaddr);
+  syslog_msg_add_sd_param (&syslog_msg, XDPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (xdport));
+  if (is_twicenat)
+    {
+      syslog_msg_add_sd_param (&syslog_msg, IDADDR_SDPARAM_NAME, "%U",
+			       format_ip4_address, idaddr);
+      syslog_msg_add_sd_param (&syslog_msg, IDPORT_SDPARAM_NAME, "%d",
+			       clib_net_to_host_u16 (idport));
+    }
+
+  syslog_msg_send (&syslog_msg);
+}
+
+void
+nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+		       u16 isport, ip4_address_t * idaddr, u16 idport,
+		       ip4_address_t * xsaddr, u16 xsport,
+		       ip4_address_t * xdaddr, u16 xdport,
+		       snat_protocol_t proto, u8 is_twicenat)
+{
+  nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+			 idaddr, idport, xdaddr, xdport, proto, 1,
+			 is_twicenat);
+}
+
+void
+nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+		       u16 isport, ip4_address_t * idaddr, u16 idport,
+		       ip4_address_t * xsaddr, u16 xsport,
+		       ip4_address_t * xdaddr, u16 xdport,
+		       snat_protocol_t proto, u8 is_twicenat)
+{
+  nat_syslog_nat44_sess (ssubix, sfibix, isaddr, isport, xsaddr, xsport,
+			 idaddr, idport, xdaddr, xdport, proto, 0,
+			 is_twicenat);
+}
+
+static inline void
+nat_syslog_nat64_sess (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+		       ip4_address_t * xsaddr, u16 xsport,
+		       ip4_address_t * xdaddr, u16 xdport,
+		       snat_protocol_t proto, u8 is_add)
+{
+  syslog_msg_t syslog_msg;
+  fib_table_t *fib;
+
+  if (!syslog_is_enabled ())
+    return;
+
+  if (syslog_severity_filter_block (SADD_SDEL_SEVERITY))
+    return;
+
+  fib = fib_table_get (sfibix, FIB_PROTOCOL_IP6);
+
+  syslog_msg_init (&syslog_msg, NAT_FACILITY, SADD_SDEL_SEVERITY, NAT_APPNAME,
+		   is_add ? SADD_MSGID : SDEL_MSGID);
+
+  syslog_msg_sd_init (&syslog_msg, NSESS_SDID);
+  syslog_msg_add_sd_param (&syslog_msg, SVLAN_SDPARAM_NAME, "%d",
+			   fib->ft_table_id);
+  syslog_msg_add_sd_param (&syslog_msg, IATYP_SDPARAM_NAME, IATYP_IPV6);
+  syslog_msg_add_sd_param (&syslog_msg, ISADDR_SDPARAM_NAME, "%U",
+			   format_ip6_address, isaddr);
+  syslog_msg_add_sd_param (&syslog_msg, ISPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (isport));
+  syslog_msg_add_sd_param (&syslog_msg, XATYP_SDPARAM_NAME, IATYP_IPV4);
+  syslog_msg_add_sd_param (&syslog_msg, XSADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, xsaddr);
+  syslog_msg_add_sd_param (&syslog_msg, XSPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (xsport));
+  syslog_msg_add_sd_param (&syslog_msg, PROTO_SDPARAM_NAME, "%d", proto);
+  syslog_msg_add_sd_param (&syslog_msg, XDADDR_SDPARAM_NAME, "%U",
+			   format_ip4_address, xdaddr);
+  syslog_msg_add_sd_param (&syslog_msg, XDPORT_SDPARAM_NAME, "%d",
+			   clib_net_to_host_u16 (xdport));
+
+  syslog_msg_send (&syslog_msg);
+}
+
+void
+nat_syslog_nat64_sadd (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+		       ip4_address_t * xsaddr, u16 xsport,
+		       ip4_address_t * xdaddr, u16 xdport,
+		       snat_protocol_t proto)
+{
+  nat_syslog_nat64_sess (sfibix, isaddr, isport, xsaddr, xsport, xdaddr,
+			 xdport, proto, 1);
+}
+
+void
+nat_syslog_nat64_sdel (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+		       ip4_address_t * xsaddr, u16 xsport,
+		       ip4_address_t * xdaddr, u16 xdport,
+		       snat_protocol_t proto)
+{
+  nat_syslog_nat64_sess (sfibix, isaddr, isport, xsaddr, xsport, xdaddr,
+			 xdport, proto, 0);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/nat/nat_syslog.h b/src/plugins/nat/nat_syslog.h
new file mode 100644
index 0000000..15a891f
--- /dev/null
+++ b/src/plugins/nat/nat_syslog.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+/**
+ * @file
+ * @brief NAT syslog logging
+ */
+
+#ifndef __included_nat_syslog_h__
+#define __included_nat_syslog_h__
+
+#include <nat/nat.h>
+
+void nat_syslog_nat44_apmadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			      u16 isport, ip4_address_t * xsaddr, u16 xsport,
+			      snat_protocol_t proto);
+
+void nat_syslog_nat44_apmdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			      u16 isport, ip4_address_t * xsaddr, u16 xsport,
+			      snat_protocol_t proto);
+
+void
+nat_syslog_dslite_apmadd (u32 ssubix, ip6_address_t * sv6enc,
+			  ip4_address_t * isaddr, u16 isport,
+			  ip4_address_t * xsaddr, u16 xsport,
+			  snat_protocol_t proto);
+
+void
+nat_syslog_dslite_apmdel (u32 ssubix, ip6_address_t * sv6enc,
+			  ip4_address_t * isaddr, u16 isport,
+			  ip4_address_t * xsaddr, u16 xsport,
+			  snat_protocol_t proto);
+
+void nat_syslog_nat44_sadd (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			    u16 isport, ip4_address_t * idaddr, u16 idport,
+			    ip4_address_t * xsaddr, u16 xsport,
+			    ip4_address_t * xdaddr, u16 xdport,
+			    snat_protocol_t proto, u8 is_twicenat);
+
+void nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t * isaddr,
+			    u16 isport, ip4_address_t * idaddr, u16 idport,
+			    ip4_address_t * xsaddr, u16 xsport,
+			    ip4_address_t * xdaddr, u16 xdport,
+			    snat_protocol_t proto, u8 is_twicenat);
+
+void nat_syslog_nat64_sadd (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+			    ip4_address_t * xsaddr, u16 xsport,
+			    ip4_address_t * xdaddr, u16 xdport,
+			    snat_protocol_t proto);
+
+void nat_syslog_nat64_sdel (u32 sfibix, ip6_address_t * isaddr, u16 isport,
+			    ip4_address_t * xsaddr, u16 xsport,
+			    ip4_address_t * xdaddr, u16 xdport,
+			    snat_protocol_t proto);
+
+#endif /* __included_nat_syslog_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c
index 52f2023..74d2088 100755
--- a/src/plugins/nat/out2in.c
+++ b/src/plugins/nat/out2in.c
@@ -29,6 +29,7 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_reass.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat_syslog.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
@@ -132,6 +133,11 @@
 					   s->out2in.port,
 					   s->in2out.fib_index);
 
+      nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
+			       &s->in2out.addr, s->in2out.port,
+			       &s->out2in.addr, s->out2in.port,
+			       s->in2out.protocol);
+
       if (!snat_is_session_static (s))
 	snat_free_outside_address_and_port (sm->addresses, ctx->thread_index,
 					    &s->out2in);
@@ -229,6 +235,11 @@
 				       s->in2out.protocol,
 				       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->in2out.protocol);
+
   return s;
 }
 
diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c
index aa7f7e4..f76fc60 100644
--- a/src/plugins/nat/out2in_ed.c
+++ b/src/plugins/nat/out2in_ed.c
@@ -29,6 +29,7 @@
 #include <nat/nat_ipfix_logging.h>
 #include <nat/nat_reass.h>
 #include <nat/nat_inlines.h>
+#include <nat/nat_syslog.h>
 
 #define foreach_nat_out2in_ed_error                     \
 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol")         \
@@ -173,6 +174,13 @@
 					   s->out2in.port,
 					   s->in2out.fib_index);
 
+      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->in2out.protocol, is_twice_nat_session (s));
+
       if (is_twice_nat_session (s))
 	{
 	  for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
@@ -303,6 +311,19 @@
 					       &ctx))
     nat_log_notice ("in2out-ed key add failed");
 
+  snat_ipfix_logging_nat44_ses_create (s->in2out.addr.as_u32,
+				       s->out2in.addr.as_u32,
+				       s->in2out.protocol,
+				       s->in2out.port,
+				       s->out2in.port, s->in2out.fib_index);
+
+  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->in2out.protocol, is_twice_nat_session (s));
+
   return s;
 }
 
diff --git a/test/test_nat.py b/test/test_nat.py
index 59d98d9..b7b80c9 100644
--- a/test/test_nat.py
+++ b/test/test_nat.py
@@ -21,6 +21,9 @@
 from time import sleep
 from util import ip4_range
 from util import mactobinary
+from syslog_rfc5424_parser import SyslogMessage, ParseError
+from syslog_rfc5424_parser.constants import SyslogFacility, SyslogSeverity
+from vpp_papi_provider import SYSLOG_SEVERITY
 
 
 class MethodHolder(VppTestCase):
@@ -69,6 +72,8 @@
         self.ipfix_src_port = 4739
         self.ipfix_domain_id = 1
 
+        self.vapi.syslog_set_filter(SYSLOG_SEVERITY.EMERG)
+
         interfaces = self.vapi.nat44_interface_dump()
         for intf in interfaces:
             if intf.is_inside > 1:
@@ -1031,6 +1036,55 @@
         # sourceIPv4Address
         self.assertEqual(src_addr, record[8])
 
+    def verify_syslog_apmap(self, data, is_add=True):
+        message = data.decode('utf-8')
+        try:
+            message = SyslogMessage.parse(message)
+            self.assertEqual(message.severity, SyslogSeverity.info)
+            self.assertEqual(message.appname, 'NAT')
+            self.assertEqual(message.msgid, 'APMADD' if is_add else 'APMDEL')
+            sd_params = message.sd.get('napmap')
+            self.assertTrue(sd_params is not None)
+            self.assertEqual(sd_params.get('IATYP'), 'IPv4')
+            self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
+            self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
+            self.assertEqual(sd_params.get('XATYP'), 'IPv4')
+            self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
+            self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
+            self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
+            self.assertTrue(sd_params.get('SSUBIX') is not None)
+            self.assertEqual(sd_params.get('SVLAN'), '0')
+        except ParseError as e:
+            self.logger.error(e)
+
+    def verify_syslog_sess(self, data, is_add=True, is_ip6=False):
+        message = data.decode('utf-8')
+        try:
+            message = SyslogMessage.parse(message)
+            self.assertEqual(message.severity, SyslogSeverity.info)
+            self.assertEqual(message.appname, 'NAT')
+            self.assertEqual(message.msgid, 'SADD' if is_add else 'SDEL')
+            sd_params = message.sd.get('nsess')
+            self.assertTrue(sd_params is not None)
+            if is_ip6:
+                self.assertEqual(sd_params.get('IATYP'), 'IPv6')
+                self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip6)
+            else:
+                self.assertEqual(sd_params.get('IATYP'), 'IPv4')
+                self.assertEqual(sd_params.get('ISADDR'), self.pg0.remote_ip4)
+                self.assertTrue(sd_params.get('SSUBIX') is not None)
+            self.assertEqual(sd_params.get('ISPORT'), "%d" % self.tcp_port_in)
+            self.assertEqual(sd_params.get('XATYP'), 'IPv4')
+            self.assertEqual(sd_params.get('XSADDR'), self.nat_addr)
+            self.assertEqual(sd_params.get('XSPORT'), "%d" % self.tcp_port_out)
+            self.assertEqual(sd_params.get('PROTO'), "%d" % IP_PROTOS.tcp)
+            self.assertEqual(sd_params.get('SVLAN'), '0')
+            self.assertEqual(sd_params.get('XDADDR'), self.pg1.remote_ip4)
+            self.assertEqual(sd_params.get('XDPORT'),
+                             "%d" % self.tcp_external_port)
+        except ParseError as e:
+            self.logger.error(e)
+
     def verify_mss_value(self, pkt, mss):
         """
         Verify TCP MSS value
@@ -2687,6 +2741,32 @@
                 data = ipfix.decode_data_set(p.getlayer(Set))
                 self.verify_ipfix_max_sessions(data, max_sessions)
 
+    def test_syslog_apmap(self):
+        """ Test syslog address and port mapping creation and deletion """
+        self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
+        self.vapi.syslog_set_sender(self.pg3.remote_ip4n, self.pg3.local_ip4n)
+        self.nat44_add_address(self.nat_addr)
+        self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
+        self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
+                                                  is_inside=0)
+
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+             TCP(sport=self.tcp_port_in, dport=20))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        capture = self.pg1.get_capture(1)
+        self.tcp_port_out = capture[0][TCP].sport
+        capture = self.pg3.get_capture(1)
+        self.verify_syslog_apmap(capture[0][Raw].load)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.nat44_add_address(self.nat_addr, is_add=0)
+        capture = self.pg3.get_capture(1)
+        self.verify_syslog_apmap(capture[0][Raw].load, False)
+
     def test_pool_addr_fib(self):
         """ NAT44 add pool addresses to FIB """
         static_addr = '10.0.0.10'
@@ -5777,6 +5857,32 @@
         self.pg_start()
         self.pg1.get_capture(1)
 
+    def test_syslog_sess(self):
+        """ Test syslog session creation and deletion """
+        self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
+        self.vapi.syslog_set_sender(self.pg2.remote_ip4n, self.pg2.local_ip4n)
+        self.nat44_add_address(self.nat_addr)
+        self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index)
+        self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index,
+                                                  is_inside=0)
+
+        p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+             IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
+             TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        capture = self.pg1.get_capture(1)
+        self.tcp_port_out = capture[0][TCP].sport
+        capture = self.pg2.get_capture(1)
+        self.verify_syslog_sess(capture[0][Raw].load)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.nat44_add_address(self.nat_addr, is_add=0)
+        capture = self.pg2.get_capture(1)
+        self.verify_syslog_sess(capture[0][Raw].load, False)
+
     def tearDown(self):
         super(TestNAT44EndpointDependent, self).tearDown()
         if not self.vpp_dead:
@@ -6524,6 +6630,7 @@
             cls.udp_port_out = 6304
             cls.icmp_id_in = 6305
             cls.icmp_id_out = 6305
+            cls.tcp_external_port = 80
             cls.nat_addr = '10.0.0.3'
             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
             cls.vrf1_id = 10
@@ -7726,6 +7833,39 @@
                 else:
                     self.logger.error(ppp("Unexpected or invalid packet: ", p))
 
+    def test_syslog_sess(self):
+        """ Test syslog session creation and deletion """
+        self.tcp_port_in = random.randint(1025, 65535)
+        remote_host_ip6 = self.compose_ip6(self.pg1.remote_ip4,
+                                           '64:ff9b::',
+                                           96)
+
+        self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
+                                                self.nat_addr_n)
+        self.vapi.nat64_add_del_interface(self.pg0.sw_if_index)
+        self.vapi.nat64_add_del_interface(self.pg1.sw_if_index, is_inside=0)
+        self.vapi.syslog_set_filter(SYSLOG_SEVERITY.INFO)
+        self.vapi.syslog_set_sender(self.pg3.remote_ip4n, self.pg3.local_ip4n)
+
+        p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
+             IPv6(src=self.pg0.remote_ip6, dst=remote_host_ip6) /
+             TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
+        self.pg0.add_stream(p)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        p = self.pg1.get_capture(1)
+        self.tcp_port_out = p[0][TCP].sport
+        capture = self.pg3.get_capture(1)
+        self.verify_syslog_sess(capture[0][Raw].load, is_ip6=True)
+
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        self.vapi.nat64_add_del_pool_addr_range(self.nat_addr_n,
+                                                self.nat_addr_n,
+                                                is_add=0)
+        capture = self.pg3.get_capture(1)
+        self.verify_syslog_sess(capture[0][Raw].load, False, True)
+
     def nat64_get_ses_num(self):
         """
         Return number of active NAT64 sessions.
@@ -7742,6 +7882,8 @@
         self.ipfix_src_port = 4739
         self.ipfix_domain_id = 1
 
+        self.vapi.syslog_set_filter(SYSLOG_SEVERITY.EMERG)
+
         self.vapi.nat_set_timeouts()
 
         interfaces = self.vapi.nat64_interface_dump()
@@ -7802,7 +7944,7 @@
             cls.nat_addr = '10.0.0.3'
             cls.nat_addr_n = socket.inet_pton(socket.AF_INET, cls.nat_addr)
 
-            cls.create_pg_interfaces(range(2))
+            cls.create_pg_interfaces(range(3))
             cls.pg0.admin_up()
             cls.pg0.config_ip4()
             cls.pg0.resolve_arp()
@@ -7810,11 +7952,36 @@
             cls.pg1.config_ip6()
             cls.pg1.generate_remote_hosts(2)
             cls.pg1.configure_ipv6_neighbors()
+            cls.pg2.admin_up()
+            cls.pg2.config_ip4()
+            cls.pg2.resolve_arp()
 
         except Exception:
             super(TestDSlite, cls).tearDownClass()
             raise
 
+    def verify_syslog_apmadd(self, data, isaddr, isport, xsaddr, xsport,
+                             sv6enc, proto):
+        message = data.decode('utf-8')
+        try:
+            message = SyslogMessage.parse(message)
+            self.assertEqual(message.severity, SyslogSeverity.info)
+            self.assertEqual(message.appname, 'NAT')
+            self.assertEqual(message.msgid, 'APMADD')
+            sd_params = message.sd.get('napmap')
+            self.assertTrue(sd_params is not None)
+            self.assertEqual(sd_params.get('IATYP'), 'IPv4')
+            self.assertEqual(sd_params.get('ISADDR'), isaddr)
+            self.assertEqual(sd_params.get('ISPORT'), "%d" % isport)
+            self.assertEqual(sd_params.get('XATYP'), 'IPv4')
+            self.assertEqual(sd_params.get('XSADDR'), xsaddr)
+            self.assertEqual(sd_params.get('XSPORT'), "%d" % xsport)
+            self.assertEqual(sd_params.get('PROTO'), "%d" % proto)
+            self.assertTrue(sd_params.get('SSUBIX') is not None)
+            self.assertEqual(sd_params.get('SV6ENC'), sv6enc)
+        except ParseError as e:
+            self.logger.error(e)
+
     def test_dslite(self):
         """ Test DS-Lite """
         nat_config = self.vapi.nat_show_config()
@@ -7827,6 +7994,7 @@
         aftr_ip6 = '2001:db8:85a3::8a2e:370:1'
         aftr_ip6_n = socket.inet_pton(socket.AF_INET6, aftr_ip6)
         self.vapi.dslite_set_aftr_addr(aftr_ip6_n, aftr_ip4_n)
+        self.vapi.syslog_set_sender(self.pg2.remote_ip4n, self.pg2.local_ip4n)
 
         # UDP
         p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
@@ -7845,6 +8013,10 @@
         self.assertEqual(capture[UDP].dport, 10000)
         self.assert_packet_checksums_valid(capture)
         out_port = capture[UDP].sport
+        capture = self.pg2.get_capture(1)
+        self.verify_syslog_apmadd(capture[0][Raw].load, '192.168.1.1',
+                                  20000, self.nat_addr, out_port,
+                                  self.pg1.remote_hosts[0].ip6, IP_PROTOS.udp)
 
         p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
              IP(dst=self.nat_addr, src=self.pg0.remote_ip4) /