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