session/tcp: filtering improvements

- make allow action explicit (-3)
- add session lookup is_filtered return flag that is set if lookup hit a
  deny filter
- change tcp logic to drop filtered packets when punting is enabled

Change-Id: Ic38f294424663a4e108439b7571511f46f8e0be1
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 eaf09e8..21c1cbc 100644
--- a/src/vnet/session/application_namespace.c
+++ b/src/vnet/session/application_namespace.c
@@ -248,7 +248,8 @@
 format_app_namespace (u8 * s, va_list * args)
 {
   app_namespace_t *app_ns = va_arg (*args, app_namespace_t *);
-  s = format (s, "%-20v%-20lu%-20u", app_ns->ns_id, app_ns->ns_secret,
+  s = format (s, "%-20v%-10u%-20lu%-20u", app_ns->ns_id,
+	      app_namespace_index (app_ns), app_ns->ns_secret,
 	      app_ns->sw_if_index);
   return s;
 }
@@ -301,9 +302,10 @@
       goto done;
     }
 
-  vlib_cli_output (vm, "%-20s%-20s%-20s", "Namespace", "Secret",
-		   "sw_if_index");
 do_ns_list:
+  vlib_cli_output (vm, "%-20s%-10s%-20s%-20s", "Namespace", "Index", "Secret",
+		   "sw_if_index");
+
   /* *INDENT-OFF* */
   pool_foreach (app_ns, app_namespace_pool, ({
     vlib_cli_output (vm, "%U", format_app_namespace, app_ns);
diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c
index 30e3913..2e4e96a 100644
--- a/src/vnet/session/session_lookup.c
+++ b/src/vnet/session/session_lookup.c
@@ -378,12 +378,28 @@
   return session_lookup_del_connection (ts);
 }
 
-static u32
-session_lookup_action_to_session_index (u32 action_index)
+static u8
+session_lookup_action_index_is_valid (u32 action_index)
 {
-  if (action_index != SESSION_RULES_TABLE_ACTION_DROP)
-    return action_index;
-  return SESSION_INVALID_INDEX;
+  if (action_index == SESSION_RULES_TABLE_ACTION_ALLOW
+      || action_index == SESSION_RULES_TABLE_INVALID_INDEX)
+    return 0;
+  return 1;
+}
+
+static u32
+session_lookup_action_to_app_index (u32 action_index)
+{
+  switch (action_index)
+    {
+    case SESSION_RULES_TABLE_ACTION_DROP:
+      return APP_DROP_INDEX;
+    case SESSION_RULES_TABLE_ACTION_ALLOW:
+    case SESSION_RULES_TABLE_INVALID_INDEX:
+      return APP_INVALID_INDEX;
+    default:
+      return action_index;
+    }
 }
 
 static stream_session_t *
@@ -391,7 +407,7 @@
 				   u8 transport_proto)
 {
   application_t *app;
-  app = application_get (app_index);
+  app = application_get_if_valid (app_index);
   if (!app)
     return 0;
 
@@ -402,10 +418,10 @@
 session_lookup_action_to_session (u32 action_index, u8 fib_proto,
 				  u8 transport_proto)
 {
-  u32 session_index;
-  session_index = session_lookup_action_to_session_index (action_index);
+  u32 app_index;
+  app_index = session_lookup_action_to_app_index (action_index);
   /* Nothing sophisticated for now, action index is app index */
-  return session_lookup_app_listen_session (session_index, fib_proto,
+  return session_lookup_app_listen_session (app_index, fib_proto,
 					    transport_proto);
 }
 
@@ -415,26 +431,26 @@
 				     ip4_address_t * rmt, u16 rmt_port)
 {
   session_rules_table_t *srt = &st->session_rules[proto];
-  u32 action_index, session_index;
+  u32 action_index, app_index;
   action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port,
 					      rmt_port);
-  session_index = session_lookup_action_to_session_index (action_index);
+  app_index = session_lookup_action_to_app_index (action_index);
   /* Nothing sophisticated for now, action index is app index */
-  return session_lookup_app_listen_session (session_index, FIB_PROTOCOL_IP4,
+  return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP4,
 					    proto);
 }
 
 stream_session_t *
-session_lookup_rules_table6 (session_table_t * st, u8 proto,
-			     ip6_address_t * lcl, u16 lcl_port,
-			     ip6_address_t * rmt, u16 rmt_port)
+session_lookup_rules_table_session6 (session_table_t * st, u8 proto,
+				     ip6_address_t * lcl, u16 lcl_port,
+				     ip6_address_t * rmt, u16 rmt_port)
 {
   session_rules_table_t *srt = &st->session_rules[proto];
-  u32 action_index, session_index;
+  u32 action_index, app_index;
   action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port,
 					      rmt_port);
-  session_index = session_lookup_action_to_session_index (action_index);
-  return session_lookup_app_listen_session (session_index, FIB_PROTOCOL_IP6,
+  app_index = session_lookup_action_to_app_index (action_index);
+  return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP6,
 					    proto);
 }
 
