session: lookup/rules table improvements and cleanup
[vpp.git] / src / vnet / session / session_test.c
index bdd4f05..d592487 100644 (file)
@@ -98,6 +98,72 @@ static session_cb_vft_t dummy_session_cbs = {
 };
 /* *INDENT-ON* */
 
+static int
+session_test_basic (vlib_main_t * vm, unformat_input_t * input)
+{
+  session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
+  u64 options[SESSION_OPTIONS_N_OPTIONS], bind4_handle, bind6_handle;
+  u8 segment_name[128];
+  clib_error_t *error = 0;
+  u32 server_index;
+
+  memset (options, 0, sizeof (options));
+  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
+  vnet_app_attach_args_t attach_args = {
+    .api_client_index = ~0,
+    .options = options,
+    .namespace_id = 0,
+    .session_cb_vft = &dummy_session_cbs,
+    .segment_name = segment_name,
+  };
+
+  error = vnet_application_attach (&attach_args);
+  SESSION_TEST ((error == 0), "app attached");
+  server_index = attach_args.app_index;
+
+  server_sep.is_ip4 = 1;
+  vnet_bind_args_t bind_args = {
+    .sep = server_sep,
+    .app_index = 0,
+  };
+
+  bind_args.app_index = server_index;
+  error = vnet_bind (&bind_args);
+  SESSION_TEST ((error == 0), "server bind4 should work");
+  bind4_handle = bind_args.handle;
+
+  error = vnet_bind (&bind_args);
+  SESSION_TEST ((error != 0), "double server bind4 should not work");
+
+  bind_args.sep.is_ip4 = 0;
+  error = vnet_bind (&bind_args);
+  SESSION_TEST ((error == 0), "server bind6 should work");
+  bind6_handle = bind_args.handle;
+
+  error = vnet_bind (&bind_args);
+  SESSION_TEST ((error != 0), "double server bind6 should not work");
+
+  vnet_unbind_args_t unbind_args = {
+    .handle = bind4_handle,
+    .app_index = server_index,
+  };
+  error = vnet_unbind (&unbind_args);
+  SESSION_TEST ((error == 0), "unbind4 should work");
+
+  unbind_args.handle = bind6_handle;
+  error = vnet_unbind (&unbind_args);
+  SESSION_TEST ((error == 0), "unbind6 should work");
+
+  vnet_app_detach_args_t detach_args = {
+    .app_index = server_index,
+  };
+  vnet_application_detach (&detach_args);
+  return 0;
+}
+
 static int
 session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
 {
@@ -124,7 +190,7 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
   memset (options, 0, sizeof (options));
   memset (intf_mac, 0, sizeof (intf_mac));
 
-  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_BUILTIN_APP;
+  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
   vnet_app_attach_args_t attach_args = {
     .api_client_index = ~0,
@@ -263,8 +329,7 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
                "the server");
   server_local_st_index = application_local_session_table (server);
   local_listener =
-    session_lookup_local_session_endpoint (server_local_st_index,
-                                          &server_sep);
+    session_lookup_local_endpoint (server_local_st_index, &server_sep);
   SESSION_TEST ((local_listener != SESSION_INVALID_INDEX),
                "listener should exist in local table");
 
@@ -316,8 +381,7 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
   s = session_lookup_listener (server_st_index, &server_sep);
   SESSION_TEST ((s == 0), "listener should not exist in global table");
   local_listener =
-    session_lookup_local_session_endpoint (server_local_st_index,
-                                          &server_sep);
+    session_lookup_local_endpoint (server_local_st_index, &server_sep);
   SESSION_TEST ((s == 0), "listener should not exist in local table");
 
   detach_args.app_index = server_index;
@@ -342,8 +406,7 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
   SESSION_TEST ((s == 0), "listener should not exist in global table");
   server_local_st_index = application_local_session_table (server);
   local_listener =
-    session_lookup_local_session_endpoint (server_local_st_index,
-                                          &server_sep);
+    session_lookup_local_endpoint (server_local_st_index, &server_sep);
   SESSION_TEST ((local_listener != SESSION_INVALID_INDEX),
                "listener should exist in local table");
 
@@ -352,8 +415,7 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
   SESSION_TEST ((error == 0), "unbind should work");
 
   local_listener =
-    session_lookup_local_session_endpoint (server_local_st_index,
-                                          &server_sep);
+    session_lookup_local_endpoint (server_local_st_index, &server_sep);
   SESSION_TEST ((local_listener == SESSION_INVALID_INDEX),
                "listener should not exist in local table");
 
@@ -424,8 +486,7 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
                "the server");
   server_local_st_index = application_local_session_table (server);
   local_listener =
