LCOV - code coverage report
Current view: top level - plugins/unittest - session_test.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 970 1085 89.4 %
Date: 2023-07-05 22:20:52 Functions: 18 22 81.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/session/application_namespace.h>
      17             : #include <vnet/session/application_interface.h>
      18             : #include <vnet/session/application.h>
      19             : #include <vnet/session/session.h>
      20             : #include <vnet/session/session_rules_table.h>
      21             : #include <vnet/tcp/tcp.h>
      22             : #include <sys/epoll.h>
      23             : 
      24             : #define SESSION_TEST_I(_cond, _comment, _args...)               \
      25             : ({                                                              \
      26             :   int _evald = (_cond);                                         \
      27             :   if (!(_evald)) {                                              \
      28             :     fformat(stderr, "FAIL:%d: " _comment "\n",                      \
      29             :             __LINE__, ##_args);                                 \
      30             :   } else {                                                      \
      31             :     fformat(stderr, "PASS:%d: " _comment "\n",                      \
      32             :             __LINE__, ##_args);                                 \
      33             :   }                                                             \
      34             :   _evald;                                                       \
      35             : })
      36             : 
      37             : #define SESSION_TEST(_cond, _comment, _args...)                 \
      38             : {                                                               \
      39             :     if (!SESSION_TEST_I(_cond, _comment, ##_args)) {            \
      40             :         return 1;                                               \
      41             :     }                                                           \
      42             : }
      43             : 
      44             : #define ST_DBG(_comment, _args...)                              \
      45             :     fformat(stderr,  _comment "\n",  ##_args);                        \
      46             : 
      47             : void
      48           0 : placeholder_session_reset_callback (session_t * s)
      49             : {
      50           0 :   clib_warning ("called...");
      51           0 : }
      52             : 
      53             : volatile u32 connected_session_index = ~0;
      54             : volatile u32 connected_session_thread = ~0;
      55             : int
      56           1 : placeholder_session_connected_callback (u32 app_index, u32 api_context,
      57             :                                         session_t * s, session_error_t err)
      58             : {
      59           1 :   if (s)
      60             :     {
      61           1 :       connected_session_index = s->session_index;
      62           1 :       connected_session_thread = s->thread_index;
      63             :     }
      64           1 :   return 0;
      65             : }
      66             : 
      67             : static u32 placeholder_segment_count;
      68             : 
      69             : int
      70           3 : placeholder_add_segment_callback (u32 client_index, u64 segment_handle)
      71             : {
      72           3 :   placeholder_segment_count = 1;
      73           3 :   return 0;
      74             : }
      75             : 
      76             : int
      77           0 : placeholder_del_segment_callback (u32 client_index, u64 segment_handle)
      78             : {
      79           0 :   placeholder_segment_count = 0;
      80           0 :   return 0;
      81             : }
      82             : 
      83             : void
      84           0 : placeholder_session_disconnect_callback (session_t * s)
      85             : {
      86           0 :   clib_warning ("called...");
      87           0 : }
      88             : 
      89             : static u32 placeholder_accept;
      90             : volatile u32 accepted_session_index;
      91             : volatile u32 accepted_session_thread;
      92             : 
      93             : int
      94           2 : placeholder_session_accept_callback (session_t * s)
      95             : {
      96           2 :   placeholder_accept = 1;
      97           2 :   accepted_session_index = s->session_index;
      98           2 :   accepted_session_thread = s->thread_index;
      99           2 :   s->session_state = SESSION_STATE_READY;
     100           2 :   return 0;
     101             : }
     102             : 
     103             : int
     104           0 : placeholder_server_rx_callback (session_t * s)
     105             : {
     106           0 :   clib_warning ("called...");
     107           0 :   return -1;
     108             : }
     109             : 
     110             : /* *INDENT-OFF* */
     111             : static session_cb_vft_t placeholder_session_cbs = {
     112             :   .session_reset_callback = placeholder_session_reset_callback,
     113             :   .session_connected_callback = placeholder_session_connected_callback,
     114             :   .session_accept_callback = placeholder_session_accept_callback,
     115             :   .session_disconnect_callback = placeholder_session_disconnect_callback,
     116             :   .builtin_app_rx_callback = placeholder_server_rx_callback,
     117             :   .add_segment_callback = placeholder_add_segment_callback,
     118             :   .del_segment_callback = placeholder_del_segment_callback,
     119             : };
     120             : /* *INDENT-ON* */
     121             : 
     122             : static int
     123           4 : session_create_lookpback (u32 table_id, u32 * sw_if_index,
     124             :                           ip4_address_t * intf_addr)
     125             : {
     126             :   u8 intf_mac[6];
     127             : 
     128           4 :   clib_memset (intf_mac, 0, sizeof (intf_mac));
     129             : 
     130           4 :   if (vnet_create_loopback_interface (sw_if_index, intf_mac, 0, 0))
     131             :     {
     132           0 :       clib_warning ("couldn't create loopback. stopping the test!");
     133           0 :       return -1;
     134             :     }
     135             : 
     136           4 :   if (table_id != 0)
     137             :     {
     138           1 :       ip_table_create (FIB_PROTOCOL_IP4, table_id, 0, 0);
     139           1 :       ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id);
     140             :     }
     141             : 
     142           4 :   vnet_sw_interface_set_flags (vnet_get_main (), *sw_if_index,
     143             :                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     144             : 
     145           4 :   if (ip4_add_del_interface_address (vlib_get_main (), *sw_if_index,
     146             :                                      intf_addr, 24, 0))
     147             :     {
     148           0 :       clib_warning ("couldn't assign loopback ip %U", format_ip4_address,
     149             :                     intf_addr);
     150           0 :       return -1;
     151             :     }
     152             : 
     153           4 :   return 0;
     154             : }
     155             : 
     156             : static void
     157           4 : session_delete_loopback (u32 sw_if_index)
     158             : {
     159             :   /* fails spectacularly  */
     160             :   /* vnet_delete_loopback_interface (sw_if_index); */
     161             : 
     162           4 :   vnet_sw_interface_set_flags (vnet_get_main (), sw_if_index, 0);
     163           4 : }
     164             : 
     165             : static int
     166           1 : session_test_basic (vlib_main_t * vm, unformat_input_t * input)
     167             : {
     168           1 :   session_endpoint_cfg_t server_sep = SESSION_ENDPOINT_CFG_NULL;
     169             :   u64 options[APP_OPTIONS_N_OPTIONS], bind4_handle, bind6_handle;
     170             :   u32 server_index;
     171           1 :   int error = 0;
     172             : 
     173           1 :   clib_memset (options, 0, sizeof (options));
     174           1 :   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
     175           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     176           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     177           2 :   vnet_app_attach_args_t attach_args = {
     178             :     .api_client_index = ~0,
     179             :     .options = options,
     180             :     .namespace_id = 0,
     181             :     .session_cb_vft = &placeholder_session_cbs,
     182           1 :     .name = format (0, "session_test"),
     183             :   };
     184             : 
     185           1 :   error = vnet_application_attach (&attach_args);
     186           1 :   SESSION_TEST ((error == 0), "app attached");
     187           1 :   server_index = attach_args.app_index;
     188           1 :   vec_free (attach_args.name);
     189             : 
     190           1 :   server_sep.is_ip4 = 1;
     191           1 :   vnet_listen_args_t bind_args = {
     192             :     .sep_ext = server_sep,
     193             :     .app_index = 0,
     194             :     .wrk_map_index = 0,
     195             :   };
     196             : 
     197           1 :   bind_args.app_index = server_index;
     198           1 :   error = vnet_listen (&bind_args);
     199           1 :   SESSION_TEST ((error == 0), "server bind4 should work");
     200           1 :   bind4_handle = bind_args.handle;
     201             : 
     202           1 :   error = vnet_listen (&bind_args);
     203           1 :   SESSION_TEST ((error != 0), "double server bind4 should not work");
     204             : 
     205           1 :   bind_args.sep.is_ip4 = 0;
     206           1 :   error = vnet_listen (&bind_args);
     207           1 :   SESSION_TEST ((error == 0), "server bind6 should work");
     208           1 :   bind6_handle = bind_args.handle;
     209             : 
     210           1 :   error = vnet_listen (&bind_args);
     211           1 :   SESSION_TEST ((error != 0), "double server bind6 should not work");
     212             : 
     213           1 :   vnet_unlisten_args_t unbind_args = {
     214             :     .handle = bind4_handle,
     215             :     .app_index = server_index,
     216             :   };
     217           1 :   error = vnet_unlisten (&unbind_args);
     218           1 :   SESSION_TEST ((error == 0), "unbind4 should work");
     219             : 
     220           1 :   unbind_args.handle = bind6_handle;
     221           1 :   error = vnet_unlisten (&unbind_args);
     222           1 :   SESSION_TEST ((error == 0), "unbind6 should work");
     223             : 
     224           1 :   vnet_app_detach_args_t detach_args = {
     225             :     .app_index = server_index,
     226             :     .api_client_index = ~0,
     227             :   };
     228           1 :   vnet_application_detach (&detach_args);
     229           1 :   return 0;
     230             : }
     231             : 
     232             : static void
     233           4 : session_add_del_route_via_lookup_in_table (u32 in_table_id, u32 via_table_id,
     234             :                                            ip4_address_t * ip, u8 mask,
     235             :                                            u8 is_add)
     236             : {
     237           4 :   fib_route_path_t *rpaths = 0, *rpath;
     238             :   u32 in_fib_index, via_fib_index;
     239             : 
     240           4 :   fib_prefix_t prefix = {
     241           4 :     .fp_addr.ip4.as_u32 = ip->as_u32,
     242             :     .fp_len = mask,
     243             :     .fp_proto = FIB_PROTOCOL_IP4,
     244             :   };
     245             : 
     246           4 :   via_fib_index = fib_table_find (FIB_PROTOCOL_IP4, via_table_id);
     247           4 :   if (via_fib_index == ~0)
     248             :     {
     249           0 :       clib_warning ("couldn't resolve via table id to index");
     250           0 :       return;
     251             :     }
     252           4 :   in_fib_index = fib_table_find (FIB_PROTOCOL_IP4, in_table_id);
     253           4 :   if (in_fib_index == ~0)
     254             :     {
     255           0 :       clib_warning ("couldn't resolve in table id to index");
     256           0 :       return;
     257             :     }
     258             : 
     259           4 :   vec_add2 (rpaths, rpath, 1);
     260           4 :   clib_memset (rpath, 0, sizeof (*rpath));
     261           4 :   rpath->frp_weight = 1;
     262           4 :   rpath->frp_fib_index = via_fib_index;
     263           4 :   rpath->frp_proto = DPO_PROTO_IP4;
     264           4 :   rpath->frp_sw_if_index = ~0;
     265           4 :   rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
     266             : 
     267           4 :   if (is_add)
     268           2 :     fib_table_entry_path_add2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
     269             :                                FIB_ENTRY_FLAG_NONE, rpath);
     270             :   else
     271           2 :     fib_table_entry_path_remove2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
     272             :                                   rpath);
     273           4 :   vec_free (rpaths);
     274             : }
     275             : 
     276             : static int
     277           1 : session_test_endpoint_cfg (vlib_main_t * vm, unformat_input_t * input)
     278             : {
     279           1 :   session_endpoint_cfg_t client_sep = SESSION_ENDPOINT_CFG_NULL;
     280           1 :   u32 server_index, client_index, sw_if_index[2], tries = 0;
     281           1 :   u64 options[APP_OPTIONS_N_OPTIONS], placeholder_secret = 1234;
     282           1 :   u16 placeholder_server_port = 1234, placeholder_client_port = 5678;
     283           1 :   session_endpoint_cfg_t server_sep = SESSION_ENDPOINT_CFG_NULL;
     284             :   ip4_address_t intf_addr[3];
     285             :   transport_connection_t *tc;
     286             :   session_t *s;
     287             :   u8 *appns_id;
     288             :   int error;
     289             : 
     290             :   /*
     291             :    * Create the loopbacks
     292             :    */
     293           1 :   intf_addr[0].as_u32 = clib_host_to_net_u32 (0x01010101);
     294           1 :   session_create_lookpback (0, &sw_if_index[0], &intf_addr[0]);
     295             : 
     296           1 :   intf_addr[1].as_u32 = clib_host_to_net_u32 (0x02020202);
     297           1 :   session_create_lookpback (1, &sw_if_index[1], &intf_addr[1]);
     298             : 
     299           1 :   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
     300             :                                              1 /* is_add */ );
     301           1 :   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
     302             :                                              1 /* is_add */ );
     303             : 
     304             :   /*
     305             :    * Insert namespace
     306             :    */
     307           1 :   appns_id = format (0, "appns1");
     308           1 :   vnet_app_namespace_add_del_args_t ns_args = {
     309             :     .ns_id = appns_id,
     310             :     .secret = placeholder_secret,
     311           1 :     .sw_if_index = sw_if_index[1],
     312             :     .ip4_fib_id = 0,
     313             :     .is_add = 1
     314             :   };
     315           1 :   error = vnet_app_namespace_add_del (&ns_args);
     316           1 :   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", error);
     317             : 
     318             :   /*
     319             :    * Attach client/server
     320             :    */
     321           1 :   clib_memset (options, 0, sizeof (options));
     322           1 :   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
     323           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     324             : 
     325           2 :   vnet_app_attach_args_t attach_args = {
     326             :     .api_client_index = ~0,
     327             :     .options = options,
     328             :     .namespace_id = 0,
     329             :     .session_cb_vft = &placeholder_session_cbs,
     330           1 :     .name = format (0, "session_test_client"),
     331             :   };
     332             : 
     333           1 :   error = vnet_application_attach (&attach_args);
     334           1 :   SESSION_TEST ((error == 0), "client app attached");
     335           1 :   client_index = attach_args.app_index;
     336           1 :   vec_free (attach_args.name);
     337             : 
     338           1 :   attach_args.name = format (0, "session_test_server");
     339           1 :   attach_args.namespace_id = appns_id;
     340             :   /* Allow server to allocate another segment for listens. Needed
     341             :    * because by default we do not allow segment additions */
     342           1 :   attach_args.options[APP_OPTIONS_ADD_SEGMENT_SIZE] = 32 << 20;
     343           1 :   attach_args.options[APP_OPTIONS_NAMESPACE_SECRET] = placeholder_secret;
     344           1 :   error = vnet_application_attach (&attach_args);
     345           1 :   SESSION_TEST ((error == 0), "server app attached: %U", format_clib_error,
     346             :                 error);
     347           1 :   vec_free (attach_args.name);
     348           1 :   server_index = attach_args.app_index;
     349             : 
     350           1 :   server_sep.is_ip4 = 1;
     351           1 :   server_sep.port = placeholder_server_port;
     352           1 :   vnet_listen_args_t bind_args = {
     353             :     .sep_ext = server_sep,
     354             :     .app_index = server_index,
     355             :   };
     356           1 :   error = vnet_listen (&bind_args);
     357           1 :   SESSION_TEST ((error == 0), "server bind should work");
     358             : 
     359             :   /*
     360             :    * Connect and force lcl ip
     361             :    */
     362           1 :   client_sep.is_ip4 = 1;
     363           1 :   client_sep.ip.ip4.as_u32 = clib_host_to_net_u32 (0x02020202);
     364           1 :   client_sep.port = placeholder_server_port;
     365           1 :   client_sep.peer.is_ip4 = 1;
     366           1 :   client_sep.peer.ip.ip4.as_u32 = clib_host_to_net_u32 (0x01010101);
     367           1 :   client_sep.peer.port = placeholder_client_port;
     368           1 :   client_sep.transport_proto = TRANSPORT_PROTO_TCP;
     369             : 
     370           1 :   vnet_connect_args_t connect_args = {
     371             :     .sep_ext = client_sep,
     372             :     .app_index = client_index,
     373             :   };
     374             : 
     375           1 :   connected_session_index = connected_session_thread = ~0;
     376           1 :   accepted_session_index = accepted_session_thread = ~0;
     377           1 :   error = vnet_connect (&connect_args);
     378           1 :   SESSION_TEST ((error == 0), "connect should work");
     379             : 
     380             :   /* wait for stuff to happen */
     381           2 :   while (connected_session_index == ~0 && ++tries < 100)
     382             :     {
     383           1 :       vlib_worker_thread_barrier_release (vm);
     384           1 :       vlib_process_suspend (vm, 100e-3);
     385           1 :       vlib_worker_thread_barrier_sync (vm);
     386             :     }
     387           1 :   while (accepted_session_index == ~0 && ++tries < 100)
     388             :     {
     389           0 :       vlib_worker_thread_barrier_release (vm);
     390           0 :       vlib_process_suspend (vm, 100e-3);
     391           0 :       vlib_worker_thread_barrier_sync (vm);
     392             :     }
     393             : 
     394           1 :   clib_warning ("waited %.1f seconds for connections", tries / 10.0);
     395           1 :   SESSION_TEST ((connected_session_index != ~0), "session should exist");
     396           1 :   SESSION_TEST ((connected_session_thread != ~0), "thread should exist");
     397           1 :   SESSION_TEST ((accepted_session_index != ~0), "session should exist");
     398           1 :   SESSION_TEST ((accepted_session_thread != ~0), "thread should exist");
     399           1 :   s = session_get (connected_session_index, connected_session_thread);
     400           1 :   tc = session_get_transport (s);
     401           1 :   SESSION_TEST ((tc != 0), "transport should exist");
     402           1 :   SESSION_TEST ((memcmp (&tc->lcl_ip, &client_sep.peer.ip,
     403             :                          sizeof (tc->lcl_ip)) == 0), "ips should be equal");
     404           1 :   SESSION_TEST ((tc->lcl_port == placeholder_client_port),
     405             :                 "ports should be equal");
     406             : 
     407           1 :   vnet_app_detach_args_t detach_args = {
     408             :     .app_index = server_index,
     409             :     .api_client_index = ~0,
     410             :   };
     411           1 :   vnet_application_detach (&detach_args);
     412           1 :   detach_args.app_index = client_index;
     413           1 :   vnet_application_detach (&detach_args);
     414             : 
     415           1 :   ns_args.is_add = 0;
     416           1 :   error = vnet_app_namespace_add_del (&ns_args);
     417           1 :   SESSION_TEST ((error == 0), "app ns delete should succeed: %d", error);
     418             : 
     419             :   /* Allow the disconnects to finish before removing the routes. */
     420           1 :   vlib_process_suspend (vm, 10e-3);
     421             : 
     422           1 :   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
     423             :                                              0 /* is_add */ );
     424           1 :   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
     425             :                                              0 /* is_add */ );
     426             : 
     427           1 :   session_delete_loopback (sw_if_index[0]);
     428           1 :   session_delete_loopback (sw_if_index[1]);
     429           1 :   return 0;
     430             : }
     431             : 
     432             : static int
     433           1 : session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
     434             : {
     435           1 :   u64 options[APP_OPTIONS_N_OPTIONS], placeholder_secret = 1234, tries;
     436             :   u32 server_index, server_st_index, server_local_st_index;
     437           1 :   u32 placeholder_port = 1234, client_index, server_wrk_index;
     438           1 :   u32 placeholder_api_context = 4321, placeholder_client_api_index = ~0;
     439           1 :   u32 placeholder_server_api_index = ~0, sw_if_index = 0;
     440           1 :   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
     441           1 :   session_endpoint_t client_sep = SESSION_ENDPOINT_NULL;
     442           1 :   session_endpoint_t intf_sep = SESSION_ENDPOINT_NULL;
     443             :   u8 *ns_id, *server_name, *client_name;
     444             :   app_namespace_t *app_ns;
     445             :   application_t *server;
     446             :   session_t *s;
     447             :   u64 handle;
     448           1 :   int error = 0;
     449             : 
     450           1 :   ns_id = format (0, "appns1");
     451           1 :   server_name = format (0, "session_test");
     452           1 :   client_name = format (0, "session_test_client");
     453             : 
     454           1 :   server_sep.is_ip4 = 1;
     455           1 :   server_sep.port = placeholder_port;
     456           1 :   client_sep.is_ip4 = 1;
     457           1 :   client_sep.port = placeholder_port;
     458           1 :   clib_memset (options, 0, sizeof (options));
     459             : 
     460           1 :   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
     461           1 :   vnet_app_attach_args_t attach_args = {
     462             :     .api_client_index = ~0,
     463             :     .options = options,
     464             :     .namespace_id = 0,
     465             :     .session_cb_vft = &placeholder_session_cbs,
     466             :     .name = server_name,
     467             :   };
     468             : 
     469           1 :   vnet_listen_args_t bind_args = {
     470             :     .sep = server_sep,
     471             :     .app_index = 0,
     472             :   };
     473             : 
     474           1 :   vnet_connect_args_t connect_args = {
     475             :     .app_index = 0,
     476             :     .api_context = 0,
     477             :   };
     478           1 :   clib_memcpy (&connect_args.sep, &client_sep, sizeof (client_sep));
     479             : 
     480           1 :   vnet_unlisten_args_t unbind_args = {
     481           1 :     .handle = bind_args.handle,
     482             :     .app_index = 0,
     483             :   };
     484             : 
     485           1 :   vnet_app_detach_args_t detach_args = {
     486             :     .app_index = 0,
     487             :     .api_client_index = ~0,
     488             :   };
     489             : 
     490           1 :   ip4_address_t intf_addr = {
     491           1 :     .as_u32 = clib_host_to_net_u32 (0x07000105),
     492             :   };
     493             : 
     494           1 :   intf_sep.ip.ip4 = intf_addr;
     495           1 :   intf_sep.is_ip4 = 1;
     496           1 :   intf_sep.port = placeholder_port;
     497             : 
     498             :   /*
     499             :    * Insert namespace and lookup
     500             :    */
     501             : 
     502           1 :   vnet_app_namespace_add_del_args_t ns_args = {
     503             :     .ns_id = ns_id,
     504             :     .secret = placeholder_secret,
     505             :     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
     506             :     .is_add = 1
     507             :   };
     508           1 :   error = vnet_app_namespace_add_del (&ns_args);
     509           1 :   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", error);
     510             : 
     511           1 :   app_ns = app_namespace_get_from_id (ns_id);
     512           1 :   SESSION_TEST ((app_ns != 0), "should find ns %v status", ns_id);
     513           1 :   SESSION_TEST ((app_ns->ns_secret == placeholder_secret),
     514             :                 "secret should be %d", placeholder_secret);
     515           1 :   SESSION_TEST ((app_ns->sw_if_index == APP_NAMESPACE_INVALID_INDEX),
     516             :                 "sw_if_index should be invalid");
     517             : 
     518             :   /*
     519             :    * Try application attach with wrong secret
     520             :    */
     521             : 
     522           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     523           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     524           1 :   options[APP_OPTIONS_NAMESPACE_SECRET] = placeholder_secret - 1;
     525           1 :   attach_args.namespace_id = ns_id;
     526           1 :   attach_args.api_client_index = placeholder_server_api_index;
     527             : 
     528           1 :   error = vnet_application_attach (&attach_args);
     529           1 :   SESSION_TEST ((error != 0), "app attachment should fail");
     530           1 :   SESSION_TEST ((error == VNET_API_ERROR_APP_WRONG_NS_SECRET),
     531             :                 "code should be wrong ns secret: %d", error);
     532             : 
     533             :   /*
     534             :    * Attach server with global default scope
     535             :    */
     536           1 :   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     537           1 :   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     538           1 :   options[APP_OPTIONS_NAMESPACE_SECRET] = 0;
     539           1 :   attach_args.namespace_id = 0;
     540           1 :   attach_args.api_client_index = placeholder_server_api_index;
     541           1 :   error = vnet_application_attach (&attach_args);
     542           1 :   SESSION_TEST ((error == 0), "server attachment should work");
     543           1 :   server_index = attach_args.app_index;
     544           1 :   server = application_get (server_index);
     545           1 :   server_wrk_index = application_get_default_worker (server)->wrk_index;
     546           1 :   SESSION_TEST ((server->ns_index == 0),
     547             :                 "server should be in the default ns");
     548             : 
     549           1 :   bind_args.app_index = server_index;
     550           1 :   error = vnet_listen (&bind_args);
     551           1 :   SESSION_TEST ((error == 0), "server bind should work");
     552             : 
     553           1 :   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
     554           1 :   s = session_lookup_listener (server_st_index, &server_sep);
     555           1 :   SESSION_TEST ((s != 0), "listener should exist in global table");
     556           1 :   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
     557             :                 " that of the server");
     558           1 :   server_local_st_index = application_local_session_table (server);
     559           1 :   SESSION_TEST ((server_local_st_index == APP_INVALID_INDEX),
     560             :                 "server shouldn't have access to local table");
     561             : 
     562           1 :   unbind_args.app_index = server_index;
     563           1 :   unbind_args.handle = bind_args.handle;
     564           1 :   error = vnet_unlisten (&unbind_args);
     565           1 :   SESSION_TEST ((error == 0), "unbind should work");
     566             : 
     567           1 :   s = session_lookup_listener (server_st_index, &server_sep);
     568           1 :   SESSION_TEST ((s == 0), "listener should not exist in global table");
     569             : 
     570           1 :   detach_args.app_index = server_index;
     571           1 :   vnet_application_detach (&detach_args);
     572             : 
     573             :   /*
     574             :    * Attach server with local and global scope
     575             :    */
     576           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     577           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     578           1 :   options[APP_OPTIONS_NAMESPACE_SECRET] = placeholder_secret;
     579           1 :   attach_args.namespace_id = ns_id;
     580           1 :   attach_args.api_client_index = placeholder_server_api_index;
     581           1 :   error = vnet_application_attach (&attach_args);
     582           1 :   SESSION_TEST ((error == 0), "server attachment should work");
     583           1 :   server_index = attach_args.app_index;
     584           1 :   server = application_get (server_index);
     585           1 :   server_wrk_index = application_get_default_worker (server)->wrk_index;
     586           1 :   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
     587             :                 "server should be in the right ns");
     588             : 
     589           1 :   bind_args.app_index = server_index;
     590           1 :   error = vnet_listen (&bind_args);
     591           1 :   SESSION_TEST ((error == 0), "bind should work");
     592           1 :   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
     593           1 :   s = session_lookup_listener (server_st_index, &server_sep);
     594           1 :   SESSION_TEST ((s != 0), "listener should exist in global table");
     595           1 :   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
     596             :                 " that of the server");
     597           1 :   server_local_st_index = application_local_session_table (server);
     598           1 :   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
     599           1 :   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
     600             :                 "listener should exist in local table");
     601             : 
     602             :   /*
     603             :    * Try client connect with 1) local scope 2) global scope
     604             :    */
     605           1 :   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     606           1 :   attach_args.name = client_name;
     607           1 :   attach_args.api_client_index = placeholder_client_api_index;
     608           1 :   error = vnet_application_attach (&attach_args);
     609           1 :   SESSION_TEST ((error == 0), "client attachment should work");
     610           1 :   client_index = attach_args.app_index;
     611           1 :   connect_args.api_context = placeholder_api_context;
     612           1 :   connect_args.app_index = client_index;
     613           1 :   error = vnet_connect (&connect_args);
     614           1 :   SESSION_TEST ((error != 0), "client connect should return error code");
     615           1 :   SESSION_TEST ((error == SESSION_E_INVALID_RMT_IP),
     616             :                 "error code should be invalid value (zero ip)");
     617           1 :   SESSION_TEST ((placeholder_segment_count == 0),
     618             :                 "shouldn't have received request to map new segment");
     619           1 :   connect_args.sep.ip.ip4.as_u8[0] = 127;
     620           1 :   error = vnet_connect (&connect_args);
     621           1 :   SESSION_TEST ((error == 0), "client connect should not return error code");
     622             : 
     623             :   /* wait for accept */
     624           1 :   tries = 0;
     625           2 :   while (!placeholder_accept && ++tries < 100)
     626             :     {
     627           1 :       vlib_worker_thread_barrier_release (vm);
     628           1 :       vlib_process_suspend (vm, 100e-3);
     629           1 :       vlib_worker_thread_barrier_sync (vm);
     630             :     }
     631             : 
     632           1 :   SESSION_TEST ((placeholder_segment_count == 1),
     633             :                 "should've received request to map new segment");
     634           1 :   SESSION_TEST ((placeholder_accept == 1),
     635             :                 "should've received accept request");
     636           1 :   detach_args.app_index = client_index;
     637           1 :   vnet_application_detach (&detach_args);
     638             : 
     639           1 :   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     640           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     641           1 :   attach_args.api_client_index = placeholder_client_api_index;
     642           1 :   error = vnet_application_attach (&attach_args);
     643           1 :   SESSION_TEST ((error == 0), "client attachment should work");
     644           1 :   error = vnet_connect (&connect_args);
     645           1 :   SESSION_TEST ((error != 0), "client connect should return error code");
     646           1 :   SESSION_TEST ((error == SESSION_E_NOINTF),
     647             :                 "error code should be connect (nothing in local scope)");
     648           1 :   detach_args.app_index = client_index;
     649           1 :   vnet_application_detach (&detach_args);
     650             : 
     651             :   /*
     652             :    * Unbind and detach server and then re-attach with local scope only
     653             :    */
     654           1 :   unbind_args.handle = bind_args.handle;
     655           1 :   unbind_args.app_index = server_index;
     656           1 :   error = vnet_unlisten (&unbind_args);
     657           1 :   SESSION_TEST ((error == 0), "unbind should work");
     658             : 
     659           1 :   s = session_lookup_listener (server_st_index, &server_sep);
     660           1 :   SESSION_TEST ((s == 0), "listener should not exist in global table");
     661           1 :   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
     662           1 :   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
     663             :                 "listener should not exist in local table");
     664             : 
     665           1 :   detach_args.app_index = server_index;
     666           1 :   vnet_application_detach (&detach_args);
     667             : 
     668           1 :   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     669           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     670           1 :   attach_args.api_client_index = placeholder_server_api_index;
     671           1 :   attach_args.name = server_name;
     672           1 :   error = vnet_application_attach (&attach_args);
     673           1 :   SESSION_TEST ((error == 0), "app attachment should work");
     674           1 :   server_index = attach_args.app_index;
     675           1 :   server = application_get (server_index);
     676           1 :   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
     677             :                 "app should be in the right ns");
     678             : 
     679           1 :   bind_args.app_index = server_index;
     680           1 :   error = vnet_listen (&bind_args);
     681           1 :   SESSION_TEST ((error == 0), "bind should work");
     682             : 
     683           1 :   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
     684           1 :   s = session_lookup_listener (server_st_index, &server_sep);
     685           1 :   SESSION_TEST ((s == 0), "listener should not exist in global table");
     686           1 :   server_local_st_index = application_local_session_table (server);
     687           1 :   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
     688           1 :   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
     689             :                 "listener should exist in local table");
     690             : 
     691           1 :   unbind_args.handle = bind_args.handle;
     692           1 :   error = vnet_unlisten (&unbind_args);
     693           1 :   SESSION_TEST ((error == 0), "unbind should work");
     694             : 
     695           1 :   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
     696           1 :   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
     697             :                 "listener should not exist in local table");
     698             : 
     699             :   /*
     700             :    * Client attach + connect in default ns with local scope
     701             :    */
     702           1 :   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     703           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     704           1 :   attach_args.namespace_id = 0;
     705           1 :   attach_args.api_client_index = placeholder_client_api_index;
     706           1 :   attach_args.name = client_name;
     707           1 :   vnet_application_attach (&attach_args);
     708           1 :   error = vnet_connect (&connect_args);
     709           1 :   SESSION_TEST ((error != 0), "client connect should return error code");
     710           1 :   SESSION_TEST ((error == SESSION_E_NOROUTE),
     711             :                 "error code should be noroute (not in same ns)");
     712           1 :   detach_args.app_index = client_index;
     713           1 :   vnet_application_detach (&detach_args);
     714             : 
     715             :   /*
     716             :    * Detach server
     717             :    */
     718           1 :   detach_args.app_index = server_index;
     719           1 :   vnet_application_detach (&detach_args);
     720             : 
     721             :   /*
     722             :    * Create loopback interface
     723             :    */
     724           1 :   session_create_lookpback (0, &sw_if_index, &intf_addr);
     725             : 
     726             :   /*
     727             :    * Update namespace with interface
     728             :    */
     729           1 :   ns_args.sw_if_index = sw_if_index;
     730           1 :   error = vnet_app_namespace_add_del (&ns_args);
     731           1 :   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", error);
     732             : 
     733             :   /*
     734             :    * Attach server with local and global scope
     735             :    */
     736           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
     737           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
     738           1 :   options[APP_OPTIONS_NAMESPACE_SECRET] = placeholder_secret;
     739           1 :   attach_args.namespace_id = ns_id;
     740           1 :   attach_args.api_client_index = placeholder_server_api_index;
     741           1 :   attach_args.name = server_name;
     742           1 :   error = vnet_application_attach (&attach_args);
     743           1 :   SESSION_TEST ((error == 0), "server attachment should work");
     744           1 :   server_index = attach_args.app_index;
     745           1 :   server = application_get (server_index);
     746           1 :   server_wrk_index = application_get_default_worker (server)->wrk_index;
     747             : 
     748           1 :   bind_args.app_index = server_index;
     749           1 :   error = vnet_listen (&bind_args);
     750           1 :   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
     751           1 :   s = session_lookup_listener (server_st_index, &server_sep);
     752           1 :   SESSION_TEST ((s == 0), "zero listener should not exist in global table");
     753             : 
     754           1 :   s = session_lookup_listener (server_st_index, &intf_sep);
     755           1 :   SESSION_TEST ((s != 0), "intf listener should exist in global table");
     756           1 :   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be "
     757             :                 "that of the server");
     758           1 :   server_local_st_index = application_local_session_table (server);
     759           1 :   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
     760           1 :   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
     761             :                 "zero listener should exist in local table");
     762           1 :   detach_args.app_index = server_index;
     763           1 :   vnet_application_detach (&detach_args);
     764             : 
     765           1 :   ns_args.is_add = 0;
     766           1 :   error = vnet_app_namespace_add_del (&ns_args);
     767           1 :   SESSION_TEST ((error == 0), "app ns delete should succeed: %d", error);
     768             : 
     769             :   /*
     770             :    * Cleanup
     771             :    */
     772           1 :   vec_free (server_name);
     773           1 :   vec_free (client_name);
     774           1 :   vec_free (ns_id);
     775           1 :   session_delete_loopback (sw_if_index);
     776           1 :   return 0;
     777             : }
     778             : 
     779             : static int
     780           1 : session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
     781             : {
     782           1 :   session_rules_table_t _srt, *srt = &_srt;
     783           1 :   u16 lcl_port = 1234, rmt_port = 4321;
     784           1 :   u32 action_index = 1, res;
     785             :   ip4_address_t lcl_lkup, rmt_lkup;
     786           1 :   int verbose = 0, error;
     787             : 
     788           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     789             :     {
     790           0 :       if (unformat (input, "verbose"))
     791           0 :         verbose = 1;
     792             :       else
     793             :         {
     794           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
     795             :                            input);
     796           0 :           return -1;
     797             :         }
     798             :     }
     799             : 
     800           1 :   clib_memset (srt, 0, sizeof (*srt));
     801           1 :   session_rules_table_init (srt);
     802             : 
     803           1 :   ip4_address_t lcl_ip = {
     804           1 :     .as_u32 = clib_host_to_net_u32 (0x01020304),
     805             :   };
     806           1 :   ip4_address_t rmt_ip = {
     807           1 :     .as_u32 = clib_host_to_net_u32 (0x05060708),
     808             :   };
     809           1 :   ip4_address_t lcl_ip2 = {
     810           1 :     .as_u32 = clib_host_to_net_u32 (0x02020202),
     811             :   };
     812           1 :   ip4_address_t rmt_ip2 = {
     813           1 :     .as_u32 = clib_host_to_net_u32 (0x06060606),
     814             :   };
     815           1 :   ip4_address_t lcl_ip3 = {
     816           1 :     .as_u32 = clib_host_to_net_u32 (0x03030303),
     817             :   };
     818           1 :   ip4_address_t rmt_ip3 = {
     819           1 :     .as_u32 = clib_host_to_net_u32 (0x07070707),
     820             :   };
     821           1 :   fib_prefix_t lcl_pref = {
     822           1 :     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
     823             :     .fp_len = 16,
     824             :     .fp_proto = FIB_PROTOCOL_IP4,
     825             :   };
     826           1 :   fib_prefix_t rmt_pref = {
     827           1 :     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
     828             :     .fp_len = 16,
     829             :     .fp_proto = FIB_PROTOCOL_IP4,
     830             :   };
     831             : 
     832           1 :   session_rule_table_add_del_args_t args = {
     833             :     .lcl = lcl_pref,
     834             :     .rmt = rmt_pref,
     835             :     .lcl_port = lcl_port,
     836             :     .rmt_port = rmt_port,
     837           1 :     .action_index = action_index++,
     838             :     .is_add = 1,
     839             :   };
     840           1 :   error = session_rules_table_add_del (srt, &args);
     841           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
     842             :                 action_index - 1);
     843             : 
     844             :   res =
     845           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
     846           1 :   SESSION_TEST ((res == 1),
     847             :                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
     848             :                 res);
     849             : 
     850             :   /*
     851             :    * Add 1.2.3.4/24 1234 5.6.7.8/16 4321 and 1.2.3.4/24 1234 5.6.7.8/24 4321
     852             :    */
     853           1 :   args.lcl.fp_addr.ip4 = lcl_ip;
     854           1 :   args.lcl.fp_len = 24;
     855           1 :   args.action_index = action_index++;
     856           1 :   error = session_rules_table_add_del (srt, &args);
     857           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
     858             :                 action_index - 1);
     859           1 :   args.rmt.fp_addr.ip4 = rmt_ip;
     860           1 :   args.rmt.fp_len = 24;
     861           1 :   args.action_index = action_index++;
     862           1 :   error = session_rules_table_add_del (srt, &args);
     863           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
     864             :                 action_index - 1);
     865             : 
     866             :   /*
     867             :    * Add 2.2.2.2/24 1234 6.6.6.6/16 4321 and 3.3.3.3/24 1234 7.7.7.7/16 4321
     868             :    */
     869           1 :   args.lcl.fp_addr.ip4 = lcl_ip2;
     870           1 :   args.lcl.fp_len = 24;
     871           1 :   args.rmt.fp_addr.ip4 = rmt_ip2;
     872           1 :   args.rmt.fp_len = 16;
     873           1 :   args.action_index = action_index++;
     874           1 :   error = session_rules_table_add_del (srt, &args);
     875           1 :   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
     876             :                 action_index - 1);
     877           1 :   args.lcl.fp_addr.ip4 = lcl_ip3;
     878           1 :   args.rmt.fp_addr.ip4 = rmt_ip3;
     879           1 :   args.action_index = action_index++;
     880           1 :   error = session_rules_table_add_del (srt, &args);
     881           1 :   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
     882             :                 action_index - 1);
     883             : 
     884             :   /*
     885             :    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
     886             :    */
     887           1 :   args.lcl.fp_addr.ip4 = lcl_ip3;
     888           1 :   args.rmt.fp_addr.ip4 = rmt_ip3;
     889           1 :   args.action_index = action_index++;
     890           1 :   error = session_rules_table_add_del (srt, &args);
     891           1 :   SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
     892             :                 "action %d", action_index - 1);
     893             : 
     894             :   /*
     895             :    * Lookup 1.2.3.4/32 1234 5.6.7.8/32 4321, 1.2.2.4/32 1234 5.6.7.9/32 4321
     896             :    * and  3.3.3.3 1234 7.7.7.7 4321
     897             :    */
     898             :   res =
     899           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
     900           1 :   SESSION_TEST ((res == 3),
     901             :                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
     902             :                 res);
     903             : 
     904           1 :   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
     905           1 :   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
     906             :   res =
     907           1 :     session_rules_table_lookup4 (srt, &lcl_lkup,
     908             :                                  &rmt_lkup, lcl_port, rmt_port);
     909           1 :   SESSION_TEST ((res == 1),
     910             :                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
     911             :                 res);
     912             : 
     913             :   res =
     914           1 :     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
     915           1 :   SESSION_TEST ((res == 6),
     916             :                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
     917             :                 "should be 6 (updated): %d", res);
     918             : 
     919             :   /*
     920             :    * Add 1.2.3.4/24 * 5.6.7.8/24 *
     921             :    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
     922             :    */
     923           1 :   args.lcl.fp_addr.ip4 = lcl_ip;
     924           1 :   args.rmt.fp_addr.ip4 = rmt_ip;
     925           1 :   args.lcl.fp_len = 24;
     926           1 :   args.rmt.fp_len = 24;
     927           1 :   args.lcl_port = 0;
     928           1 :   args.rmt_port = 0;
     929           1 :   args.action_index = action_index++;
     930           1 :   error = session_rules_table_add_del (srt, &args);
     931           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
     932             :                 action_index - 1);
     933             :   res =
     934           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
     935           1 :   SESSION_TEST ((res == 7),
     936             :                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
     937             :                 " be 7 (lpm dst): %d", res);
     938             :   res =
     939           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
     940           1 :                                  lcl_port + 1, rmt_port);
     941           1 :   SESSION_TEST ((res == 7),
     942             :                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
     943             :                 res);
     944             : 
     945             :   /*
     946             :    * Del 1.2.3.4/24 * 5.6.7.8/24 *
     947             :    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
     948             :    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
     949             :    * 1.2.3.4 1235 5.6.7.8 4322
     950             :    */
     951           1 :   args.is_add = 0;
     952           1 :   error = session_rules_table_add_del (srt, &args);
     953           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
     954             : 
     955           1 :   args.lcl.fp_addr.ip4 = lcl_ip;
     956           1 :   args.rmt.fp_addr.ip4 = rmt_ip;
     957           1 :   args.lcl.fp_len = 16;
     958           1 :   args.rmt.fp_len = 16;
     959           1 :   args.lcl_port = 0;
     960           1 :   args.rmt_port = 0;
     961           1 :   args.action_index = action_index++;
     962           1 :   args.is_add = 1;
     963           1 :   error = session_rules_table_add_del (srt, &args);
     964           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
     965             :                 action_index - 1);
     966             : 
     967           1 :   args.lcl.fp_addr.ip4 = lcl_ip;
     968           1 :   args.rmt.fp_addr.ip4 = rmt_ip;
     969           1 :   args.lcl.fp_len = 24;
     970           1 :   args.rmt.fp_len = 24;
     971           1 :   args.lcl_port = lcl_port + 1;
     972           1 :   args.rmt_port = rmt_port;
     973           1 :   args.action_index = action_index++;
     974           1 :   args.is_add = 1;
     975           1 :   error = session_rules_table_add_del (srt, &args);
     976           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
     977             :                 action_index - 1);
     978             : 
     979           1 :   if (verbose)
     980           0 :     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
     981             : 
     982             :   res =
     983           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
     984           1 :   SESSION_TEST ((res == 3),
     985             :                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
     986             :                 res);
     987             :   res =
     988           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
     989           1 :                                  lcl_port + 1, rmt_port);
     990           1 :   SESSION_TEST ((res == 9),
     991             :                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
     992             :                 res);
     993             :   res =
     994           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
     995           1 :                                  lcl_port + 1, rmt_port + 1);
     996           1 :   SESSION_TEST ((res == 8),
     997             :                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
     998             :                 res);
     999             : 
    1000             :   /*
    1001             :    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
    1002             :    * Lookup 1.2.3.4 1234 5.6.7.8 4321
    1003             :    */
    1004           1 :   args.lcl_port = 1234;
    1005           1 :   args.rmt_port = 4321;
    1006           1 :   args.lcl.fp_len = 16;
    1007           1 :   args.rmt.fp_len = 16;
    1008           1 :   args.is_add = 0;
    1009           1 :   error = session_rules_table_add_del (srt, &args);
    1010           1 :   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
    1011             :   res =
    1012           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
    1013           1 :   SESSION_TEST ((res == 3),
    1014             :                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
    1015             :                 res);
    1016             : 
    1017           1 :   args.lcl_port = 0;
    1018           1 :   args.rmt_port = 0;
    1019           1 :   args.is_add = 0;
    1020           1 :   error = session_rules_table_add_del (srt, &args);
    1021           1 :   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
    1022             :   res =
    1023           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
    1024           1 :   SESSION_TEST ((res == 3),
    1025             :                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
    1026             :                 res);
    1027             : 
    1028             :   /*
    1029             :    * Delete 1.2.3.4/24 1234 5.6.7.5/24
    1030             :    */
    1031           1 :   args.lcl.fp_addr.ip4 = lcl_ip;
    1032           1 :   args.rmt.fp_addr.ip4 = rmt_ip;
    1033           1 :   args.lcl.fp_len = 24;
    1034           1 :   args.rmt.fp_len = 24;
    1035           1 :   args.lcl_port = 1234;
    1036           1 :   args.rmt_port = 4321;
    1037           1 :   args.is_add = 0;
    1038           1 :   error = session_rules_table_add_del (srt, &args);
    1039           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
    1040             :   res =
    1041           1 :     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
    1042           1 :   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
    1043             : 
    1044           1 :   return 0;
    1045             : }
    1046             : 
    1047             : static int
    1048           1 : session_test_rules (vlib_main_t * vm, unformat_input_t * input)
    1049             : {
    1050           1 :   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
    1051             :   u64 options[APP_OPTIONS_N_OPTIONS];
    1052           1 :   u16 lcl_port = 1234, rmt_port = 4321;
    1053             :   u32 server_index, server_index2;
    1054           1 :   u32 placeholder_server_api_index = ~0;
    1055             :   transport_connection_t *tc;
    1056           1 :   u32 placeholder_port = 1111;
    1057           1 :   u8 is_filtered = 0, *ns_id = format (0, "appns1");
    1058             :   session_t *listener, *s;
    1059           1 :   app_namespace_t *default_ns = app_namespace_get_default ();
    1060           1 :   u32 local_ns_index = default_ns->local_table_index;
    1061           1 :   int verbose = 0;
    1062             :   app_namespace_t *app_ns;
    1063             :   app_listener_t *al;
    1064           1 :   int error = 0;
    1065             :   u64 handle;
    1066             : 
    1067           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1068             :     {
    1069           0 :       if (unformat (input, "verbose"))
    1070           0 :         verbose = 1;
    1071             :       else
    1072             :         {
    1073           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
    1074             :                            input);
    1075           0 :           return -1;
    1076             :         }
    1077             :     }
    1078             : 
    1079           1 :   server_sep.is_ip4 = 1;
    1080           1 :   server_sep.port = placeholder_port;
    1081           1 :   clib_memset (options, 0, sizeof (options));
    1082             : 
    1083           2 :   vnet_app_attach_args_t attach_args = {
    1084             :     .api_client_index = ~0,
    1085             :     .options = options,
    1086             :     .namespace_id = 0,
    1087             :     .session_cb_vft = &placeholder_session_cbs,
    1088           1 :     .name = format (0, "session_test"),
    1089             :   };
    1090             : 
    1091           1 :   vnet_listen_args_t bind_args = {
    1092             :     .sep = server_sep,
    1093             :     .app_index = 0,
    1094             :   };
    1095             : 
    1096             :   /*
    1097             :    * Attach server with global and local default scope
    1098             :    */
    1099           1 :   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
    1100           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
    1101           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
    1102           1 :   attach_args.namespace_id = 0;
    1103           1 :   attach_args.api_client_index = placeholder_server_api_index;
    1104           1 :   error = vnet_application_attach (&attach_args);
    1105           1 :   SESSION_TEST ((error == 0), "server attached");
    1106           1 :   server_index = attach_args.app_index;
    1107             : 
    1108           1 :   bind_args.app_index = server_index;
    1109           1 :   error = vnet_listen (&bind_args);
    1110           1 :   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
    1111             :                 &server_sep.ip, 1, server_sep.port);
    1112           1 :   al = app_listener_get_w_handle (bind_args.handle);
    1113           1 :   listener = app_listener_get_session (al);
    1114           1 :   ip4_address_t lcl_ip = {
    1115           1 :     .as_u32 = clib_host_to_net_u32 (0x01020304),
    1116             :   };
    1117           1 :   ip4_address_t rmt_ip = {
    1118           1 :     .as_u32 = clib_host_to_net_u32 (0x05060708),
    1119             :   };
    1120           1 :   fib_prefix_t lcl_pref = {
    1121           1 :     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
    1122             :     .fp_len = 16,
    1123             :     .fp_proto = FIB_PROTOCOL_IP4,
    1124             :   };
    1125           1 :   fib_prefix_t rmt_pref = {
    1126           1 :     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
    1127             :     .fp_len = 16,
    1128             :     .fp_proto = FIB_PROTOCOL_IP4,
    1129             :   };
    1130             : 
    1131           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1132             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1133             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1134             :                                       &is_filtered);
    1135           1 :   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
    1136             : 
    1137             :   /*
    1138             :    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
    1139             :    */
    1140           1 :   session_rule_add_del_args_t args = {
    1141             :     .table_args.lcl = lcl_pref,
    1142             :     .table_args.rmt = rmt_pref,
    1143             :     .table_args.lcl_port = lcl_port,
    1144             :     .table_args.rmt_port = rmt_port,
    1145             :     .table_args.action_index = server_index,
    1146             :     .table_args.is_add = 1,
    1147             :     .appns_index = 0,
    1148             :   };
    1149           1 :   error = vnet_session_rule_add_del (&args);
    1150           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
    1151             :                 args.table_args.action_index);
    1152             : 
    1153           1 :   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
    1154             :                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
    1155             :                                    TRANSPORT_PROTO_TCP);
    1156           1 :   SESSION_TEST ((tc->c_index == listener->connection_index),
    1157             :                 "optimized lookup should return the listener");
    1158           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1159             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1160             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1161             :                                       &is_filtered);
    1162           1 :   SESSION_TEST ((tc->c_index == listener->connection_index),
    1163             :                 "lookup should return the listener");
    1164           1 :   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
    1165             :                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
    1166           1 :   SESSION_TEST ((s->connection_index == listener->connection_index),
    1167             :                 "safe lookup should return the listener");
    1168           1 :   session_endpoint_t sep = {
    1169             :     .ip = rmt_pref.fp_addr,
    1170             :     .is_ip4 = 1,
    1171             :     .port = rmt_port,
    1172             :     .transport_proto = TRANSPORT_PROTO_TCP,
    1173             :   };
    1174           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1175           1 :   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
    1176             :                 "should not work (global scope)");
    1177             : 
    1178           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1179           1 :                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
    1180             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1181             :                                       &is_filtered);
    1182           1 :   SESSION_TEST ((tc == 0),
    1183             :                 "optimized lookup for wrong lcl port + 1 should not work");
    1184             : 
    1185             :   /*
    1186             :    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
    1187             :    */
    1188           1 :   args.table_args.lcl_port = 0;
    1189           1 :   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
    1190           1 :   error = vnet_session_rule_add_del (&args);
    1191           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
    1192             :                 args.table_args.action_index);
    1193           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1194           1 :                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
    1195             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1196             :                                       &is_filtered);
    1197           1 :   SESSION_TEST ((tc->c_index == listener->connection_index),
    1198             :                 "optimized lookup for lcl port + 1 should work");
    1199           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1200           1 :   SESSION_TEST ((handle == server_index), "local session endpoint lookup "
    1201             :                 "should work (lcl ip was zeroed)");
    1202             : 
    1203             :   /*
    1204             :    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
    1205             :    */
    1206           1 :   args.table_args.lcl_port = 1234;
    1207           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1208           1 :   args.table_args.lcl.fp_len = 30;
    1209           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1210           1 :   args.table_args.rmt.fp_len = 30;
    1211           1 :   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
    1212           1 :   error = vnet_session_rule_add_del (&args);
    1213           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/30 1234 5.6.7.8/30 4321 action %d",
    1214             :                 args.table_args.action_index);
    1215             : 
    1216           1 :   if (verbose)
    1217             :     {
    1218           0 :       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
    1219             :                                        TRANSPORT_PROTO_TCP);
    1220           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1221             :                                              TRANSPORT_PROTO_TCP);
    1222             :     }
    1223             : 
    1224           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1225             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1226             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1227             :                                       &is_filtered);
    1228           1 :   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
    1229             :                 "should fail (deny rule)");
    1230           1 :   SESSION_TEST ((is_filtered == SESSION_LOOKUP_RESULT_FILTERED),
    1231             :                 "lookup should be filtered (deny)");
    1232             : 
    1233           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1234           1 :   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
    1235             :                 "5.6.7.8/16 4321 in local table should return deny");
    1236             : 
    1237           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1238           1 :                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
    1239             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1240             :                                       &is_filtered);
    1241           1 :   SESSION_TEST ((tc->c_index == listener->connection_index),
    1242             :                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should work");
    1243             : 
    1244             :   /*
    1245             :    * "Mask" deny rule with more specific allow:
    1246             :    * Add allow rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -3 (allow)
    1247             :    */
    1248           1 :   args.table_args.is_add = 1;
    1249           1 :   args.table_args.lcl_port = 1234;
    1250           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1251           1 :   args.table_args.lcl.fp_len = 32;
    1252           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1253           1 :   args.table_args.rmt.fp_len = 32;
    1254           1 :   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
    1255           1 :   error = vnet_session_rule_add_del (&args);
    1256           1 :   SESSION_TEST ((error == 0), "Add masking rule 1.2.3.4/30 1234 5.6.7.8/32 "
    1257             :                 "4321 action %d", args.table_args.action_index);
    1258             : 
    1259           1 :   is_filtered = 0;
    1260           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1261             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1262             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1263             :                                       &is_filtered);
    1264           1 :   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
    1265             :                 "should fail (allow without app)");
    1266           1 :   SESSION_TEST ((is_filtered == 0), "lookup should NOT be filtered");
    1267             : 
    1268           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1269           1 :   SESSION_TEST ((handle == SESSION_INVALID_HANDLE), "lookup for 1.2.3.4/32 "
    1270             :                 "1234 5.6.7.8/32 4321 in local table should return invalid");
    1271             : 
    1272           1 :   if (verbose)
    1273             :     {
    1274           0 :       vlib_cli_output (vm, "Local rules");
    1275           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1276             :                                              TRANSPORT_PROTO_TCP);
    1277             :     }
    1278             : 
    1279           1 :   sep.ip.ip4.as_u32 += 1 << 24;
    1280           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1281           1 :   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234"
    1282             :                 " 5.6.7.9/32 4321 in local table should return deny");
    1283             : 
    1284           1 :   vnet_connect_args_t connect_args = {
    1285           1 :     .app_index = attach_args.app_index,
    1286             :     .api_context = 0,
    1287             :   };
    1288           1 :   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
    1289             : 
    1290             :   /* Try connecting */
    1291           1 :   error = vnet_connect (&connect_args);
    1292           1 :   SESSION_TEST ((error != 0), "connect should fail");
    1293           1 :   SESSION_TEST ((error == SESSION_E_FILTERED), "connect should be filtered");
    1294             : 
    1295           1 :   sep.ip.ip4.as_u32 -= 1 << 24;
    1296             : 
    1297             :   /*
    1298             :    * Delete masking rule: 1.2.3.4/32 1234 5.6.7.8/32 4321 allow
    1299             :    */
    1300           1 :   args.table_args.is_add = 0;
    1301           1 :   args.table_args.lcl_port = 1234;
    1302           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1303           1 :   args.table_args.lcl.fp_len = 32;
    1304           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1305           1 :   args.table_args.rmt.fp_len = 32;
    1306           1 :   error = vnet_session_rule_add_del (&args);
    1307           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 allow");
    1308             : 
    1309             : 
    1310             :   /*
    1311             :    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
    1312             :    */
    1313           1 :   args.table_args.is_add = 1;
    1314           1 :   args.table_args.lcl_port = 0;
    1315           1 :   args.table_args.lcl.fp_len = 0;
    1316           1 :   args.table_args.rmt.fp_len = 16;
    1317           1 :   args.table_args.action_index = -1;
    1318           1 :   error = vnet_session_rule_add_del (&args);
    1319           1 :   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
    1320             :                 args.table_args.action_index);
    1321             : 
    1322           1 :   if (verbose)
    1323             :     {
    1324           0 :       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
    1325             :                                        TRANSPORT_PROTO_TCP);
    1326           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1327             :                                              TRANSPORT_PROTO_TCP);
    1328             :     }
    1329             : 
    1330           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1331           1 :   SESSION_TEST ((handle == SESSION_DROP_HANDLE),
    1332             :                 "local session endpoint lookup should return deny");
    1333             : 
    1334             :   /*
    1335             :    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
    1336             :    */
    1337           1 :   args.table_args.is_add = 0;
    1338           1 :   args.table_args.lcl_port = 1234;
    1339           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1340           1 :   args.table_args.lcl.fp_len = 30;
    1341           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1342           1 :   args.table_args.rmt.fp_len = 30;
    1343           1 :   error = vnet_session_rule_add_del (&args);
    1344           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
    1345             : 
    1346           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1347           1 :   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
    1348             :                 "local session endpoint lookup should return invalid");
    1349             : 
    1350             :   /*
    1351             :    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
    1352             :    * 1.2.3.4/16 1234 5.6.7.8/16 4321
    1353             :    */
    1354           1 :   args.table_args.is_add = 0;
    1355           1 :   args.table_args.lcl_port = 0;
    1356           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1357           1 :   args.table_args.lcl.fp_len = 0;
    1358           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1359           1 :   args.table_args.rmt.fp_len = 16;
    1360           1 :   args.table_args.rmt_port = 4321;
    1361           1 :   error = vnet_session_rule_add_del (&args);
    1362           1 :   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
    1363           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1364           1 :   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
    1365             :                 "should not work (removed)");
    1366             : 
    1367           1 :   args.table_args.is_add = 0;
    1368           1 :   args.table_args.lcl = lcl_pref;
    1369             : 
    1370           1 :   args.table_args.is_add = 0;
    1371           1 :   args.table_args.lcl_port = 0;
    1372           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1373           1 :   args.table_args.lcl.fp_len = 16;
    1374           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1375           1 :   args.table_args.rmt.fp_len = 16;
    1376           1 :   args.table_args.rmt_port = 4321;
    1377           1 :   error = vnet_session_rule_add_del (&args);
    1378           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
    1379           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1380           1 :                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
    1381             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1382             :                                       &is_filtered);
    1383           1 :   SESSION_TEST ((tc == 0),
    1384             :                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
    1385             :                 "work (del)");
    1386             : 
    1387           1 :   args.table_args.is_add = 0;
    1388           1 :   args.table_args.lcl_port = 1234;
    1389           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1390           1 :   args.table_args.lcl.fp_len = 16;
    1391           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1392           1 :   args.table_args.rmt.fp_len = 16;
    1393           1 :   args.table_args.rmt_port = 4321;
    1394           1 :   error = vnet_session_rule_add_del (&args);
    1395           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
    1396           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1397             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1398             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1399             :                                       &is_filtered);
    1400           1 :   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
    1401             :                 "not work (del + deny)");
    1402             : 
    1403           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
    1404           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1405             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1406             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1407             :                                       &is_filtered);
    1408           1 :   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
    1409             :                 " not work (no-rule)");
    1410             : 
    1411             :   /*
    1412             :    * Test tags. Add/overwrite/del rule with tag
    1413             :    */
    1414           1 :   args.table_args.is_add = 1;
    1415           1 :   args.table_args.lcl_port = 1234;
    1416           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1417           1 :   args.table_args.lcl.fp_len = 16;
    1418           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1419           1 :   args.table_args.rmt.fp_len = 16;
    1420           1 :   args.table_args.rmt_port = 4321;
    1421           1 :   args.table_args.tag = format (0, "test_rule");
    1422           1 :   args.table_args.action_index = server_index;
    1423           1 :   error = vnet_session_rule_add_del (&args);
    1424           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
    1425             :                 "tag test_rule");
    1426           1 :   if (verbose)
    1427             :     {
    1428           0 :       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
    1429             :                                        TRANSPORT_PROTO_TCP);
    1430           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1431             :                                              TRANSPORT_PROTO_TCP);
    1432             :     }
    1433           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1434             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1435             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1436             :                                       &is_filtered);
    1437           1 :   SESSION_TEST ((tc->c_index == listener->connection_index),
    1438             :                 "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
    1439             : 
    1440           1 :   vec_free (args.table_args.tag);
    1441           1 :   args.table_args.lcl_port = 1234;
    1442           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1443           1 :   args.table_args.lcl.fp_len = 16;
    1444           1 :   args.table_args.tag = format (0, "test_rule_overwrite");
    1445           1 :   error = vnet_session_rule_add_del (&args);
    1446           1 :   SESSION_TEST ((error == 0),
    1447             :                 "Overwrite 1.2.3.4/16 1234 5.6.7.8/16 4321 deny tag test_rule"
    1448             :                 " should work");
    1449           1 :   if (verbose)
    1450             :     {
    1451           0 :       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
    1452             :                                        TRANSPORT_PROTO_TCP);
    1453           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1454             :                                              TRANSPORT_PROTO_TCP);
    1455             :     }
    1456             : 
    1457           1 :   args.table_args.is_add = 0;
    1458           1 :   args.table_args.lcl_port += 1;
    1459           1 :   error = vnet_session_rule_add_del (&args);
    1460           1 :   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
    1461             :                 "tag %v", args.table_args.tag);
    1462           1 :   if (verbose)
    1463             :     {
    1464           0 :       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
    1465             :                                        TRANSPORT_PROTO_TCP);
    1466           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1467             :                                              TRANSPORT_PROTO_TCP);
    1468             :     }
    1469           1 :   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
    1470             :                                       &rmt_pref.fp_addr.ip4, lcl_port,
    1471             :                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
    1472             :                                       &is_filtered);
    1473           1 :   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/32 4321 should not"
    1474             :                 " work (del)");
    1475             : 
    1476             : 
    1477             :   /*
    1478             :    * Test local rules with multiple namespaces
    1479             :    */
    1480             : 
    1481             :   /*
    1482             :    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
    1483             :    */
    1484           1 :   args.table_args.is_add = 1;
    1485           1 :   args.table_args.lcl_port = 1234;
    1486           1 :   args.table_args.rmt_port = 0;
    1487           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1488           1 :   args.table_args.lcl.fp_len = 32;
    1489           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1490           1 :   args.table_args.rmt.fp_len = 32;
    1491           1 :   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
    1492           1 :   args.table_args.tag = 0;
    1493           1 :   args.scope = SESSION_RULE_SCOPE_LOCAL;
    1494           1 :   error = vnet_session_rule_add_del (&args);
    1495           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
    1496             :                 args.table_args.action_index);
    1497             :   /*
    1498             :    * Add 'white' rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
    1499             :    */
    1500           1 :   args.table_args.is_add = 1;
    1501           1 :   args.table_args.lcl_port = 1234;
    1502           1 :   args.table_args.rmt_port = 4321;
    1503           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1504           1 :   args.table_args.lcl.fp_len = 32;
    1505           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1506           1 :   args.table_args.rmt.fp_len = 32;
    1507           1 :   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
    1508           1 :   error = vnet_session_rule_add_del (&args);
    1509             : 
    1510           1 :   if (verbose)
    1511             :     {
    1512           0 :       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
    1513             :                                              TRANSPORT_PROTO_TCP);
    1514             :     }
    1515             : 
    1516           1 :   vnet_app_namespace_add_del_args_t ns_args = {
    1517             :     .ns_id = ns_id,
    1518             :     .secret = 0,
    1519             :     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
    1520             :     .is_add = 1
    1521             :   };
    1522           1 :   error = vnet_app_namespace_add_del (&ns_args);
    1523           1 :   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", error);
    1524           1 :   app_ns = app_namespace_get_from_id (ns_id);
    1525             : 
    1526           1 :   attach_args.namespace_id = ns_id;
    1527           1 :   attach_args.api_client_index = placeholder_server_api_index;
    1528           1 :   vec_free (attach_args.name);
    1529           1 :   attach_args.name = format (0, "server_test2");
    1530           1 :   error = vnet_application_attach (&attach_args);
    1531           1 :   SESSION_TEST ((error == 0), "server2 attached");
    1532           1 :   server_index2 = attach_args.app_index;
    1533             : 
    1534             :   /*
    1535             :    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
    1536             :    */
    1537           1 :   args.table_args.lcl_port = 1234;
    1538           1 :   args.table_args.rmt_port = 0;
    1539           1 :   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
    1540           1 :   args.table_args.lcl.fp_len = 32;
    1541           1 :   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
    1542           1 :   args.table_args.rmt.fp_len = 32;
    1543           1 :   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
    1544           1 :   args.appns_index = app_namespace_index (app_ns);
    1545             : 
    1546           1 :   error = vnet_session_rule_add_del (&args);
    1547           1 :   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d "
    1548             :                 "in test namespace", args.table_args.action_index);
    1549             :   /*
    1550             :    * Lookup default namespace
    1551             :    */
    1552           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1553           1 :   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
    1554             :                 "lookup for 1.2.3.4/32 1234 5.6.7.8/32 4321 in local table "
    1555             :                 "should return allow (invalid)");
    1556             : 
    1557           1 :   sep.port += 1;
    1558           1 :   handle = session_lookup_local_endpoint (local_ns_index, &sep);
    1559           1 :   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
    1560             :                 "5.6.7.8/16 432*2* in local table should return deny");
    1561             : 
    1562             : 
    1563           1 :   connect_args.app_index = server_index;
    1564           1 :   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
    1565             : 
    1566           1 :   error = vnet_connect (&connect_args);
    1567           1 :   SESSION_TEST ((error != 0), "connect should fail");
    1568           1 :   SESSION_TEST ((error == SESSION_E_FILTERED), "connect should be filtered");
    1569             : 
    1570             :   /*
    1571             :    * Lookup test namespace
    1572             :    */
    1573           1 :   handle = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
    1574           1 :   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
    1575             :                 "5.6.7.8/16 4321 in local table should return deny");
    1576             : 
    1577           1 :   connect_args.app_index = server_index;
    1578           1 :   error = vnet_connect (&connect_args);
    1579           1 :   SESSION_TEST ((error != 0), "connect should fail");
    1580           1 :   SESSION_TEST ((error == SESSION_E_FILTERED), "connect should be filtered");
    1581             : 
    1582           1 :   args.table_args.is_add = 0;
    1583           1 :   vnet_session_rule_add_del (&args);
    1584             : 
    1585           1 :   args.appns_index = 0;
    1586           1 :   args.table_args.is_add = 0;
    1587           1 :   vnet_session_rule_add_del (&args);
    1588             : 
    1589           1 :   args.table_args.rmt_port = 4321;
    1590           1 :   vnet_session_rule_add_del (&args);
    1591             :   /*
    1592             :    * Final Cleanup
    1593             :    */
    1594           1 :   vec_free (args.table_args.tag);
    1595           1 :   vnet_app_detach_args_t detach_args = {
    1596             :     .app_index = server_index,
    1597             :     .api_client_index = ~0,
    1598             :   };
    1599           1 :   vnet_application_detach (&detach_args);
    1600             : 
    1601           1 :   detach_args.app_index = server_index2;
    1602           1 :   vnet_application_detach (&detach_args);
    1603             : 
    1604           1 :   ns_args.is_add = 0;
    1605           1 :   error = vnet_app_namespace_add_del (&ns_args);
    1606           1 :   SESSION_TEST ((error == 0), "app ns delete should succeed: %d", error);
    1607             : 
    1608           1 :   vec_free (ns_id);
    1609           1 :   vec_free (attach_args.name);
    1610           1 :   return 0;
    1611             : }
    1612             : 
    1613             : static int
    1614           1 : session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
    1615             : {
    1616             :   u64 options[APP_OPTIONS_N_OPTIONS];
    1617           1 :   char *show_listeners = "sh session listeners tcp verbose";
    1618           1 :   char *show_local_listeners = "sh app ns table default";
    1619             :   unformat_input_t tmp_input;
    1620             :   u32 server_index, app_index;
    1621           1 :   u32 placeholder_server_api_index = ~0, sw_if_index = 0;
    1622           1 :   u8 is_filtered = 0;
    1623             :   session_t *s;
    1624             :   transport_connection_t *tc;
    1625           1 :   u16 lcl_port = 1234, rmt_port = 4321;
    1626             :   app_namespace_t *app_ns;
    1627           1 :   int verbose = 0, error = 0;
    1628             : 
    1629           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1630             :     {
    1631           0 :       if (unformat (input, "verbose"))
    1632           0 :         verbose = 1;
    1633             :       else
    1634             :         {
    1635           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
    1636             :                            input);
    1637           0 :           return -1;
    1638             :         }
    1639             :     }
    1640             : 
    1641           1 :   ip4_address_t lcl_ip = {
    1642           1 :     .as_u32 = clib_host_to_net_u32 (0x01020304),
    1643             :   };
    1644           1 :   ip4_address_t rmt_ip = {
    1645           1 :     .as_u32 = clib_host_to_net_u32 (0x05060708),
    1646             :   };
    1647           1 :   fib_prefix_t rmt_pref = {
    1648           1 :     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
    1649             :     .fp_len = 16,
    1650             :     .fp_proto = FIB_PROTOCOL_IP4,
    1651             :   };
    1652           1 :   session_endpoint_t sep = {
    1653             :     .ip = rmt_pref.fp_addr,
    1654             :     .is_ip4 = 1,
    1655             :     .port = rmt_port,
    1656             :     .transport_proto = TRANSPORT_PROTO_TCP,
    1657             :   };
    1658             : 
    1659             :   /*
    1660             :    * Create loopback interface
    1661             :    */
    1662           1 :   session_create_lookpback (0, &sw_if_index, &lcl_ip);
    1663             : 
    1664           1 :   app_ns = app_namespace_get_default ();
    1665           1 :   app_ns->sw_if_index = sw_if_index;
    1666             : 
    1667           1 :   clib_memset (options, 0, sizeof (options));
    1668           1 :   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
    1669           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
    1670           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
    1671           1 :   options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
    1672           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
    1673           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
    1674           2 :   vnet_app_attach_args_t attach_args = {
    1675             :     .api_client_index = ~0,
    1676             :     .options = options,
    1677             :     .namespace_id = 0,
    1678             :     .session_cb_vft = &placeholder_session_cbs,
    1679           1 :     .name = format (0, "session_test"),
    1680             :   };
    1681             : 
    1682           1 :   attach_args.api_client_index = placeholder_server_api_index;
    1683           1 :   error = vnet_application_attach (&attach_args);
    1684           1 :   SESSION_TEST ((error == 0), "server attachment should work");
    1685           1 :   server_index = attach_args.app_index;
    1686             : 
    1687           1 :   if (verbose)
    1688             :     {
    1689           0 :       unformat_init_string (&tmp_input, show_listeners,
    1690           0 :                             strlen (show_listeners));
    1691           0 :       vlib_cli_input (vm, &tmp_input, 0, 0);
    1692           0 :       unformat_init_string (&tmp_input, show_local_listeners,
    1693           0 :                             strlen (show_local_listeners));
    1694           0 :       vlib_cli_input (vm, &tmp_input, 0, 0);
    1695             :     }
    1696             : 
    1697           1 :   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
    1698             :                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
    1699           1 :   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
    1700             :                 "successful");
    1701           1 :   s = listen_session_get (tc->s_index);
    1702           1 :   SESSION_TEST ((s->app_index == server_index), "lookup should return"
    1703             :                 " the server");
    1704             : 
    1705           1 :   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
    1706             :                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
    1707           1 :   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
    1708             :                 " not work");
    1709             : 
    1710           1 :   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
    1711           1 :   SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
    1712             :                 " should work");
    1713             : 
    1714           1 :   vnet_app_detach_args_t detach_args = {
    1715             :     .app_index = server_index,
    1716             :     .api_client_index = ~0,
    1717             :   };
    1718           1 :   vnet_application_detach (&detach_args);
    1719             : 
    1720           1 :   if (verbose)
    1721             :     {
    1722           0 :       unformat_init_string (&tmp_input, show_listeners,
    1723           0 :                             strlen (show_listeners));
    1724           0 :       vlib_cli_input (vm, &tmp_input, 0, 0);
    1725           0 :       unformat_init_string (&tmp_input, show_local_listeners,
    1726           0 :                             strlen (show_local_listeners));
    1727           0 :       vlib_cli_input (vm, &tmp_input, 0, 0);
    1728             :     }
    1729             : 
    1730           1 :   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
    1731           1 :   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
    1732             :                 "local session endpoint lookup should not work after detach");
    1733           1 :   if (verbose)
    1734           0 :     unformat_free (&tmp_input);
    1735           1 :   vec_free (attach_args.name);
    1736           1 :   session_delete_loopback (sw_if_index);
    1737           1 :   return 0;
    1738             : }
    1739             : 
    1740             : static inline void
    1741        1024 : wait_for_event (svm_msg_q_t * mq, int fd, int epfd, u8 use_eventfd)
    1742             : {
    1743        1024 :   if (!use_eventfd)
    1744             :     {
    1745        1024 :       svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
    1746             :     }
    1747             :   else
    1748             :     {
    1749             :       int __clib_unused n_read, rv;
    1750             :       struct epoll_event ep_evt;
    1751             :       u64 buf;
    1752             : 
    1753             :       while (1)
    1754             :         {
    1755           0 :           rv = epoll_wait (epfd, &ep_evt, 1, -1);
    1756           0 :           if (rv < 0)
    1757             :             {
    1758           0 :               ST_DBG ("epoll error");
    1759           0 :               exit (1);
    1760             :             }
    1761           0 :           else if (rv > 0 && (ep_evt.events & EPOLLIN))
    1762             :             {
    1763           0 :               n_read = read (fd, &buf, sizeof (buf));
    1764             :             }
    1765             :           else
    1766           0 :             continue;
    1767             : 
    1768           0 :           if (!svm_msg_q_is_empty (mq))
    1769           0 :             break;
    1770             :         }
    1771             :     }
    1772        1024 : }
    1773             : 
    1774             : static int
    1775           1 : session_test_mq_speed (vlib_main_t * vm, unformat_input_t * input)
    1776             : {
    1777           1 :   int error, __clib_unused verbose, use_eventfd = 0;
    1778           1 :   u64 i, n_test_msgs = 1 << 10, *counter;
    1779             :   u64 options[APP_OPTIONS_N_OPTIONS];
    1780           1 :   int epfd = -1, rv, prod_fd = -1;
    1781             :   svm_fifo_t *rx_fifo, *tx_fifo;
    1782             :   vl_api_registration_t *reg;
    1783             :   struct epoll_event ep_evt;
    1784             :   u32 app_index, api_index;
    1785             :   app_worker_t *app_wrk;
    1786             :   segment_manager_t *sm;
    1787             :   svm_msg_q_msg_t msg;
    1788             :   application_t *app;
    1789             :   svm_msg_q_t *mq;
    1790             :   f64 start, diff;
    1791             :   svm_queue_t *q;
    1792             :   session_t s;
    1793             :   pid_t pid;
    1794             : 
    1795           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1796             :     {
    1797           0 :       if (unformat (input, "verbose"))
    1798           0 :         verbose = 1;
    1799           0 :       else if (unformat (input, "%d", &n_test_msgs))
    1800             :         ;
    1801           0 :       else if (unformat (input, "use-eventfd"))
    1802           0 :         use_eventfd = 1;
    1803             :       else
    1804             :         {
    1805           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
    1806             :                            input);
    1807           0 :           return -1;
    1808             :         }
    1809             :     }
    1810             : 
    1811           1 :   q = clib_mem_alloc (sizeof (*q));
    1812           1 :   api_index = vl_api_memclnt_create_internal ("session_mq_test_api", q);
    1813             : 
    1814           1 :   clib_memset (options, 0, sizeof (options));
    1815           1 :   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
    1816           1 :   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
    1817           1 :   options[APP_OPTIONS_EVT_QUEUE_SIZE] = 2048;
    1818             : 
    1819           1 :   reg = vl_api_client_index_to_registration (api_index);
    1820             :   /* Shut up coverity */
    1821           1 :   if (reg == 0)
    1822           0 :     abort ();
    1823             : 
    1824           2 :   vnet_app_attach_args_t attach_args = {
    1825             :     .api_client_index = api_index,
    1826             :     .options = options,
    1827             :     .namespace_id = 0,
    1828             :     .session_cb_vft = &placeholder_session_cbs,
    1829           1 :     .name = format (0, "session_mq_test"),
    1830             :   };
    1831           1 :   error = vnet_application_attach (&attach_args);
    1832           1 :   SESSION_TEST ((error == 0), "server attachment should work");
    1833             : 
    1834           1 :   app_index = attach_args.app_index;
    1835             : 
    1836           1 :   app = application_get (app_index);
    1837           1 :   app_wrk = application_get_worker (app, 0);
    1838           1 :   mq = app_wrk->event_queue;
    1839           1 :   if (use_eventfd)
    1840             :     {
    1841           0 :       svm_msg_q_alloc_eventfd (mq);
    1842           0 :       prod_fd = svm_msg_q_get_eventfd (mq);
    1843           0 :       SESSION_TEST (prod_fd != -1, "mq producer eventd valid %u", prod_fd);
    1844             :     }
    1845             : 
    1846           1 :   sm = app_worker_get_connect_segment_manager (app_wrk);
    1847           1 :   segment_manager_alloc_session_fifos (sm, 0, &rx_fifo, &tx_fifo);
    1848           1 :   s.rx_fifo = rx_fifo;
    1849           1 :   s.tx_fifo = tx_fifo;
    1850           1 :   s.session_state = SESSION_STATE_READY;
    1851           1 :   counter = (u64 *) f_head_cptr (rx_fifo)->data;
    1852           1 :   start = vlib_time_now (vm);
    1853             : 
    1854           1 :   pid = fork ();
    1855           2 :   if (pid < 0)
    1856           0 :     SESSION_TEST (0, "fork failed");
    1857             : 
    1858           2 :   if (pid == 0)
    1859             :     {
    1860           1 :       if (use_eventfd)
    1861             :         {
    1862           0 :           epfd = epoll_create1 (0);
    1863           0 :           SESSION_TEST (epfd != -1, "epfd created");
    1864           0 :           ep_evt.events = EPOLLIN;
    1865           0 :           ep_evt.data.u64 = prod_fd;
    1866           0 :           rv = epoll_ctl (epfd, EPOLL_CTL_ADD, prod_fd, &ep_evt);
    1867           0 :           SESSION_TEST (rv == 0, "epoll returned %d", rv);
    1868             :         }
    1869             : 
    1870        1025 :       for (i = 0; i < n_test_msgs; i++)
    1871             :         {
    1872        1024 :           wait_for_event (mq, prod_fd, epfd, use_eventfd);
    1873        1024 :           svm_msg_q_sub_raw (mq, &msg);
    1874        1024 :           svm_msg_q_free_msg (mq, &msg);
    1875        1024 :           svm_msg_q_unlock (mq);
    1876        1024 :           *counter = *counter + 1;
    1877        1024 :           svm_fifo_unset_event (rx_fifo);
    1878             :         }
    1879           1 :       exit (0);
    1880             :     }
    1881             :   else
    1882             :     {
    1883           1 :       ST_DBG ("client pid %u", pid);
    1884        1025 :       for (i = 0; i < n_test_msgs; i++)
    1885             :         {
    1886    13518700 :           while (svm_fifo_has_event (rx_fifo))
    1887             :             ;
    1888        1024 :           app_worker_lock_and_send_event (app_wrk, &s, SESSION_IO_EVT_RX);
    1889             :         }
    1890             :     }
    1891             : 
    1892           1 :   diff = vlib_time_now (vm) - start;
    1893           1 :   ST_DBG ("done %u events in %.2f sec: %f evts/s", *counter,
    1894             :           diff, *counter / diff);
    1895             : 
    1896           1 :   vnet_app_detach_args_t detach_args = {
    1897             :     .app_index = app_index,
    1898             :     .api_client_index = ~0,
    1899             :   };
    1900           1 :   vnet_application_detach (&detach_args);
    1901           1 :   return 0;
    1902             : }
    1903             : 
    1904             : static int
    1905           1 : session_test_mq_basic (vlib_main_t * vm, unformat_input_t * input)
    1906             : {
    1907           1 :   svm_msg_q_cfg_t _cfg, *cfg = &_cfg;
    1908             :   svm_msg_q_msg_t msg1, msg2, msg[12];
    1909             :   int __clib_unused verbose, i, rv;
    1910             :   svm_msg_q_shared_t *smq;
    1911             :   svm_msg_q_ring_t *ring;
    1912           1 :   svm_msg_q_t _mq = { 0 }, *mq = &_mq;
    1913             :   u8 *rings_ptr;
    1914             : 
    1915           1 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1916             :     {
    1917           0 :       if (unformat (input, "verbose"))
    1918           0 :         verbose = 1;
    1919             :       else
    1920             :         {
    1921           0 :           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
    1922             :                            input);
    1923           0 :           return -1;
    1924             :         }
    1925             :     }
    1926             : 
    1927           1 :   svm_msg_q_ring_cfg_t rc[2] = { {8, 8, 0}
    1928             :   , {8, 16, 0}
    1929             :   };
    1930           1 :   cfg->consumer_pid = ~0;
    1931           1 :   cfg->n_rings = 2;
    1932           1 :   cfg->q_nitems = 16;
    1933           1 :   cfg->ring_cfgs = rc;
    1934             : 
    1935           1 :   smq = svm_msg_q_alloc (cfg);
    1936           1 :   svm_msg_q_attach (mq, smq);
    1937           1 :   SESSION_TEST (smq != 0, "svm_msg_q_alloc");
    1938           1 :   SESSION_TEST (vec_len (mq->rings) == 2, "ring allocation");
    1939           1 :   rings_ptr = (u8 *) mq->rings[0].shr->data;
    1940           3 :   vec_foreach (ring, mq->rings)
    1941             :   {
    1942           2 :     SESSION_TEST (ring->shr->data == rings_ptr, "ring data");
    1943           2 :     rings_ptr += (uword) ring->nitems * ring->elsize;
    1944           2 :     rings_ptr += sizeof (svm_msg_q_ring_shared_t);
    1945             :   }
    1946             : 
    1947           1 :   msg1 = svm_msg_q_alloc_msg (mq, 8);
    1948           2 :   rv = (mq->rings[0].shr->cursize != 1 || msg1.ring_index != 0 ||
    1949           1 :         msg1.elt_index != 0);
    1950           1 :   SESSION_TEST (rv == 0, "msg alloc1");
    1951             : 
    1952           1 :   msg2 = svm_msg_q_alloc_msg (mq, 15);
    1953           2 :   rv = (mq->rings[1].shr->cursize != 1 || msg2.ring_index != 1 ||
    1954           1 :         msg2.elt_index != 0);
    1955           1 :   SESSION_TEST (rv == 0, "msg alloc2");
    1956             : 
    1957           1 :   svm_msg_q_free_msg (mq, &msg1);
    1958           1 :   SESSION_TEST (mq->rings[0].shr->cursize == 0, "free msg");
    1959             : 
    1960          13 :   for (i = 0; i < 12; i++)
    1961             :     {
    1962          12 :       msg[i] = svm_msg_q_alloc_msg (mq, 7);
    1963          12 :       *(u32 *) svm_msg_q_msg_data (mq, &msg[i]) = i;
    1964             :     }
    1965             : 
    1966           1 :   rv = (mq->rings[0].shr->cursize != 8 || mq->rings[1].shr->cursize != 5);
    1967           1 :   SESSION_TEST (rv == 0, "msg alloc3");
    1968             : 
    1969           1 :   *(u32 *) svm_msg_q_msg_data (mq, &msg2) = 123;
    1970           1 :   svm_msg_q_add (mq, &msg2, SVM_Q_NOWAIT);
    1971          13 :   for (i = 0; i < 12; i++)
    1972          12 :     svm_msg_q_add (mq, &msg[i], SVM_Q_NOWAIT);
    1973             : 
    1974           1 :   rv = svm_msg_q_sub (mq, &msg2, SVM_Q_NOWAIT, 0);
    1975           1 :   SESSION_TEST (rv == 0, "dequeue1");
    1976             : 
    1977           1 :   SESSION_TEST (msg2.ring_index == 1 && msg2.elt_index == 0,
    1978             :                 "dequeue1 result");
    1979           1 :   rv = (*(u32 *) svm_msg_q_msg_data (mq, &msg2) == 123);
    1980           1 :   SESSION_TEST (rv, "dequeue 1 data");
    1981             : 
    1982           1 :   svm_msg_q_free_msg (mq, &msg2);
    1983             : 
    1984          13 :   for (i = 0; i < 12; i++)
    1985             :     {
    1986          12 :       if (svm_msg_q_sub (mq, &msg[i], SVM_Q_NOWAIT, 0))
    1987           0 :         SESSION_TEST (0, "dequeue2");
    1988          12 :       if (i < 8)
    1989             :         {
    1990           8 :           if (msg[i].ring_index != 0 || msg[i].elt_index != (i + 1) % 8)
    1991           0 :             SESSION_TEST (0, "dequeue2 result2");
    1992             :         }
    1993             :       else
    1994             :         {
    1995           4 :           if (msg[i].ring_index != 1 || msg[i].elt_index != (i - 8) + 1)
    1996           0 :             SESSION_TEST (0, "dequeue2 result3");
    1997             :         }
    1998          12 :       if (*(u32 *) svm_msg_q_msg_data (mq, &msg[i]) != i)
    1999           0 :         SESSION_TEST (0, "dequeue2 wrong data");
    2000          12 :       svm_msg_q_free_msg (mq, &msg[i]);
    2001             :     }
    2002           1 :   rv = (mq->rings[0].shr->cursize == 0 && mq->rings[1].shr->cursize == 0);
    2003           1 :   SESSION_TEST (rv, "post dequeue");
    2004             : 
    2005           1 :   return 0;
    2006             : }
    2007             : 
    2008             : static clib_error_t *
    2009           1 : session_test (vlib_main_t * vm,
    2010             :               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
    2011             : {
    2012           1 :   int res = 0;
    2013             : 
    2014           1 :   vnet_session_enable_disable (vm, 1);
    2015             : 
    2016           2 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    2017             :     {
    2018           1 :       if (unformat (input, "basic"))
    2019           0 :         res = session_test_basic (vm, input);
    2020           1 :       else if (unformat (input, "namespace"))
    2021           0 :         res = session_test_namespace (vm, input);
    2022           1 :       else if (unformat (input, "rules-table"))
    2023           0 :         res = session_test_rule_table (vm, input);
    2024           1 :       else if (unformat (input, "rules"))
    2025           0 :         res = session_test_rules (vm, input);
    2026           1 :       else if (unformat (input, "proxy"))
    2027           0 :         res = session_test_proxy (vm, input);
    2028           1 :       else if (unformat (input, "endpt-cfg"))
    2029           0 :         res = session_test_endpoint_cfg (vm, input);
    2030           1 :       else if (unformat (input, "mq-speed"))
    2031           0 :         res = session_test_mq_speed (vm, input);
    2032           1 :       else if (unformat (input, "mq-basic"))
    2033           0 :         res = session_test_mq_basic (vm, input);
    2034           1 :       else if (unformat (input, "all"))
    2035             :         {
    2036           1 :           if ((res = session_test_basic (vm, input)))
    2037           0 :             goto done;
    2038           1 :           if ((res = session_test_namespace (vm, input)))
    2039           0 :             goto done;
    2040           1 :           if ((res = session_test_rule_table (vm, input)))
    2041           0 :             goto done;
    2042           1 :           if ((res = session_test_rules (vm, input)))
    2043           0 :             goto done;
    2044           1 :           if ((res = session_test_proxy (vm, input)))
    2045           0 :             goto done;
    2046           1 :           if ((res = session_test_endpoint_cfg (vm, input)))
    2047           0 :             goto done;
    2048           1 :           if ((res = session_test_mq_speed (vm, input)))
    2049           0 :             goto done;
    2050           1 :           if ((res = session_test_mq_basic (vm, input)))
    2051           0 :             goto done;
    2052             :         }
    2053             :       else
    2054           0 :         break;
    2055             :     }
    2056             : 
    2057           1 : done:
    2058           1 :   if (res)
    2059           0 :     return clib_error_return (0, "Session unit test failed");
    2060           1 :   return 0;
    2061             : }
    2062             : 
    2063             : /* *INDENT-OFF* */
    2064       16239 : VLIB_CLI_COMMAND (tcp_test_command, static) =
    2065             : {
    2066             :   .path = "test session",
    2067             :   .short_help = "internal session unit tests",
    2068             :   .function = session_test,
    2069             : };
    2070             : /* *INDENT-ON* */
    2071             : 
    2072             : /*
    2073             :  * fd.io coding-style-patch-verification: ON
    2074             :  *
    2075             :  * Local Variables:
    2076             :  * eval: (c-set-style "gnu")
    2077             :  * End:
    2078             :  */

Generated by: LCOV version 1.14