session: add api to dump rules

Change-Id: Ie42fd77e75e86a45cfe5951768c4638f27fdc3aa
Signed-off-by: Florin Coras <fcoras@cisco.com>
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* */