-    session_lookup_local_session_endpoint (server_local_st_index,
-                                          &server_sep);
+    session_lookup_local_endpoint (server_local_st_index, &server_sep);
   SESSION_TEST ((local_listener != SESSION_INVALID_INDEX),
                "zero listener should exist in local table");
   detach_args.app_index = server_index;
@@ -506,8 +567,7 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
                action_index - 1);
 
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 1),
                "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
                res);
@@ -561,8 +621,7 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
    * and  3.3.3.3 1234 7.7.7.7 4321
    */
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 3),
                "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
                res);
@@ -570,15 +629,14 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_lkup,
+    session_rules_table_lookup4 (srt, &lcl_lkup,
                                 &rmt_lkup, lcl_port, rmt_port);
   SESSION_TEST ((res == 1),
                "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
                res);
 
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip3, &rmt_ip3,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
   SESSION_TEST ((res == 6),
                "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
                "should be 6 (updated): %d", res);
@@ -598,13 +656,12 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
                action_index - 1);
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 7),
                "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
                " be 7 (lpm dst): %d", res);
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
                                 lcl_port + 1, rmt_port);
   SESSION_TEST ((res == 7),
                "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
@@ -645,23 +702,21 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
                action_index - 1);
 
   if (verbose)
-    session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4,
-                                 TRANSPORT_PROTO_TCP);
+    session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
 
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 3),
                "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
                res);
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
                                 lcl_port + 1, rmt_port);
   SESSION_TEST ((res == 9),
                "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
                res);
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
                                 lcl_port + 1, rmt_port + 1);
   SESSION_TEST ((res == 8),
                "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
@@ -679,8 +734,7 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
   error = session_rules_table_add_del (srt, &args);
   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 3),
                "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
                res);
@@ -691,8 +745,7 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
   error = session_rules_table_add_del (srt, &args);
   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 3),
                "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
                res);
@@ -710,8 +763,7 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
   error = session_rules_table_add_del (srt, &args);
   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
   res =
-    session_rules_table_lookup4 (srt, TRANSPORT_PROTO_TCP, &lcl_ip, &rmt_ip,
-                                lcl_port, rmt_port);
+    session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
 
   return 0;
@@ -732,6 +784,19 @@ session_test_rules (vlib_main_t * vm, unformat_input_t * input)
   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;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "verbose"))
+       verbose = 1;
+      else
+       {
+         vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
+                          input);
+         return -1;
+       }
+    }
 
   server_sep.is_ip4 = 1;
   server_sep.port = dummy_port;
@@ -753,7 +818,7 @@ session_test_rules (vlib_main_t * vm, unformat_input_t * input)
   /*
    * Attach server with global and local default scope
    */
-  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_BUILTIN_APP;
+  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
@@ -826,7 +891,7 @@ session_test_rules (vlib_main_t * vm, unformat_input_t * input)
     .port = rmt_port,
     .transport_proto = TRANSPORT_PROTO_TCP,
   };
-  app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
                "should not work (global scope)");
 
@@ -834,7 +899,7 @@ session_test_rules (vlib_main_t * vm, unformat_input_t * input)
                                      &rmt_pref.fp_addr.ip4, lcl_port + 1,
                                      rmt_port, TRANSPORT_PROTO_TCP, 0);
   SESSION_TEST ((tc == 0),
-               "optimized lookup for wrong lcl port + 1 should not" " work");
+               "optimized lookup for wrong lcl port + 1 should not work");
 
   /*
    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
@@ -849,50 +914,320 @@ session_test_rules (vlib_main_t * vm, unformat_input_t * input)
                                      rmt_port, TRANSPORT_PROTO_TCP, 0);
   SESSION_TEST ((tc->c_index == listener->connection_index),
                "optimized lookup for lcl port + 1 should work");
-  app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
-  SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
-               "should not work (constrained lcl ip)");
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
+  SESSION_TEST ((app_index == server_index), "local session endpoint lookup "
+               "should work (lcl ip was zeroed)");
+
+  /*
+   * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
+   */
+  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_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",
+               args.table_args.action_index);
+
+  if (verbose)
+    {
+      session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
+                                      TRANSPORT_PROTO_TCP);
+      session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
+                                            TRANSPORT_PROTO_TCP);
+    }
+
+  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 fail (deny rule)");
+  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);
+  SESSION_TEST ((tc->c_index == listener->connection_index),
+               "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should work");
 
   /*
    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
    */