@@ -477,8 +493,8 @@
 	  srt = &st->session_rules[sep->transport_proto];
 	  ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
 					    sep->port);
-	  if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
-	    return session_lookup_action_to_session_index (ai);
+	  if (session_lookup_action_index_is_valid (ai))
+	    return session_lookup_action_to_app_index (ai);
 	}
     }
   else
@@ -497,8 +513,8 @@
 	  srt = &st->session_rules[sep->transport_proto];
 	  ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
 					    sep->port);
-	  if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
-	    return session_lookup_action_to_session_index (ai);
+	  if (session_lookup_action_index_is_valid (ai))
+	    return session_lookup_action_to_app_index (ai);
 	}
     }
   return SESSION_INVALID_HANDLE;
@@ -545,10 +561,8 @@
       srt = &st->session_rules[sep->transport_proto];
       ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
 					sep->port);
-      if (ai == SESSION_RULES_TABLE_ACTION_DROP)
-	return APP_DROP_INDEX;
-      if (ai != SESSION_RULES_TABLE_ACTION_NONE)
-	return session_lookup_action_to_session_index (ai);
+      if (session_lookup_action_index_is_valid (ai))
+	return session_lookup_action_to_app_index (ai);
 
       /*
        * Check if session endpoint is a listener
@@ -585,10 +599,8 @@
       srt = &st->session_rules[sep->transport_proto];
       ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
 					sep->port);
-      if (ai == SESSION_RULES_TABLE_ACTION_DROP)
-	return APP_DROP_INDEX;
-      if (ai != SESSION_RULES_TABLE_INVALID_INDEX)
-	return session_lookup_action_to_session_index (ai);
+      if (session_lookup_action_index_is_valid (ai))
+	return session_lookup_action_to_app_index (ai);
 
       make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
 			   sep->transport_proto);
@@ -828,13 +840,15 @@
  * @param rmt_port	remote port
  * @param proto		transport protocol (e.g., tcp, udp)
  * @param thread_index	thread index for request
+ * @param is_filtered	return flag that indicates if connection was filtered.
  *
  * @return pointer to transport connection, if one is found, 0 otherwise
  */
 transport_connection_t *
 session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl,
 			       ip4_address_t * rmt, u16 lcl_port,
-			       u16 rmt_port, u8 proto, u32 thread_index)
+			       u16 rmt_port, u8 proto, u32 thread_index,
+			       u8 * is_filtered)
 {
   session_table_t *st;
   session_kv4_t kv4;
@@ -874,14 +888,14 @@
    */
   action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
 					      rmt, lcl_port, rmt_port);
-  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
-    return 0;
-  if (action_index != SESSION_RULES_TABLE_ACTION_NONE)
+  if (session_lookup_action_index_is_valid (action_index))
     {
-      s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
-					    proto);
-      if (s)
+      if ((*is_filtered = (action_index == SESSION_RULES_TABLE_ACTION_DROP)))
+	return 0;
+      if ((s = session_lookup_action_to_session (action_index,
+						 FIB_PROTOCOL_IP4, proto)))
 	return tp_vfts[s->session_type].get_listener (s->connection_index);
+      return 0;
     }
 
   /*
@@ -952,14 +966,14 @@
    */
   action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
 					      rmt, lcl_port, rmt_port);
-  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
-    return 0;
-  if (action_index != SESSION_RULES_TABLE_ACTION_NONE)
+  if (session_lookup_action_index_is_valid (action_index))
     {
-      s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
-					    proto);
-      if (s)
+      if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+	return 0;
+      if ((s = session_lookup_action_to_session (action_index,
+						 FIB_PROTOCOL_IP4, proto)))
 	return tp_vfts[s->session_type].get_listener (s->connection_index);
