session: session table holding free appns index

session table may be shared among multiple appns's.
  app ns add id blue secret 1 if tap0
  app ns add id red secret 1 if tap0

session table holds the last added app_ns's appns_index.
If the last app_ns is deleted, session table is not free
since there is still an appns which uses the same session
table. In that case, session table is holding the free
app_ns's appns_index and it can cause problem.

The fix is to modify appns_index in session table to hold
a vector of appns_index's instead of just the appns_index
that was last added. When the app ns is deleted, remove the
deleted appns_index from the session table's vector of
appns_index's.

Type: fix

Change-Id: Ied8bc97f185071dc89b9b56656e18efbd2995131
Signed-off-by: Steven Luong <sluong@cisco.com>
diff --git a/src/plugins/unittest/session_test.c b/src/plugins/unittest/session_test.c
index 4e9b2fb..7702e81 100644
--- a/src/plugins/unittest/session_test.c
+++ b/src/plugins/unittest/session_test.c
@@ -825,6 +825,8 @@
   session_test_enable_rule_table_engine (vm);
 
   session_table_init (st, FIB_PROTOCOL_MAX);
+  vec_add1 (st->appns_index,
+	    app_namespace_index (app_namespace_get_default ()));
   session_rules_table_init (st, FIB_PROTOCOL_MAX);
 
   ip4_address_t lcl_ip = {
@@ -2238,6 +2240,8 @@
   session_test_enable_sdl_engine (vm);
 
   session_table_init (st, FIB_PROTOCOL_MAX);
+  vec_add1 (st->appns_index,
+	    app_namespace_index (app_namespace_get_default ()));
   session_rules_table_init (st, FIB_PROTOCOL_MAX);
 
   /* Add 1.2.0.0/16 */
diff --git a/src/vnet/session/application_namespace.c b/src/vnet/session/application_namespace.c
index 8b06331..2507f37 100644
--- a/src/vnet/session/application_namespace.c
+++ b/src/vnet/session/application_namespace.c
@@ -127,7 +127,7 @@
 	  st = session_table_alloc ();
 	  session_table_init (st, FIB_PROTOCOL_MAX);
 	  st->is_local = 1;
-	  st->appns_index = app_namespace_index (app_ns);
+	  vec_add1 (st->appns_index, app_namespace_index (app_ns));
 	  app_ns->local_table_index = session_table_index (st);
 	  if (a->sock_name)
 	    {
@@ -173,8 +173,10 @@
       if (app_ns->sock_name)
 	vec_free (app_ns->sock_name);
 
-      session_lookup_table_cleanup (FIB_PROTOCOL_IP4, app_ns->ip4_fib_index);
-      session_lookup_table_cleanup (FIB_PROTOCOL_IP6, app_ns->ip6_fib_index);
+      session_lookup_table_cleanup (FIB_PROTOCOL_IP4, app_ns->ip4_fib_index,
+				    ns_index);
+      session_lookup_table_cleanup (FIB_PROTOCOL_IP6, app_ns->ip6_fib_index,
+				    ns_index);
 
       app_namespace_free (app_ns);
     }
diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api
index f678f8b..2805546 100644
--- a/src/vnet/session/session.api
+++ b/src/vnet/session/session.api
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-option version = "4.0.2";
+option version = "4.0.3";
 
 import "vnet/interface_types.api";
 import "vnet/ip/ip_types.api";
@@ -411,6 +411,7 @@
  */
 define session_rules_dump
 {
+  option deprecated;
   u32 client_index;
   u32 context;
 };
@@ -434,6 +435,7 @@
   */
 define session_rules_details
 {
+  option deprecated;
   u32 context;
   vl_api_transport_proto_t transport_proto;
   vl_api_prefix_t lcl;
@@ -446,6 +448,49 @@
   string tag[64];
 };
 
+/** \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_v2_dump
+{
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Session rules details
+    @param context - sender context, to match reply w/ request
+    @param transport_proto - transport protocol
+    @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 scope - enum that indicates scope of the rule: global or local.
+                   If 0, default is global, 1 is global 2 is local, 3 is both
+    @param tag - tag
+    @param count - count of the number of appns_index
+    @param appns_index - application namespaces where rule is to be applied to
+  */
+define session_rules_v2_details
+{
+  u32 context;
+  vl_api_transport_proto_t transport_proto;
+  vl_api_prefix_t lcl;
+  vl_api_prefix_t rmt;
+  u16 lcl_port;
+  u16 rmt_port;
+  u32 action_index;
+  vl_api_session_rule_scope_t scope;
+  string tag[64];
+  u32 count;
+  u32 appns_index[count];
+};
+
 autoreply define session_sdl_add_del {
   option deprecated;
   u32 client_index;
@@ -500,6 +545,7 @@
  */
 define session_sdl_v2_dump
 {
+  option deprecated;
   u32 client_index;
   u32 context;
 };
@@ -514,6 +560,7 @@
   */
 define session_sdl_v2_details
 {
+  option deprecated;
   u32 context;
   vl_api_prefix_t rmt;
   u32 action_index;
@@ -521,6 +568,35 @@
   string tag[64];
 };
 
+/** \brief Dump session sdl v3
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+ */
+define session_sdl_v3_dump
+{
+  u32 client_index;
+  u32 context;
+};
+
+/** \brief Session sdl details v3
+    @param context - sender context, to match reply w/ request
+    @param rmt - remote prefix
+    @param action_index - the only action defined now is forward to
+                          application with index action_index
+    @param tag - tag
+    @param count - count of the number of appns_index
+    @param appns_index - application namespaces where rule is to be applied to
+  */
+define session_sdl_v3_details
+{
+  u32 context;
+  vl_api_prefix_t rmt;
+  u32 action_index;
+  string tag[64];
+  u32 count;
+  u32 appns_index[count];
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index e54c9b3..c6df47b 100644
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -1333,6 +1333,7 @@
   vl_api_registration_t *reg;
   session_table_t *st;
   u8 tp;
+  u32 appns_index;
 
   reg = vl_api_client_index_to_registration (mp->client_index);
   if (!reg)
@@ -1344,8 +1345,183 @@
 			       {
 				 session_rules_table_t *srt =
 				   srtg_handle_to_srt (st->srtg_handle, tp);
+				 appns_index = *vec_elt_at_index (
+				   st->appns_index,
+				   vec_len (st->appns_index) - 1);
 				 send_session_rules_table_details (
 				   srt, st->active_fib_proto, tp, st->is_local,
+				   appns_index, reg, mp->context);
+			       }
+			 }));
+}
+
+/*
+ * session_rules_v2_dunp handler
+ */
+static void
+send_session_rule_v2_details4 (mma_rule_16_t *rule, u8 is_local,
+			       u8 transport_proto, u32 *appns_index, u8 *tag,
+			       vl_api_registration_t *reg, u32 context)
+{
+  vl_api_session_rules_v2_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;
+  fib_prefix_t lcl, rmt;
+  u32 i, appns_index_count = vec_len (appns_index);
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp) +
+			  appns_index_count * sizeof (*appns_index));
+  if (!rmp)
+    return;
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_RULES_V2_DETAILS);
+  rmp->context = context;
+
+  rmp->count = clib_host_to_net_u32 (appns_index_count);
+  vec_foreach_index (i, appns_index)
+    {
+      u32 index = *vec_elt_at_index (appns_index, i);
+      rmp->appns_index[i] = clib_host_to_net_u32 (index);
+    }
+
+  clib_memset (&lcl, 0, sizeof (lcl));
+  clib_memset (&rmt, 0, sizeof (rmt));
+  ip_set (&lcl.fp_addr, &match->lcl_ip, 1);
+  ip_set (&rmt.fp_addr, &match->rmt_ip, 1);
+  lcl.fp_len = ip4_mask_to_preflen (&mask->lcl_ip);
+  rmt.fp_len = ip4_mask_to_preflen (&mask->rmt_ip);
+  lcl.fp_proto = FIB_PROTOCOL_IP4;
+  rmt.fp_proto = FIB_PROTOCOL_IP4;
+
+  ip_prefix_encode (&lcl, &rmp->lcl);
+  ip_prefix_encode (&rmt, &rmp->rmt);
+  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_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
+  rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
+  if (tag)
+    {
+      clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
+      rmp->tag[vec_len (tag)] = 0;
+    }
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+send_session_rule_v2_details6 (mma_rule_40_t *rule, u8 is_local,
+			       u8 transport_proto, u32 *appns_index, u8 *tag,
+			       vl_api_registration_t *reg, u32 context)
+{
+  vl_api_session_rules_v2_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;
+  fib_prefix_t lcl, rmt;
+  u32 i, appns_index_count = vec_len (appns_index);
+
+  rmp = vl_msg_api_alloc (sizeof (*rmp) +
+			  appns_index_count * sizeof (*appns_index));
+  if (!rmp)
+    return;
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id =
+    ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_RULES_V2_DETAILS);
+  rmp->context = context;
+
+  rmp->count = clib_host_to_net_u32 (appns_index_count);
+  vec_foreach_index (i, appns_index)
+    {
+      u32 index = *vec_elt_at_index (appns_index, i);
+      rmp->appns_index[i] = clib_host_to_net_u32 (index);
+    }
+
+  clib_memset (&lcl, 0, sizeof (lcl));
+  clib_memset (&rmt, 0, sizeof (rmt));
+  ip_set (&lcl.fp_addr, &match->lcl_ip, 0);
+  ip_set (&rmt.fp_addr, &match->rmt_ip, 0);
+  lcl.fp_len = ip6_mask_to_preflen (&mask->lcl_ip);
+  rmt.fp_len = ip6_mask_to_preflen (&mask->rmt_ip);
+  lcl.fp_proto = FIB_PROTOCOL_IP6;
+  rmt.fp_proto = FIB_PROTOCOL_IP6;
+
+  ip_prefix_encode (&lcl, &rmp->lcl);
+  ip_prefix_encode (&rmt, &rmp->rmt);
+  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_API_LOCAL : SESSION_RULE_SCOPE_API_GLOBAL;
+  rmp->transport_proto = api_session_transport_proto_encode (transport_proto);
+  if (tag)
+    {
+      clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
+      rmp->tag[vec_len (tag)] = 0;
+    }
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+send_session_rules_table_v2_details (session_rules_table_t *srt, u8 fib_proto,
+				     u8 tp, u8 is_local, u32 *appns_index,
+				     vl_api_registration_t *reg, u32 context)
+{
+  mma_rule_16_t *rule16;
+  mma_rule_40_t *rule40;
+  mma_rules_table_16_t *srt16;
+  mma_rules_table_40_t *srt40;
+  u32 ri;
+
+  if (is_local || fib_proto == FIB_PROTOCOL_IP4)
+    {
+      u8 *tag = 0;
+      srt16 = &srt->session_rules_tables_16;
+      pool_foreach (rule16, srt16->rules)
+      {
+	ri = mma_rules_table_rule_index_16 (srt16, rule16);
+	tag = session_rules_table_rule_tag (srt, ri, 1);
+	send_session_rule_v2_details4 (rule16, is_local, tp, appns_index, tag,
+				       reg, context);
+      }
+    }
+  if (is_local || fib_proto == FIB_PROTOCOL_IP6)
+    {
+      u8 *tag = 0;
+      srt40 = &srt->session_rules_tables_40;
+      pool_foreach (rule40, srt40->rules)
+      {
+	ri = mma_rules_table_rule_index_40 (srt40, rule40);
+	tag = session_rules_table_rule_tag (srt, ri, 1);
+	send_session_rule_v2_details6 (rule40, is_local, tp, appns_index, tag,
+				       reg, context);
+      }
+    }
+}
+
+static void
+vl_api_session_rules_v2_dump_t_handler (vl_api_session_rules_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  session_table_t *st;
+  u8 tp;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  session_table_foreach (st, ({
+			   if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+			     for (tp = 0; tp < TRANSPORT_N_PROTOS; tp++)
+			       {
+				 session_rules_table_t *srt =
+				   srtg_handle_to_srt (st->srtg_handle, tp);
+				 send_session_rules_table_v2_details (
+				   srt, st->active_fib_proto, tp, st->is_local,
 				   st->appns_index, reg, mp->context);
 			       }
 			 }));
@@ -1355,7 +1531,7 @@
 {
   vl_api_registration_t *reg;
   u32 mp_context;
-  u32 appns_index;
+  u32 *appns_index;
 } session_sdl_table_walk_ctx;
 
 static void
@@ -1365,7 +1541,8 @@
 {
   session_sdl_table_walk_ctx *ctx = args;
   vl_api_registration_t *reg = ctx->reg;
-  u32 appns_index = ctx->appns_index;
+  u32 appns_index =
+    *vec_elt_at_index (ctx->appns_index, vec_len (ctx->appns_index) - 1);
   u32 context = ctx->mp_context;
   vl_api_session_sdl_v2_details_t *rmp = 0;
   fib_prefix_t rmt;
@@ -1414,7 +1591,6 @@
       if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
 	{
 	  ctx.appns_index = st->appns_index;
-
 	  if (st->active_fib_proto == FIB_PROTOCOL_IP4)
 	    session_sdl_table_walk4 (st->srtg_handle,
 				     send_session_sdl_v2_details, &ctx);
@@ -1426,12 +1602,90 @@
 }
 
 static void
+send_session_sdl_v3_details (u32 fei, ip46_address_t *rmt_ip, u16 fp_len,
+			     u32 action_index, u32 fp_proto, u8 *tag,
+			     void *args)
+{
+  session_sdl_table_walk_ctx *ctx = args;
+  vl_api_registration_t *reg = ctx->reg;
+  u32 context = ctx->mp_context;
+  vl_api_session_sdl_v3_details_t *rmp = 0;
+  fib_prefix_t rmt;
+  u32 appns_index_count, appns_index, i;
+
+  appns_index_count = vec_len (ctx->appns_index);
+  rmp = vl_msg_api_alloc (sizeof (*rmp) +
+			  appns_index_count * sizeof (appns_index));
+  if (!rmp)
+    return;
+  clib_memset (rmp, 0, sizeof (*rmp));
+  rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_V3_DETAILS);
+  rmp->context = context;
+
+  rmp->count = clib_host_to_net_u32 (appns_index_count);
+  vec_foreach_index (i, ctx->appns_index)
+    {
+      appns_index = *vec_elt_at_index (ctx->appns_index, i);
+      rmp->appns_index[i] = clib_host_to_net_u32 (appns_index);
+    }
+
+  clib_memset (&rmt, 0, sizeof (rmt));
+  if (fp_proto == FIB_PROTOCOL_IP4)
+    ip_set (&rmt.fp_addr, &rmt_ip->ip4, 1);
+  else
+    ip_set (&rmt.fp_addr, &rmt_ip->ip6, 0);
+  rmt.fp_len = fp_len;
+  rmt.fp_proto = fp_proto,
+
+  ip_prefix_encode (&rmt, &rmp->rmt);
+  rmp->action_index = clib_host_to_net_u32 (action_index);
+
+  if (tag)
+    {
+      clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
+      rmp->tag[vec_len (tag)] = 0;
+    }
+
+  vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_session_sdl_v3_dump_t_handler (vl_api_session_sdl_v2_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+  session_table_t *st;
+  session_sdl_table_walk_ctx ctx;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  ctx.reg = reg;
+  ctx.mp_context = mp->context;
+
+  session_table_foreach (
+    st, ({
+      if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+	{
+	  ctx.appns_index = st->appns_index;
+	  if (st->active_fib_proto == FIB_PROTOCOL_IP4)
+	    session_sdl_table_walk4 (st->srtg_handle,
+				     send_session_sdl_v3_details, &ctx);
+	  else
+	    session_sdl_table_walk6 (st->srtg_handle,
+				     send_session_sdl_v3_details, &ctx);
+	}
+    }));
+}
+
+static void
 send_session_sdl_details (u32 fei, ip46_address_t *lcl_ip, u16 fp_len,
 			  u32 action_index, u32 fp_proto, u8 *tag, void *args)
 {
   session_sdl_table_walk_ctx *ctx = args;
   vl_api_registration_t *reg = ctx->reg;
-  u32 appns_index = ctx->appns_index;
+  u32 appns_index =
+    *vec_elt_at_index (ctx->appns_index, vec_len (ctx->appns_index) - 1);
   u32 context = ctx->mp_context;
   vl_api_session_sdl_details_t *rmp = 0;
   fib_prefix_t lcl;
@@ -1480,7 +1734,6 @@
       if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
 	{
 	  ctx.appns_index = st->appns_index;
-
 	  if (st->active_fib_proto == FIB_PROTOCOL_IP4)
 	    session_sdl_table_walk4 (st->srtg_handle, send_session_sdl_details,
 				     &ctx);
@@ -2209,6 +2462,10 @@
     am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_V2_DUMP, 1);
   vl_api_set_msg_thread_safe (
     am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_V2_DETAILS, 1);
+  vl_api_set_msg_thread_safe (
+    am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_V3_DUMP, 1);
+  vl_api_set_msg_thread_safe (
+    am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_V3_DETAILS, 1);
   return 0;
 }
 
diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c
index 720b94d..fa2051a 100644
--- a/src/vnet/session/session_lookup.c
+++ b/src/vnet/session/session_lookup.c
@@ -1455,7 +1455,7 @@
       st = session_table_get_or_alloc (fp, fib_index);
       if (st)
 	{
-	  st->appns_index = app_namespace_index (app_ns);
+	  vec_add1 (st->appns_index, app_namespace_index (app_ns));
 	  session_lookup_fib_table_lock (fib_index, fp);
 	}
     }
@@ -1945,23 +1945,30 @@
 }
 
 void