+  args.table_args.lcl_port = 0;
   args.table_args.lcl.fp_len = 0;
+  args.table_args.rmt.fp_len = 16;
+  args.table_args.action_index = -1;
   error = vnet_session_rule_add_del (&args);
   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
                args.table_args.action_index);
-  app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
-  SESSION_TEST ((app_index == server_index), "local session endpoint lookup "
-               "should work");
+
+  if (verbose)
+    {
+      session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
+                                      TRANSPORT_PROTO_TCP);
+      session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
+                                            TRANSPORT_PROTO_TCP);
+    }
+
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
+  SESSION_TEST ((app_index == APP_DROP_INDEX),
+               "local session endpoint lookup " "should return deny");
+
+  /*
+   * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
+   */
+  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 deny");
+
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
+  SESSION_TEST ((app_index == APP_INVALID_INDEX),
+               "local session endpoint lookup should return invalid");
 
   /*
    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
    * 1.2.3.4/16 1234 5.6.7.8/16 4321
    */
   args.table_args.is_add = 0;
+  args.table_args.lcl_port = 0;
+  args.table_args.lcl.fp_addr.ip4 = lcl_ip;
+  args.table_args.lcl.fp_len = 0;
+  args.table_args.rmt.fp_addr.ip4 = rmt_ip;
+  args.table_args.rmt.fp_len = 16;
+  args.table_args.rmt_port = 4321;
   error = vnet_session_rule_add_del (&args);
   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
-  app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
+  app_index = session_lookup_local_endpoint (local_ns_index, &sep);
   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
                "should not work (removed)");
 
   args.table_args.is_add = 0;
   args.table_args.lcl = lcl_pref;
+
+  args.table_args.is_add = 0;
+  args.table_args.lcl_port = 0;
+  args.table_args.lcl.fp_addr.ip4 = lcl_ip;
+  args.table_args.lcl.fp_len = 16;
+  args.table_args.rmt.fp_addr.ip4 = rmt_ip;
+  args.table_args.rmt.fp_len = 16;
+  args.table_args.rmt_port = 4321;
   error = vnet_session_rule_add_del (&args);
   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);
-  SESSION_TEST ((tc == 0), "optimized lookup for lcl port + 1 should not "
+  SESSION_TEST ((tc == 0),
+               "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
                "work (del)");
 
   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 = 16;
+  args.table_args.rmt.fp_addr.ip4 = rmt_ip;
+  args.table_args.rmt.fp_len = 16;
+  args.table_args.rmt_port = 4321;
   error = vnet_session_rule_add_del (&args);
   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);