+      return 0;
     }
 
   /*
@@ -1012,13 +1026,12 @@
    */
   action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
 					      rmt, lcl_port, rmt_port);
-  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
-    return 0;
-  if (action_index != SESSION_RULES_TABLE_ACTION_NONE)
+  if (session_lookup_action_index_is_valid (action_index))
     {
-      if ((s = session_lookup_action_to_session (action_index,
-						 FIB_PROTOCOL_IP4, proto)))
-	return s;
+      if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+	return 0;
+      return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
+					       proto);
     }
 
   /*
@@ -1058,7 +1071,8 @@
 transport_connection_t *
 session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl,
 			       ip6_address_t * rmt, u16 lcl_port,
-			       u16 rmt_port, u8 proto, u32 thread_index)
+			       u16 rmt_port, u8 proto, u32 thread_index,
+			       u8 * is_filtered)
 {
   session_table_t *st;
   stream_session_t *s;
@@ -1091,14 +1105,14 @@
   /* Check the session rules table */
   action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
 					      rmt, lcl_port, rmt_port);
-  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
-    return 0;
-  if (action_index != SESSION_RULES_TABLE_ACTION_NONE)
+  if (session_lookup_action_index_is_valid (action_index))
     {
-      s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
-					    proto);
-      if (s)
+      if ((*is_filtered = (action_index == SESSION_RULES_TABLE_ACTION_DROP)))
+	return 0;
+      if ((s = session_lookup_action_to_session (action_index,
+						 FIB_PROTOCOL_IP6, proto)))
 	return tp_vfts[s->session_type].get_listener (s->connection_index);
+      return 0;
     }
 
   /* If nothing is found, check if any listener is available */
@@ -1160,14 +1174,14 @@
   /* Check the session rules table */
   action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
 					      rmt, lcl_port, rmt_port);
-  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
-    return 0;
-  if (action_index != SESSION_RULES_TABLE_ACTION_NONE)
+  if (session_lookup_action_index_is_valid (action_index))
     {
-      s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
-					    proto);
-      if (s)
+      if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+	return 0;
+      if ((s = session_lookup_action_to_session (action_index,
+						 FIB_PROTOCOL_IP6, proto)))
 	return tp_vfts[s->session_type].get_listener (s->connection_index);
+      return 0;
     }
 
   /* If nothing is found, check if any listener is available */
@@ -1213,14 +1227,12 @@
   /* Check the session rules table */
   action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
 					      rmt, lcl_port, rmt_port);
-  if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
-    return 0;
-  if (action_index != SESSION_RULES_TABLE_ACTION_NONE)
+  if (session_lookup_action_index_is_valid (action_index))
     {
-      if ((s =
-	   session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
-					     proto)))
-	return s;
+      if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+	return 0;
+      return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6,
+					       proto);
     }
 
   /* If nothing is found, check if any listener is available */
@@ -1639,8 +1651,8 @@
 VLIB_CLI_COMMAND (show_session_rules_command, static) =
 {
   .path = "show session rules",
-  .short_help = "show session rules [appns <id> proto <proto> <lcl-ip/plen>"
-      " <lcl-port> <rmt-ip/plen> <rmt-port>]",
+  .short_help = "show session rules [<proto> appns <id> <lcl-ip/plen> "
+      "<lcl-port> <rmt-ip/plen> <rmt-port> scope <scope>]",
   .function = show_session_rules_command_fn,
 };
 /* *INDENT-ON* */
diff --git a/src/vnet/session/session_lookup.h b/src/vnet/session/session_lookup.h
index 00ef19f..1bdf6d1 100644
--- a/src/vnet/session/session_lookup.h
+++ b/src/vnet/session/session_lookup.h
@@ -32,7 +32,8 @@
 						       ip4_address_t * rmt,
 						       u16 lcl_port,
 						       u16 rmt_port, u8 proto,