-session_lookup_table_cleanup (u32 fib_proto, u32 fib_index)
+session_lookup_table_cleanup (u32 fib_proto, u32 fib_index, u32 ns_index)
 {
   session_table_t *st;
-  u32 table_index;
+  u32 table_index, appns_index;
+  int i;
 
   session_lookup_fib_table_unlock (fib_index, fib_proto);
+  table_index = session_lookup_get_index_for_fib (fib_proto, fib_index);
+  st = session_table_get (table_index);
+  if (st == 0)
+    return;
   if (fib_index_to_lock_count[fib_proto][fib_index] == 0)
     {
-      table_index = session_lookup_get_index_for_fib (fib_proto, fib_index);
-      st = session_table_get (table_index);
-      if (st)
-	{
-	  session_table_free (st, fib_proto);
-	  if (vec_len (fib_index_to_table_index[fib_proto]) > fib_index)
-	    fib_index_to_table_index[fib_proto][fib_index] = ~0;
-	}
+      session_table_free (st, fib_proto);
+      if (vec_len (fib_index_to_table_index[fib_proto]) > fib_index)
+	fib_index_to_table_index[fib_proto][fib_index] = ~0;
     }
+  else
+    vec_foreach_index (i, st->appns_index)
+      {
+	appns_index = *vec_elt_at_index (st->appns_index, i);
+	if (ns_index == appns_index)
+	  vec_del1 (st->appns_index, i);
+      }
 }
 
 /*
diff --git a/src/vnet/session/session_sdl.c b/src/vnet/session/session_sdl.c
index 2fd63d1..f1dfac4 100644
--- a/src/vnet/session/session_sdl.c
+++ b/src/vnet/session/session_sdl.c
@@ -244,13 +244,17 @@
   session_sdl_block_t *sdlb;
   u8 all = fib_proto > FIB_PROTOCOL_IP6 ? 1 : 0;
   char name[80];
-  app_namespace_t *app_ns = app_namespace_get (st->appns_index);
+  u32 appns_index;
+  app_namespace_t *app_ns;
   session_rules_table_group_t *srtg;
 
   /* Don't support local table */
   if (st->is_local == 1)
     return;
 