-  SESSION_TEST ((tc == 0), "optimized lookup should not work (del)");
+  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);
+  SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
+               " not work (no-rule)");
+
+  /*
+   * Test tags. Add/del rule with tag
+   */
+  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 = 16;
+  args.table_args.rmt.fp_addr.ip4 = rmt_ip;
+  args.table_args.rmt.fp_len = 16;
+  args.table_args.rmt_port = 4321;
+  args.table_args.tag = format (0, "test_rule");
+  args.table_args.action_index = server_index;
+  error = vnet_session_rule_add_del (&args);
+  SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
+               "tag test_rule");
+  if (verbose)
+    {
+      session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
+                                      TRANSPORT_PROTO_TCP);
+      session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
+                                            TRANSPORT_PROTO_TCP);
+    }
+  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->c_index == listener->connection_index),
+               "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
+
+  args.table_args.is_add = 0;
+  args.table_args.lcl_port += 1;
+  error = vnet_session_rule_add_del (&args);
+  if (verbose)
+    {
+      session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
+                                      TRANSPORT_PROTO_TCP);
+      session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
+                                            TRANSPORT_PROTO_TCP);
+    }
+  SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
+               "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);
+  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);
+  vnet_app_detach_args_t detach_args = {
+    .app_index = server_index,
+  };
+  vnet_application_detach (&detach_args);
+  return 0;
+}
+
+static int
+session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
+{
+  u64 options[SESSION_OPTIONS_N_OPTIONS];
+  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;
+  stream_session_t *s;
+  transport_connection_t *tc;
+  u16 lcl_port = 1234, rmt_port = 4321;
+  app_namespace_t *app_ns;
+  int verbose = 0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "verbose"))
+       verbose = 1;
+      else
+       {
+         vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
+                          input);
+         return -1;
+       }
+    }
+
+  ip4_address_t lcl_ip = {
+    .as_u32 = clib_host_to_net_u32 (0x01020304),
+  };
+  ip4_address_t rmt_ip = {
+    .as_u32 = clib_host_to_net_u32 (0x05060708),
+  };
+  fib_prefix_t rmt_pref = {
+    .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
+    .fp_len = 16,
+    .fp_proto = FIB_PROTOCOL_IP4,
+  };
+  session_endpoint_t sep = {
+    .ip = rmt_pref.fp_addr,
+    .is_ip4 = 1,
+    .port = rmt_port,
+    .transport_proto = TRANSPORT_PROTO_TCP,
+  };
+
+  /*
+   * Create loopback interface
+   */
+  memset (intf_mac, 0, sizeof (intf_mac));
+  if (vnet_create_loopback_interface (&sw_if_index, intf_mac, 0, 0))
+    {
+      clib_warning ("couldn't create loopback. stopping the test!");
+      return 0;
+    }
+  vnet_sw_interface_set_flags (vnet_get_main (), sw_if_index,
+                              VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+  ip4_add_del_interface_address (vlib_get_main (), sw_if_index, &lcl_ip,
+                                24, 0);
+
+  app_ns = app_namespace_get_default ();
+  app_ns->sw_if_index = sw_if_index;
+
+  memset (options, 0, sizeof (options));
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
+  options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
+  vnet_app_attach_args_t attach_args = {
+    .api_client_index = ~0,
+    .options = options,
+    .namespace_id = 0,
+    .session_cb_vft = &dummy_session_cbs,
+    .segment_name = segment_name,
+  };
+
+  attach_args.api_client_index = dummy_server_api_index;
+  error = vnet_application_attach (&attach_args);
+  SESSION_TEST ((error == 0), "server attachment should work");
+  server_index = attach_args.app_index;
+
+  if (verbose)
+    session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
+                                    TRANSPORT_PROTO_TCP);
+
+  tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
+                                     TRANSPORT_PROTO_TCP, 0);
+  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);
+  s = listen_session_get (sst, tc->s_index);
+  SESSION_TEST ((s->app_index == server_index), "lookup should return the"
+               " server");
+
+  tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
+                                     TRANSPORT_PROTO_TCP, 0);
+  SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
+               " not work");
+
+  if (verbose)
+    session_lookup_dump_local_rules_table (app_ns->local_table_index,
+                                          FIB_PROTOCOL_IP4,
+                                          TRANSPORT_PROTO_TCP);
+  app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
+  SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
+               " should work");
+
+  vnet_app_detach_args_t detach_args = {
+    .app_index = server_index,
+  };
+  vnet_application_detach (&detach_args);
+
+  if (verbose)
+    session_lookup_dump_local_rules_table (app_ns->local_table_index,
+                                          FIB_PROTOCOL_IP4,
+                                          TRANSPORT_PROTO_TCP);
+
+  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");
+
   return 0;
 }
 
@@ -906,18 +1241,34 @@ session_test (vlib_main_t * vm,
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "namespace"))
-       {
-         res = session_test_namespace (vm, input);
-       }
+      if (unformat (input, "basic"))
+       res = session_test_basic (vm, input);
+      else if (unformat (input, "namespace"))
+       res = session_test_namespace (vm, input);
       else if (unformat (input, "rules-table"))
        res = session_test_rule_table (vm, input);
       else if (unformat (input, "rules"))
        res = session_test_rules (vm, input);
+      else if (unformat (input, "proxy"))
+       res = session_test_proxy (vm, input);
+      else if (unformat (input, "all"))
+       {
+         if ((res = session_test_basic (vm, input)))
+           goto done;
+         if ((res = session_test_namespace (vm, input)))
+           goto done;
+         if ((res = session_test_rule_table (vm, input)))
+           goto done;
+         if ((res = session_test_rules (vm, input)))
+           goto done;
+         if ((res = session_test_proxy (vm, input)))
+           goto done;
+       }
       else
        break;
     }
 
+done:
   if (res)
     return clib_error_return (0, "Session unit test failed");
   return 0;