-						       u32 thread_index);
+						       u32 thread_index,
+						       u8 * is_filtered);
 transport_connection_t *session_lookup_connection4 (u32 fib_index,
 						    ip4_address_t * lcl,
 						    ip4_address_t * rmt,
@@ -43,7 +44,8 @@
 						       ip6_address_t * rmt,
 						       u16 lcl_port,
 						       u16 rmt_port, u8 proto,
-						       u32 thread_index);
+						       u32 thread_index,
+						       u8 * is_filtered);
 transport_connection_t *session_lookup_connection6 (u32 fib_index,
 						    ip6_address_t * lcl,
 						    ip6_address_t * rmt,
diff --git a/src/vnet/session/session_rules_table.h b/src/vnet/session/session_rules_table.h
index ecd2d9b..9088afc 100644
--- a/src/vnet/session/session_rules_table.h
+++ b/src/vnet/session/session_rules_table.h
@@ -56,8 +56,8 @@
 
 #define SESSION_RULE_TAG_MAX_LEN 64
 #define SESSION_RULES_TABLE_INVALID_INDEX MMA_TABLE_INVALID_INDEX
-#define SESSION_RULES_TABLE_ACTION_DROP (((u32)~0) - 1)
-#define SESSION_RULES_TABLE_ACTION_NONE SESSION_RULES_TABLE_INVALID_INDEX
+#define SESSION_RULES_TABLE_ACTION_DROP (MMA_TABLE_INVALID_INDEX - 1)
+#define SESSION_RULES_TABLE_ACTION_ALLOW (MMA_TABLE_INVALID_INDEX - 2)
 
 typedef struct _session_rules_table_add_del_args
 {
diff --git a/src/vnet/session/session_test.c b/src/vnet/session/session_test.c
index 8194a31..58d0d28 100644
--- a/src/vnet/session/session_test.c
+++ b/src/vnet/session/session_test.c
@@ -496,7 +496,8 @@
    * Cleanup
    */
   vec_free (ns_id);
-  vnet_delete_loopback_interface (sw_if_index);
+  /* fails in multi core scenarions .. */
+  /* vnet_delete_loopback_interface (sw_if_index); */
   return 0;
 }
 
@@ -780,11 +781,11 @@
   transport_connection_t *tc;
   u32 dummy_port = 1111;
   clib_error_t *error = 0;
-  u8 segment_name[128];
+  u8 segment_name[128], is_filtered = 0;
   stream_session_t *listener, *s;
   app_namespace_t *default_ns = app_namespace_get_default ();
   u32 local_ns_index = default_ns->local_table_index;
-  int verbose = 0;
+  int verbose = 0, rv;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -852,7 +853,8 @@
 
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
 
   /*
@@ -878,7 +880,8 @@
 		"optimized lookup should return the listener");
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc->c_index == listener->connection_index),
 		"lookup should return the listener");
   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
@@ -897,7 +900,8 @@
 
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port + 1,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0),
 		"optimized lookup for wrong lcl port + 1 should not work");
 
@@ -911,7 +915,8 @@
 		args.table_args.action_index);
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port + 1,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc->c_index == listener->connection_index),
 		"optimized lookup for lcl port + 1 should work");
   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
@@ -923,12 +928,12 @@
    */
   args.table_args.lcl_port = 1234;
   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
-  args.table_args.lcl.fp_len = 32;
+  args.table_args.lcl.fp_len = 30;
   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
-  args.table_args.rmt.fp_len = 32;
+  args.table_args.rmt.fp_len = 30;
   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
   error = vnet_session_rule_add_del (&args);
-  SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
+  SESSION_TEST ((error == 0), "Add 1.2.3.4/30 1234 5.6.7.8/30 4321 action %d",
 		args.table_args.action_index);
 
   if (verbose)
@@ -941,26 +946,97 @@
 
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
 		"should fail (deny rule)");
+  SESSION_TEST ((is_filtered == 1), "lookup should be filtered (deny)");
+
   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
   SESSION_TEST ((app_index == APP_DROP_INDEX), "lookup for 1.2.3.4/32 1234 "
 		"5.6.7.8/16 4321 in local table should return deny");
