session: add api to dump rules

Change-Id: Ie42fd77e75e86a45cfe5951768c4638f27fdc3aa
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 9f76f8a..f27d51a 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -5626,7 +5626,8 @@
 _(DNS_NAME_SERVER_ADD_DEL_REPLY, dns_name_server_add_del_reply)		\
 _(DNS_RESOLVE_NAME_REPLY, dns_resolve_name_reply)			\
 _(DNS_RESOLVE_IP_REPLY, dns_resolve_ip_reply)				\
-_(SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply)
+_(SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply)		\
+_(SESSION_RULES_DETAILS, session_rules_details)
 
 #define foreach_standalone_reply_msg					\
 _(SW_INTERFACE_EVENT, sw_interface_event)                               \
@@ -21552,6 +21553,75 @@
   return ret;
 }
 
+static void
+vl_api_session_rules_details_t_handler (vl_api_session_rules_details_t * mp)
+{
+  vat_main_t *vam = &vat_main;
+
+  if (mp->is_ip4)
+    {
+      print (vam->ofp, "appns %u tp %u scope %d %U/%d %d %U/%d %d action: %d",
+	     mp->appns_index, mp->transport_proto, mp->scope,
+	     format_ip4_address, &mp->lcl_ip, mp->lcl_plen, mp->lcl_port,
+	     format_ip4_address, &mp->rmt_ip, mp->rmt_plen, mp->rmt_port,
+	     mp->action_index);
+    }
+  else
+    {
+      print (vam->ofp, "appns %u tp %u scope %d %U/%d %d %U/%d %d action: %d",
+	     mp->appns_index, mp->transport_proto, mp->scope,
+	     format_ip6_address, &mp->lcl_ip, mp->lcl_plen, mp->lcl_port,
+	     format_ip6_address, &mp->rmt_ip, mp->rmt_plen, mp->rmt_port,
+	     mp->action_index);
+    }
+}
+
+static void
+vl_api_session_rules_details_t_handler_json (vl_api_session_rules_details_t *
+					     mp)
+{
+  vat_main_t *vam = &vat_main;
+  vat_json_node_t *node = NULL;
+  struct in6_addr ip6;
+  struct in_addr ip4;
+
+  if (VAT_JSON_ARRAY != vam->json_tree.type)
+    {
+      ASSERT (VAT_JSON_NONE == vam->json_tree.type);
+      vat_json_init_array (&vam->json_tree);
+    }
+  node = vat_json_array_add (&vam->json_tree);
+  vat_json_init_object (node);
+
+  vat_json_object_add_uint (node, "is_ip4", mp->is_ip4 ? 1 : 0);
+  vat_json_object_add_uint (node, "appns_index",
+			    clib_net_to_host_u32 (mp->appns_index));
+  vat_json_object_add_uint (node, "transport_proto", mp->transport_proto);
+  vat_json_object_add_uint (node, "scope", mp->scope);
+  vat_json_object_add_uint (node, "action_index",
+			    clib_net_to_host_u32 (mp->action_index));
+  vat_json_object_add_uint (node, "lcl_port",
+			    clib_net_to_host_u16 (mp->lcl_port));
+  vat_json_object_add_uint (node, "rmt_port",
+			    clib_net_to_host_u16 (mp->rmt_port));
+  vat_json_object_add_uint (node, "lcl_plen", mp->lcl_plen);
+  vat_json_object_add_uint (node, "rmt_plen", mp->rmt_plen);
+  if (mp->is_ip4)
+    {
+      clib_memcpy (&ip4, mp->lcl_ip, sizeof (ip4));
+      vat_json_object_add_ip4 (node, "lcl_ip", ip4);
+      clib_memcpy (&ip4, mp->rmt_ip, sizeof (ip4));
+      vat_json_object_add_ip4 (node, "rmt_ip", ip4);
+    }
+  else
+    {
+      clib_memcpy (&ip6, mp->lcl_ip, sizeof (ip6));
+      vat_json_object_add_ip6 (node, "lcl_ip", ip6);
+      clib_memcpy (&ip6, mp->rmt_ip, sizeof (ip6));
+      vat_json_object_add_ip6 (node, "rmt_ip", ip6);
+    }
+}
+
 static int
 api_session_rule_add_del (vat_main_t * vam)
 {
@@ -21641,6 +21711,31 @@
 }
 
 static int
