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