-  tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
-				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
-  SESSION_TEST ((tc == 0),
-		"lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 should not work");
+
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port + 1,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc->c_index == listener->connection_index),
 		"lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should work");
 
   /*
+   * "Mask" deny rule with more specific allow:
+   * Add allow rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -3 (allow)
+   */
+  args.table_args.is_add = 1;
+  args.table_args.lcl_port = 1234;
+  args.table_args.lcl.fp_addr.ip4 = lcl_ip;
+  args.table_args.lcl.fp_len = 32;
+  args.table_args.rmt.fp_addr.ip4 = rmt_ip;
+  args.table_args.rmt.fp_len = 32;
+  args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
+  error = vnet_session_rule_add_del (&args);
+  SESSION_TEST ((error == 0), "Add masking rule 1.2.3.4/30 1234 5.6.7.8/32 "
+		"4321 action %d", args.table_args.action_index);
+
+  is_filtered = 0;
+  tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
+				      &rmt_pref.fp_addr.ip4, lcl_port,
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
+  SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
+		"should fail (allow without app)");
+  SESSION_TEST ((is_filtered == 0), "lookup should NOT be filtered");
+
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
+  SESSION_TEST ((app_index == APP_INVALID_INDEX), "lookup for 1.2.3.4/32 1234"
+		" 5.6.7.8/16 4321 in local table should return invalid");
+
+  if (verbose)
+    {
+      vlib_cli_output (vm, "Local rules");
+      session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
+					     TRANSPORT_PROTO_TCP);
+    }
+
+  sep.ip.ip4.as_u32 += 1 << 24;
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
+  SESSION_TEST ((app_index == APP_DROP_INDEX), "lookup for 1.2.3.4/32 1234"
+		" 5.6.7.9/16 4321 in local table should return invalid");
+
+  vnet_connect_args_t connect_args = {
+    .sep = sep,
+    .app_index = attach_args.app_index,
+    .api_context = 0,
+  };
+
+  /* Try connecting */
+  error = vnet_connect (&connect_args);
+  SESSION_TEST ((error != 0), "connect should fail");
+  rv = clib_error_get_code (error);
+  SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
+		"connect should be filtered");
+
+  sep.ip.ip4.as_u32 -= 1 << 24;
+
+
+
+  /*
+   * Delete masking rule: 1.2.3.4/32 1234 5.6.7.8/32 4321 allow
+   */
+  args.table_args.is_add = 0;
+  args.table_args.lcl_port = 1234;
+  args.table_args.lcl.fp_addr.ip4 = lcl_ip;
+  args.table_args.lcl.fp_len = 32;
+  args.table_args.rmt.fp_addr.ip4 = rmt_ip;
+  args.table_args.rmt.fp_len = 32;
+  error = vnet_session_rule_add_del (&args);
+  SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 allow");
+
+
+  /*
    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
    */
+  args.table_args.is_add = 1;
   args.table_args.lcl_port = 0;
   args.table_args.lcl.fp_len = 0;
   args.table_args.rmt.fp_len = 16;