+api_session_rules_dump (vat_main_t * vam)
+{
+  vl_api_session_rules_dump_t *mp;
+  vl_api_control_ping_t *mp_ping;
+  int ret;
+
+  if (!vam->json_output)
+    {
+      print (vam->ofp, "%=20s", "Session Rules");
+    }
+
+  M (SESSION_RULES_DUMP, mp);
+  /* send it... */
+  S (mp);
+
+  /* Use a control ping for synchronization */
+  MPING (CONTROL_PING, mp_ping);
+  S (mp_ping);
+
+  /* Wait for a reply... */
+  W (ret);
+  return ret;
+}
+
+static int
 q_or_quit (vat_main_t * vam)
 {
 #if VPP_API_TEST_BUILTIN == 0
@@ -22450,6 +22545,7 @@
 _(dns_resolve_name, "<hostname>")					\
 _(session_rule_add_del, "[add|del] proto <tcp/udp> <lcl-ip>/<plen> "	\
   "<lcl-port> <rmt-ip>/<plen> <rmt-port> action <nn>")			\
+_(session_rules_dump, "")						\
 
 /* List of command functions, CLI names map directly to functions */
 #define foreach_cli_function                                    \
diff --git a/src/vnet/session/application_namespace.c b/src/vnet/session/application_namespace.c
index 326b0c0..c8c5b7e 100644
--- a/src/vnet/session/application_namespace.c
+++ b/src/vnet/session/application_namespace.c
@@ -94,7 +94,9 @@
 	{
 	  app_ns = app_namespace_alloc (a->ns_id);
 	  st = session_table_alloc ();
-	  session_table_init (st);
+	  session_table_init (st, FIB_PROTOCOL_MAX);
+	  st->is_local = 1;
+	  st->appns_index = app_namespace_index (app_ns);
 	  app_ns->local_table_index = session_table_index (st);
 	}
       app_ns->ns_secret = a->secret;
@@ -103,6 +105,7 @@
 	fib_table_find (FIB_PROTOCOL_IP4, a->ip4_fib_id);
       app_ns->ip6_fib_index =
 	fib_table_find (FIB_PROTOCOL_IP6, a->ip6_fib_id);
+      session_lookup_set_tables_appns (app_ns);
     }
   else
     {
diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api
index e6f3b02..8de0922 100644
--- a/src/vnet/session/session.api
+++ b/src/vnet/session/session.api
@@ -397,6 +397,50 @@
   u8 scope;
 };
 