+  appns_index =
+    *vec_elt_at_index (st->appns_index, vec_len (st->appns_index) - 1);
+  app_ns = app_namespace_get (appns_index);
   srtg = srtg_instance_alloc (st, 0);
   srt = srtg->session_rules;
   sdlb = &srt->sdl_block;
diff --git a/src/vnet/session/session_table.c b/src/vnet/session/session_table.c
index 5dafe0e..f3ec1f9 100644
--- a/src/vnet/session/session_table.c
+++ b/src/vnet/session/session_table.c
@@ -79,6 +79,7 @@
       clib_bihash_free_48_8 (&slt->v6_half_open_hash);
     }
 
+  vec_free (slt->appns_index);
   pool_put (lookup_tables, slt);
 }
 
@@ -222,7 +223,17 @@
 format_session_table (u8 *s, va_list *args)
 {
   session_table_t *st = va_arg (*args, session_table_t *);
+  u32 appns_index, i;
 
+  s = format (s, "appns index: ");
+  vec_foreach_index (i, st->appns_index)
+    {
+      appns_index = *vec_elt_at_index (st->appns_index, i);
+      if (i > 0)
+	s = format (s, ", ");
+      s = format (s, "%d", appns_index);
+    }
+  s = format (s, "\n");
   if (clib_bihash_is_initialised_16_8 (&st->v4_session_hash))
     {
       s = format (s, "%U", format_bihash_16_8, &st->v4_session_hash, 0);
diff --git a/src/vnet/session/session_table.h b/src/vnet/session/session_table.h
index aae4a1c..126e849 100644
--- a/src/vnet/session/session_table.h
+++ b/src/vnet/session/session_table.h
@@ -42,7 +42,7 @@
   u8 is_local;
 
   /** Namespace this table belongs to */
-  u32 appns_index;
+  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
@@ -77,7 +77,7 @@
 #define session_table_foreach(VAR, BODY)		\
   pool_foreach (VAR, _get_session_tables ()) BODY
 
-void session_lookup_table_cleanup (u32 fib_proto, u32 fib_index);
+void session_lookup_table_cleanup (u32 fib_proto, u32 fib_index, u32 ns_index);
 
 #endif /* SRC_VNET_SESSION_SESSION_TABLE_H_ */
 /*
diff --git a/src/vnet/session/session_test.c b/src/vnet/session/session_test.c
index e248dd7..14f1776 100644
--- a/src/vnet/session/session_test.c
+++ b/src/vnet/session/session_test.c
@@ -382,6 +382,11 @@
 {
 }
 
+static void
+vl_api_session_sdl_v3_details_t_handler (vl_api_session_sdl_v3_details_t *mp)
+{
+}
+
 static int
 api_session_sdl_dump (vat_main_t *vam)
 {
@@ -394,6 +399,24 @@
   return -1;
 }
 
+static int
+api_session_sdl_v3_dump (vat_main_t *vam)
+{
+  return -1;
+}
+
+static void
+vl_api_session_rules_v2_details_t_handler (
+  vl_api_session_rules_v2_details_t *mp)
+{
+}
+
+static int
+api_session_rules_v2_dump (vat_main_t *vam)
+{
+  return -1;
+}
+
 #include <vnet/session/session.api_test.c>
 
 /*
diff --git a/test/asf/test_session.py b/test/asf/test_session.py
index 957f323..7850f22 100644
--- a/test/asf/test_session.py
+++ b/test/asf/test_session.py
@@ -71,7 +71,7 @@
         )
 
         super(TestSession, self).tearDown()
-        self.vapi.session_enable_disable(is_enable=1)
+        self.vapi.session_enable_disable(is_enable=0)
 
     def test_segment_manager_alloc(self):
         """Session Segment Manager Multiple Segment Allocation"""
@@ -123,6 +123,89 @@
 
 
 @tag_fixme_vpp_workers
+class TestApplicationNamespace(VppAsfTestCase):
+    """Application Namespacee"""
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestApplicationNamespace, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestApplicationNamespace, cls).tearDownClass()
+
+    def setUp(self):
+        super(TestApplicationNamespace, self).setUp()
+        self.create_loopback_interfaces(1)
+
+    def tearDown(self):
+        super(TestApplicationNamespace, self).tearDown()
+        self.vapi.session_enable_disable_v2(
+            rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_DISABLE
+        )
+
+    def test_application_namespace(self):
+        """Application Namespace Create"""
+
+        self.vapi.session_enable_disable_v2(
+            rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_RULE_TABLE
+        )
+
+        # Configure 2 namespaces, sharing the same interface
+        app0 = self.vapi.app_namespace_add_del_v4(
+            namespace_id="0", sw_if_index=self.loop0.sw_if_index
+        )
+        app1 = self.vapi.app_namespace_add_del_v4(
+            namespace_id="1", sw_if_index=self.loop0.sw_if_index
+        )
+
+        self.vapi.session_rule_add_del(
+            transport_proto=VppEnum.vl_api_transport_proto_t.TRANSPORT_PROTO_API_TCP,
+            lcl="172.100.1.1/32",
+            rmt="172.100.1.2/32",
+            lcl_port=5000,
+            rmt_port=5000,
+            action_index=1,
+            appns_index=app0.appns_index,
+            scope=VppEnum.vl_api_session_rule_scope_t.SESSION_RULE_SCOPE_API_GLOBAL,
+            is_add=1,
+        )
+        dump = self.vapi.session_rules_v2_dump()
+        # session table should contain 3 appns's indices (default, app0, and app1)
+        self.assertEqual(len(dump[1].appns_index), 3)
+        self.assertEqual(dump[1].count, 3)
+        self.assertEqual(dump[1].appns_index[0], 0)
+        self.assertEqual(dump[1].appns_index[1], app0.appns_index)
+        self.assertEqual(dump[1].appns_index[2], app1.appns_index)
+
+        # remove the last namespace
+        self.vapi.app_namespace_add_del_v4(
+            namespace_id="1", sw_if_index=self.loop0.sw_if_index, is_add=0
+        )
+        dump = self.vapi.session_rules_v2_dump()
+        # session table should contain the remainging appns's index
+        self.assertEqual(len(dump[1].appns_index), 2)
+        self.assertEqual(dump[1].count, 2)
+        self.assertEqual(dump[1].appns_index[0], 0)
+        self.assertEqual(dump[1].appns_index[1], app0.appns_index)
+
+        self.vapi.app_namespace_add_del_v4(
+            namespace_id="0", sw_if_index=self.loop0.sw_if_index, is_add=0
+        )
+        self.vapi.session_rule_add_del(
+            transport_proto=VppEnum.vl_api_transport_proto_t.TRANSPORT_PROTO_API_TCP,
+            lcl="172.100.1.1/32",
+            rmt="172.100.1.2/32",
+            lcl_port=5000,
+            rmt_port=5000,
+            action_index=1,
+            appns_index=app0.appns_index,
+            scope=VppEnum.vl_api_session_rule_scope_t.SESSION_RULE_SCOPE_API_GLOBAL,
+            is_add=0,
+        )
+
+
+@tag_fixme_vpp_workers
 class TestSessionUnitTests(VppAsfTestCase):
     """Session Unit Tests Case"""
 
diff --git a/test/asf/test_session_sdl.py b/test/asf/test_session_sdl.py
index c03dc83..952ad10 100644
--- a/test/asf/test_session_sdl.py
+++ b/test/asf/test_session_sdl.py
@@ -78,10 +78,10 @@
         )
 
         # Configure namespaces
-        self.vapi.app_namespace_add_del_v4(
+        app0 = self.vapi.app_namespace_add_del_v4(
             namespace_id="0", sw_if_index=self.loop0.sw_if_index
         )
-        self.vapi.app_namespace_add_del_v4(
+        app1 = self.vapi.app_namespace_add_del_v4(
             namespace_id="1", sw_if_index=self.loop1.sw_if_index
         )
 
@@ -120,8 +120,12 @@
         )
         self.apply_rules(rules, is_add=1, appns_index=0)
 
-        filter = self.vapi.session_sdl_v2_dump()
+        filter = self.vapi.session_sdl_v3_dump()
         self.assertEqual(filter[0].rmt, IPv4Network(self.loop1.local_ip4 + "/32"))
+        self.assertEqual(len(filter[0].appns_index), 2)
+        self.assertEqual(filter[0].count, 2)
+        self.assertEqual(filter[0].appns_index[0], 0)
+        self.assertEqual(filter[0].appns_index[1], app0.appns_index)
 
         # irrelevant rules - add 64k entries in one API call
         rules = []
@@ -158,6 +162,11 @@
         self.vapi.app_namespace_add_del_v4(
             is_add=0, namespace_id="0", sw_if_index=self.loop0.sw_if_index
         )
+        filter = self.vapi.session_sdl_v3_dump()
+        self.assertEqual(len(filter[0].appns_index), 1)
+        self.assertEqual(filter[0].count, 1)
+        self.assertEqual(filter[0].appns_index[0], 0)
+
         self.vapi.app_namespace_add_del_v4(
             is_add=0, namespace_id="1", sw_if_index=self.loop1.sw_if_index
         )