@@ -979,7 +1055,7 @@
 
   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
   SESSION_TEST ((app_index == APP_DROP_INDEX),
-		"local session endpoint lookup " "should return deny");
+		"local session endpoint lookup should return deny");
 
   /*
    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
@@ -987,9 +1063,9 @@
   args.table_args.is_add = 0;
   args.table_args.lcl_port = 1234;
   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
-  args.table_args.lcl.fp_len = 32;
+  args.table_args.lcl.fp_len = 30;
   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
-  args.table_args.rmt.fp_len = 32;
+  args.table_args.rmt.fp_len = 30;
   error = vnet_session_rule_add_del (&args);
   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
 
@@ -1028,7 +1104,8 @@
   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port + 1,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0),
 		"lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
 		"work (del)");
@@ -1044,14 +1121,16 @@
   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
 		"not work (del + deny)");
 
   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
 		" not work (no-rule)");
 
@@ -1079,7 +1158,8 @@
     }
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc->c_index == listener->connection_index),
 		"lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
 
@@ -1097,7 +1177,8 @@
 		"tag test_rule");
   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
 				      &rmt_pref.fp_addr.ip4, lcl_port,
-				      rmt_port, TRANSPORT_PROTO_TCP, 0);
+				      rmt_port, TRANSPORT_PROTO_TCP, 0,
+				      &is_filtered);
   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should not"
 		" work (del)");
   vec_free (args.table_args.tag);
@@ -1118,7 +1199,7 @@
   u32 server_index, app_index;
   u32 dummy_server_api_index = ~0, sw_if_index = 0;
   clib_error_t *error = 0;
-  u8 segment_name[128], intf_mac[6], sst;
+  u8 segment_name[128], intf_mac[6], sst, is_filtered = 0;
   stream_session_t *s;
   transport_connection_t *tc;
   u16 lcl_port = 1234, rmt_port = 4321;
@@ -1202,7 +1283,7 @@
     }
 
   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
-				      TRANSPORT_PROTO_TCP, 0);
+				      TRANSPORT_PROTO_TCP, 0, &is_filtered);
   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
 		"successful");
   sst = session_type_from_proto_and_ip (TRANSPORT_PROTO_TCP, 1);
@@ -1211,7 +1292,7 @@
 		" server");
 
   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
-				      TRANSPORT_PROTO_TCP, 0);
+				      TRANSPORT_PROTO_TCP, 0, &is_filtered);
   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
 		" not work");
 
@@ -1237,7 +1318,8 @@
   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
 		"local session endpoint lookup should not work after detach");
-  unformat_free (&tmp_input);
+  if (verbose)
+    unformat_free (&tmp_input);
   return 0;
 }
 
diff --git a/src/vnet/tcp/tcp_error.def b/src/vnet/tcp/tcp_error.def
index a179717..5bff5ee 100644
--- a/src/vnet/tcp/tcp_error.def
+++ b/src/vnet/tcp/tcp_error.def
@@ -40,4 +40,5 @@
 tcp_error (NO_WND, "No window")
 tcp_error (CONNECTION_CLOSED, "Connection closed")
 tcp_error (CREATE_EXISTS, "Connection already exists")
-tcp_error (PUNT, "Packets punted")
\ No newline at end of file
+tcp_error (PUNT, "Packets punted")
+tcp_error (FILTERED, "Packets filtered")
\ No newline at end of file
diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c
index 6d7beba..d3db7ef 100644
--- a/src/vnet/tcp/tcp_input.c
+++ b/src/vnet/tcp/tcp_input.c
@@ -1902,6 +1902,7 @@
   tcp_header_t *tcp;
   transport_connection_t *tconn;
   tcp_connection_t *tc;
+  u8 is_filtered = 0;
   if (is_ip4)
     {
       ip4_header_t *ip4;
@@ -1913,7 +1914,7 @@
 					     tcp->dst_port,
 					     tcp->src_port,
 					     TRANSPORT_PROTO_TCP,
-					     thread_index);
+					     thread_index, &is_filtered);
       tc = tcp_get_connection_from_transport (tconn);
       ASSERT (tcp_lookup_is_valid (tc, tcp));
     }
@@ -1928,7 +1929,7 @@
 					     tcp->dst_port,
 					     tcp->src_port,
 					     TRANSPORT_PROTO_TCP,
-					     thread_index);
+					     thread_index, &is_filtered);
       tc = tcp_get_connection_from_transport (tconn);
       ASSERT (tcp_lookup_is_valid (tc, tcp));
     }
@@ -2939,7 +2940,7 @@
 	  ip4_header_t *ip40;
 	  ip6_header_t *ip60;
 	  u32 error0 = TCP_ERROR_NO_LISTENER, next0 = TCP_INPUT_NEXT_DROP;
-	  u8 flags0;
+	  u8 flags0, is_filtered = 0;
 
 	  bi0 = from[0];
 	  to_next[0] = bi0;
@@ -2968,9 +2969,8 @@
 						     tcp0->dst_port,
 						     tcp0->src_port,
 						     TRANSPORT_PROTO_TCP,
-						     my_thread_index);
-	      tc0 = tcp_get_connection_from_transport (tconn);
-	      ASSERT (tcp_lookup_is_valid (tc0, tcp0));
+						     my_thread_index,
+						     &is_filtered);
 	    }
 	  else
 	    {
@@ -2986,9 +2986,8 @@
 						     tcp0->dst_port,
 						     tcp0->src_port,
 						     TRANSPORT_PROTO_TCP,
-						     my_thread_index);
-	      tc0 = tcp_get_connection_from_transport (tconn);
-	      ASSERT (tcp_lookup_is_valid (tc0, tcp0));
+						     my_thread_index,
+						     &is_filtered);
 	    }
 
 	  /* Length check */
@@ -2999,8 +2998,11 @@
 	    }
 
 	  /* Session exists */