+/** \brief Dump session rules
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+ */
+define session_rules_dump
+{
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Session rules details
+	@param context - sender context, to match reply w/ request
+    @param transport_proto - transport protocol (0 - tcp 1 - udp)
+    @param is_ip4 - flag to indicate if ip addresses are ip4 or 6
+    @param lcl_ip - local ip
+    @param lcl_plen - local prefix length
+    @param rmt_ip - remote ip
+    @param rmt_ple - remote prefix length
+    @param lcl_port - local port
+    @param rmt_port - remote port
+    @param action_index - the only action defined now is forward to
+    						  application with index action_index
+    	@param appns_index - application namespace where rule is to be applied
+    						 to
+    	@param scope - flag that indicates scope of the rule: global or local.
+    				   If 0, default is global, 1 is global 2 is local, 3 is
+    				   both
+  */
+define session_rules_details
+{
+  u32 context;
+  u8 transport_proto;
+  u8 is_ip4;
+  u8 lcl_ip[16];
+  u8 lcl_plen;
+  u8 rmt_ip[16];
+  u8 rmt_plen;
+  u16 lcl_port;
+  u16 rmt_port;
+  u32 action_index;
+  u32 appns_index;
+  u8 scope;
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index 32ef34b..7ca87a5 100755
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -18,6 +18,7 @@
 #include <vnet/session/application.h>
 #include <vnet/session/application_interface.h>
 #include <vnet/session/session_rules_table.h>
+#include <vnet/session/session_table.h>
 
 #include <vnet/vnet_msg_enum.h>
 
@@ -54,6 +55,7 @@
 _(SESSION_ENABLE_DISABLE, session_enable_disable)                   	\
 _(APP_NAMESPACE_ADD_DEL, app_namespace_add_del)				\
 _(SESSION_RULE_ADD_DEL, session_rule_add_del)				\
+_(SESSION_RULES_DUMP, session_rules_dump)				\
 
 static int
 send_add_segment_callback (u32 api_client_index, const u8 * segment_name,
@@ -816,6 +818,124 @@
   REPLY_MACRO (VL_API_SESSION_RULE_ADD_DEL_REPLY);
 }
 
+static void
+send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
+			    u8 transport_proto, u32 appns_index,
+			    unix_shared_memory_queue_t * q, u32 context)
+{
+  vl_api_session_rules_details_t *rmp = 0;
+  session_mask_or_match_4_t *match =
+    (session_mask_or_match_4_t *) & rule->match;
+  session_mask_or_match_4_t *mask =
+    (session_mask_or_match_4_t *) & rule->mask;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
+  rmp->context = context;
+
+  rmp->is_ip4 = 1;
+  clib_memcpy (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
+  clib_memcpy (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
+  rmp->lcl_plen = ip4_mask_to_preflen (&mask->lcl_ip);
+  rmp->rmt_plen = ip4_mask_to_preflen (&mask->rmt_ip);
+  rmp->lcl_port = clib_host_to_net_u16 (match->lcl_port);
+  rmp->rmt_port = clib_host_to_net_u16 (match->rmt_port);
+  rmp->action_index = clib_host_to_net_u32 (rule->action_index);
+  rmp->scope =
+    is_local ? SESSION_RULE_SCOPE_LOCAL : SESSION_RULE_SCOPE_GLOBAL;
+  rmp->transport_proto = transport_proto;
+  rmp->appns_index = clib_host_to_net_u32 (appns_index);
+
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+send_session_rule_details6 (mma_rule_40_t * rule, u8 scope,
+			    u8 transport_proto, u32 appns_index,
+			    unix_shared_memory_queue_t * q, u32 context)
+{
+  vl_api_session_rules_details_t *rmp = 0;
+  session_mask_or_match_6_t *match =
+    (session_mask_or_match_6_t *) & rule->match;
+  session_mask_or_match_6_t *mask =
+    (session_mask_or_match_6_t *) & rule->mask;
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp));
+  memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (VL_API_SESSION_RULES_DETAILS);
+  rmp->context = context;
+
+  rmp->is_ip4 = 0;
+  clib_memcpy (rmp->lcl_ip, &match->lcl_ip, sizeof (match->lcl_ip));
+  clib_memcpy (rmp->rmt_ip, &match->rmt_ip, sizeof (match->rmt_ip));
+  rmp->lcl_plen = ip6_mask_to_preflen (&mask->lcl_ip);
+  rmp->rmt_plen = ip6_mask_to_preflen (&mask->rmt_ip);
+  rmp->lcl_port = clib_host_to_net_u16 (match->lcl_port);
+  rmp->rmt_port = clib_host_to_net_u16 (match->rmt_port);
+  rmp->action_index = clib_host_to_net_u32 (rule->action_index);
+  rmp->scope = scope;
+  rmp->transport_proto = transport_proto;
+  rmp->appns_index = clib_host_to_net_u32 (appns_index);
+
+  vl_msg_api_send_shmem (q, (u8 *) & rmp);
+}
+
+static void
+send_session_rules_table_details (session_rules_table_t * srt, u8 fib_proto,
+				  u8 is_local, u32 appns_index,
+				  unix_shared_memory_queue_t * q, u32 context)
+{
+  mma_rule_16_t *rule16;
+  mma_rule_40_t *rule40;
+  mma_rules_table_16_t *srt16;
+  mma_rules_table_40_t *srt40;
+  u8 tp;
+
+  for (tp = 0; tp < TRANSPORT_N_PROTO; tp++)
+    {
+      if (is_local || fib_proto == FIB_PROTOCOL_IP4)
+	{
+          /* *INDENT-OFF* */
+          srt16 = &srt->session_rules_tables_16[tp];
+          pool_foreach (rule16, srt16->rules, ({
+            send_session_rule_details4 (rule16, is_local, tp,
+                                        appns_index, q, context);
+          }));
+          /* *INDENT-ON* */
+	}
+      if (is_local || fib_proto == FIB_PROTOCOL_IP6)
+	{
+          /* *INDENT-OFF* */
+          srt40 = &srt->session_rules_tables_40[tp];
+          pool_foreach (rule40, srt40->rules, ({
+            send_session_rule_details6 (rule40, is_local, tp,
+                                        appns_index, q, context);
+          }));
+          /* *INDENT-ON* */
+	}
+    }
+}
+
+static void
+vl_api_session_rules_dump_t_handler (vl_api_one_map_server_dump_t * mp)
+{
+  unix_shared_memory_queue_t *q = NULL;
+  session_table_t *st;
+
+  q = vl_api_client_index_to_input_queue (mp->client_index);
+  if (q == 0)
+    return;
+
+  /* *INDENT-OFF* */
+  session_table_foreach (st, ({
+    send_session_rules_table_details (&st->session_rules, st->active_fib_proto,
+                                      st->is_local, st->appns_index, q,
+                                      mp->context);
+  }));
+  /* *INDENT-ON* */
+}
+
 static clib_error_t *
 application_reaper_cb (u32 client_index)
 {
diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c
index c55712e..d537b9c 100644
--- a/src/vnet/session/session_lookup.c
+++ b/src/vnet/session/session_lookup.c
@@ -162,28 +162,36 @@
 		 session_type_from_proto_and_ip (t->proto, 0));
 }
 
-
 static session_table_t *
-session_table_get_or_alloc_for_connection (transport_connection_t * tc)
+session_table_get_or_alloc (u8 fib_proto, u8 fib_index)
 {
   session_table_t *st;
-  u32 table_index, fib_proto = transport_connection_fib_proto (tc);
-  if (vec_len (fib_index_to_table_index[fib_proto]) <= tc->fib_index)
+  u32 table_index;
+  if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
     {
       st = session_table_alloc ();
       table_index = session_table_index (st);
-      vec_validate (fib_index_to_table_index[fib_proto], tc->fib_index);
-      fib_index_to_table_index[fib_proto][tc->fib_index] = table_index;
+      vec_validate (fib_index_to_table_index[fib_proto], fib_index);
+      fib_index_to_table_index[fib_proto][fib_index] = table_index;
+      st->active_fib_proto = fib_proto;
       return st;
     }
   else
     {
-      table_index = fib_index_to_table_index[fib_proto][tc->fib_index];
+      table_index = fib_index_to_table_index[fib_proto][fib_index];
       return session_table_get (table_index);
     }
 }
 
 static session_table_t *
+session_table_get_or_alloc_for_connection (transport_connection_t * tc)
+{
+  u32 fib_proto;
+  fib_proto = transport_connection_fib_proto (tc);
+  return session_table_get_or_alloc (fib_proto, tc->fib_index);
+}
+
+static session_table_t *
 session_table_get_for_connection (transport_connection_t * tc)
 {
   u32 fib_proto = transport_connection_fib_proto (tc);
@@ -1131,6 +1139,25 @@
   return error;
 }
 
+/**
+ * Mark (global) tables as pertaining to app ns
+ */
+void
+session_lookup_set_tables_appns (app_namespace_t * app_ns)
+{
+  session_table_t *st;
+  u32 fib_index;
+  u8 fp;
+
+  for (fp = 0; fp < ARRAY_LEN (fib_index_to_table_index); fp++)
+    {
+      fib_index = app_namespace_get_fib_index (app_ns, fp);
+      st = session_table_get_for_fib_index (fp, fib_index);
+      if (st)
+	st->appns_index = app_namespace_index (app_ns);
+    }
+}
+
 u8 *
 format_ip4_session_lookup_kvp (u8 * s, va_list * args)
 {
@@ -1430,11 +1457,13 @@
   session_table_t *st = session_table_alloc ();
   vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP4], 0);
   fib_index_to_table_index[FIB_PROTOCOL_IP4][0] = session_table_index (st);