-	  if (PREDICT_TRUE (0 != tc0))
+	  if (PREDICT_TRUE (0 != tconn))
 	    {
+	      tc0 = tcp_get_connection_from_transport (tconn);
+	      ASSERT (tcp_lookup_is_valid (tc0, tcp0));
+
 	      /* Save connection index */
 	      vnet_buffer (b0)->tcp.connection_index = tc0->c_c_index;
 	      vnet_buffer (b0)->tcp.seq_number =
@@ -3032,8 +3034,13 @@
 	    }
 	  else
 	    {
-	      if ((is_ip4 && tm->punt_unknown4) ||
-		  (!is_ip4 && tm->punt_unknown6))
+	      if (is_filtered)
+		{
+		  next0 = TCP_INPUT_NEXT_DROP;
+		  error0 = TCP_ERROR_FILTERED;
+		}
+	      else if ((is_ip4 && tm->punt_unknown4) ||
+		       (!is_ip4 && tm->punt_unknown6))
 		{
 		  next0 = TCP_INPUT_NEXT_PUNT;
 		  error0 = TCP_ERROR_PUNT;
@@ -3044,6 +3051,7 @@
 		  next0 = TCP_INPUT_NEXT_RESET;
 		  error0 = TCP_ERROR_NO_LISTENER;
 		}
+	      tc0 = 0;
 	    }
 
 	done:
@@ -3051,8 +3059,8 @@
 
 	  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
 	    {
-	      tcp_rx_trace_t *t0 =
-		vlib_add_trace (vm, node, b0, sizeof (*t0));
+	      tcp_rx_trace_t *t0;
+	      t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
 	      tcp_set_rx_trace_data (t0, tc0, tcp0, b0, is_ip4);
 	    }
 	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
diff --git a/src/vnet/tcp/tcp_test.c b/src/vnet/tcp/tcp_test.c
index 021f416..e3cdb1b 100644
--- a/src/vnet/tcp/tcp_test.c
+++ b/src/vnet/tcp/tcp_test.c
@@ -1558,7 +1558,7 @@
   transport_connection_t _tc1, *tc1 = &_tc1, _tc2, *tc2 = &_tc2, *tconn;
   tcp_connection_t *tc;
   stream_session_t *s;
-  u8 cmp = 0;
+  u8 cmp = 0, is_filtered = 0;
 
   pool_get (smm->sessions[0], s);
   memset (s, 0, sizeof (*s));
@@ -1601,7 +1601,7 @@
   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
 					 &tc1->rmt_ip.ip4,
 					 tc1->lcl_port, tc1->rmt_port,
-					 tc1->proto, 0);
+					 tc1->proto, 0, &is_filtered);
   cmp = (memcmp (&tconn->rmt_ip, &tc1->rmt_ip, sizeof (tc1->rmt_ip)) == 0);
   TCP_TEST ((cmp), "rmt ip is identical %d", cmp);
   TCP_TEST ((tconn->lcl_port == tc1->lcl_port),
@@ -1614,7 +1614,7 @@
   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
 					 &tc2->rmt_ip.ip4,
 					 tc2->lcl_port, tc2->rmt_port,
-					 tc2->proto, 0);
+					 tc2->proto, 0, &is_filtered);
   TCP_TEST ((tconn == 0), "lookup result should be null");
 
   /*
@@ -1624,12 +1624,12 @@
   tconn = session_lookup_connection_wt4 (0, &tc1->lcl_ip.ip4,
 					 &tc1->rmt_ip.ip4,
 					 tc1->lcl_port, tc1->rmt_port,
-					 tc1->proto, 0);
+					 tc1->proto, 0, &is_filtered);
   TCP_TEST ((tconn == 0), "lookup result should be null");
   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
 					 &tc2->rmt_ip.ip4,
 					 tc2->lcl_port, tc2->rmt_port,
-					 tc2->proto, 0);
+					 tc2->proto, 0, &is_filtered);
   TCP_TEST ((tconn == 0), "lookup result should be null");
 
   /*
@@ -1639,7 +1639,7 @@
   tconn = session_lookup_connection_wt4 (0, &tc2->lcl_ip.ip4,
 					 &tc2->rmt_ip.ip4,
 					 tc2->lcl_port, tc2->rmt_port,
-					 tc2->proto, 0);
+					 tc2->proto, 0, &is_filtered);
   TCP_TEST ((tconn == 0), "lookup result should be null");
 
   return 0;