-  session_table_init (st);
+  st->active_fib_proto = FIB_PROTOCOL_IP4;
+  session_table_init (st, FIB_PROTOCOL_IP4);
   st = session_table_alloc ();
   vec_validate (fib_index_to_table_index[FIB_PROTOCOL_IP6], 0);
   fib_index_to_table_index[FIB_PROTOCOL_IP6][0] = session_table_index (st);
-  session_table_init (st);
+  st->active_fib_proto = FIB_PROTOCOL_IP6;
+  session_table_init (st, FIB_PROTOCOL_IP6);
 }
 
 /*
diff --git a/src/vnet/session/session_lookup.h b/src/vnet/session/session_lookup.h
index d8f0518..fa89727 100644
--- a/src/vnet/session/session_lookup.h
+++ b/src/vnet/session/session_lookup.h
@@ -19,6 +19,7 @@
 #include <vnet/session/session_table.h>
 #include <vnet/session/stream_session.h>
 #include <vnet/session/transport.h>
+#include <vnet/session/application_namespace.h>
 
 stream_session_t *session_lookup_safe4 (u32 fib_index, ip4_address_t * lcl,
 					ip4_address_t * rmt, u16 lcl_port,
@@ -115,6 +116,7 @@
 } session_rule_add_del_args_t;
 
 clib_error_t *vnet_session_rule_add_del (session_rule_add_del_args_t * args);
+void session_lookup_set_tables_appns (app_namespace_t * app_ns);
 
 void session_lookup_init (void);
 
diff --git a/src/vnet/session/session_table.c b/src/vnet/session/session_table.c
index cd8502a..f0bd338 100644
--- a/src/vnet/session/session_table.c
+++ b/src/vnet/session/session_table.c
@@ -22,6 +22,12 @@
 static session_table_t *lookup_tables;
 
 session_table_t *
+_get_session_tables (void)
+{
+  return lookup_tables;
+}
+
+session_table_t *
 session_table_alloc (void)
 {
   session_table_t *slt;
@@ -61,8 +67,10 @@
  * otherwise it uses defaults above.
  */
 void
-session_table_init (session_table_t * slt)
+session_table_init (session_table_t * slt, u8 fib_proto)
 {
+  u8 all = fib_proto > FIB_PROTOCOL_IP6 ? 1 : 0;
+
 #define _(af,table,parm,value) 						\
   u32 configured_##af##_##table##_table_##parm = value;
   foreach_hash_table_parameter;
@@ -75,19 +83,24 @@
   foreach_hash_table_parameter;
 #undef _
 
-  clib_bihash_init_16_8 (&slt->v4_session_hash, "v4 session table",
-			 configured_v4_session_table_buckets,
-			 configured_v4_session_table_memory);
-  clib_bihash_init_48_8 (&slt->v6_session_hash, "v6 session table",
-			 configured_v6_session_table_buckets,
-			 configured_v6_session_table_memory);
-  clib_bihash_init_16_8 (&slt->v4_half_open_hash, "v4 half-open table",
-			 configured_v4_halfopen_table_buckets,
-			 configured_v4_halfopen_table_memory);
-  clib_bihash_init_48_8 (&slt->v6_half_open_hash, "v6 half-open table",
-			 configured_v6_halfopen_table_buckets,
-			 configured_v6_halfopen_table_memory);
-
+  if (fib_proto == FIB_PROTOCOL_IP4 || all)
+    {
+      clib_bihash_init_16_8 (&slt->v4_session_hash, "v4 session table",
+			     configured_v4_session_table_buckets,
+			     configured_v4_session_table_memory);
+      clib_bihash_init_16_8 (&slt->v4_half_open_hash, "v4 half-open table",
+			     configured_v4_halfopen_table_buckets,
+			     configured_v4_halfopen_table_memory);
+    }
+  if (fib_proto == FIB_PROTOCOL_IP6 || all)
+    {
+      clib_bihash_init_48_8 (&slt->v6_session_hash, "v6 session table",
+			     configured_v6_session_table_buckets,
+			     configured_v6_session_table_memory);
+      clib_bihash_init_48_8 (&slt->v6_half_open_hash, "v6 half-open table",
+			     configured_v6_halfopen_table_buckets,
+			     configured_v6_halfopen_table_memory);
+    }
   session_rules_table_init (&slt->session_rules);
 }
 
diff --git a/src/vnet/session/session_table.h b/src/vnet/session/session_table.h
index 6588a43..6cf8159 100644
--- a/src/vnet/session/session_table.h
+++ b/src/vnet/session/session_table.h
@@ -38,6 +38,17 @@
    * Per fib proto and transport proto session rules tables
    */
   session_rules_table_t session_rules;
+
+  /** Flag that indicates if table has local scope */
+  u8 is_local;
+
+  /** Namespace this table belongs to */
+  u32 appns_index;
+
+  /** For global tables only one fib proto is active. This is a
+   * byproduct of fib table ids not necessarily being the same for
+   * identical fib idices of v4 and v6 fib protos */
+  u8 active_fib_proto;
 } session_table_t;
 
 #define SESSION_TABLE_INVALID_INDEX ((u32)~0)
@@ -55,7 +66,13 @@
 session_table_t *session_table_alloc (void);
 session_table_t *session_table_get (u32 table_index);
 u32 session_table_index (session_table_t * slt);
-void session_table_init (session_table_t * slt);
+void session_table_init (session_table_t * slt, u8 fib_proto);
+
+/* Internal, try not to use it! */
+session_table_t *_get_session_tables ();
+
+#define session_table_foreach(VAR, BODY)		\
+  pool_foreach(VAR, _get_session_tables (), BODY)
 
 #endif /* SRC_VNET_SESSION_SESSION_TABLE_H_ */
 /* *INDENT-ON* */