session: fix endpt cfg test (VPP-1492)
[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
23 #define SESSION_TEST_I(_cond, _comment, _args...)               \
24 ({                                                              \
25   int _evald = (_cond);                                         \
26   if (!(_evald)) {                                              \
27     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
28             __LINE__, ##_args);                                 \
29   } else {                                                      \
30     fformat(stderr, "PASS:%d: " _comment "\n",                  \
31             __LINE__, ##_args);                                 \
32   }                                                             \
33   _evald;                                                       \
34 })
35
36 #define SESSION_TEST(_cond, _comment, _args...)                 \
37 {                                                               \
38     if (!SESSION_TEST_I(_cond, _comment, ##_args)) {            \
39         return 1;                                               \
40     }                                                           \
41 }
42
43 void
44 dummy_session_reset_callback (stream_session_t * s)
45 {
46   clib_warning ("called...");
47 }
48
49 volatile u32 connected_session_index = ~0;
50 volatile u32 connected_session_thread = ~0;
51 int
52 dummy_session_connected_callback (u32 app_index, u32 api_context,
53                                   stream_session_t * s, u8 is_fail)
54 {
55   if (s)
56     {
57       connected_session_index = s->session_index;
58       connected_session_thread = s->thread_index;
59     }
60   return 0;
61 }
62
63 static u32 dummy_segment_count;
64
65 int
66 dummy_add_segment_callback (u32 client_index, const ssvm_private_t * fs)
67 {
68   dummy_segment_count = 1;
69   return 0;
70 }
71
72 int
73 dummy_del_segment_callback (u32 client_index, const ssvm_private_t * fs)
74 {
75   dummy_segment_count = 0;
76   return 0;
77 }
78
79 void
80 dummy_session_disconnect_callback (stream_session_t * s)
81 {
82   clib_warning ("called...");
83 }
84
85 static u32 dummy_accept;
86 volatile u32 accepted_session_index;
87 volatile u32 accepted_session_thread;
88
89 int
90 dummy_session_accept_callback (stream_session_t * s)
91 {
92   dummy_accept = 1;
93   accepted_session_index = s->session_index;
94   accepted_session_thread = s->thread_index;
95   s->session_state = SESSION_STATE_READY;
96   return 0;
97 }
98
99 int
100 dummy_server_rx_callback (stream_session_t * s)
101 {
102   clib_warning ("called...");
103   return -1;
104 }
105
106 /* *INDENT-OFF* */
107 static session_cb_vft_t dummy_session_cbs = {
108   .session_reset_callback = dummy_session_reset_callback,
109   .session_connected_callback = dummy_session_connected_callback,
110   .session_accept_callback = dummy_session_accept_callback,
111   .session_disconnect_callback = dummy_session_disconnect_callback,
112   .builtin_app_rx_callback = dummy_server_rx_callback,
113   .add_segment_callback = dummy_add_segment_callback,
114   .del_segment_callback = dummy_del_segment_callback,
115 };
116 /* *INDENT-ON* */
117
118 static int
119 session_create_lookpback (u32 table_id, u32 * sw_if_index,
120                           ip4_address_t * intf_addr)
121 {
122   u8 intf_mac[6];
123
124   clib_memset (intf_mac, 0, sizeof (intf_mac));
125
126   if (vnet_create_loopback_interface (sw_if_index, intf_mac, 0, 0))
127     {
128       clib_warning ("couldn't create loopback. stopping the test!");
129       return -1;
130     }
131
132   if (table_id != 0)
133     {
134       ip_table_create (FIB_PROTOCOL_IP4, table_id, 0, 0);
135       ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id, 0);
136     }
137
138   vnet_sw_interface_set_flags (vnet_get_main (), *sw_if_index,
139                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
140
141   if (ip4_add_del_interface_address (vlib_get_main (), *sw_if_index,
142                                      intf_addr, 24, 0))
143     {
144       clib_warning ("couldn't assign loopback ip %U", format_ip4_address,
145                     intf_addr);
146       return -1;
147     }
148
149   return 0;
150 }
151
152 static void
153 session_delete_loopback (u32 sw_if_index)
154 {
155   /* fails spectacularly  */
156   /* vnet_delete_loopback_interface (sw_if_index); */
157 }
158
159 static int
160 session_test_basic (vlib_main_t * vm, unformat_input_t * input)
161 {
162   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
163   u64 options[APP_OPTIONS_N_OPTIONS], bind4_handle, bind6_handle;
164   clib_error_t *error = 0;
165   u32 server_index;
166
167   clib_memset (options, 0, sizeof (options));
168   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
169   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
170   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
171   vnet_app_attach_args_t attach_args = {
172     .api_client_index = ~0,
173     .options = options,
174     .namespace_id = 0,
175     .session_cb_vft = &dummy_session_cbs,
176     .name = format (0, "session_test"),
177   };
178
179   error = vnet_application_attach (&attach_args);
180   SESSION_TEST ((error == 0), "app attached");
181   server_index = attach_args.app_index;
182   vec_free (attach_args.name);
183
184   server_sep.is_ip4 = 1;
185   vnet_bind_args_t bind_args = {
186     .sep = server_sep,
187     .app_index = 0,
188   };
189
190   bind_args.app_index = server_index;
191   error = vnet_bind (&bind_args);
192   SESSION_TEST ((error == 0), "server bind4 should work");
193   bind4_handle = bind_args.handle;
194
195   error = vnet_bind (&bind_args);
196   SESSION_TEST ((error != 0), "double server bind4 should not work");
197
198   bind_args.sep.is_ip4 = 0;
199   error = vnet_bind (&bind_args);
200   SESSION_TEST ((error == 0), "server bind6 should work");
201   bind6_handle = bind_args.handle;
202
203   error = vnet_bind (&bind_args);
204   SESSION_TEST ((error != 0), "double server bind6 should not work");
205
206   vnet_unbind_args_t unbind_args = {
207     .handle = bind4_handle,
208     .app_index = server_index,
209   };
210   error = vnet_unbind (&unbind_args);
211   SESSION_TEST ((error == 0), "unbind4 should work");
212
213   unbind_args.handle = bind6_handle;
214   error = vnet_unbind (&unbind_args);
215   SESSION_TEST ((error == 0), "unbind6 should work");
216
217   vnet_app_detach_args_t detach_args = {
218     .app_index = server_index,
219   };
220   vnet_application_detach (&detach_args);
221   return 0;
222 }
223
224 static void
225 session_add_del_route_via_lookup_in_table (u32 in_table_id, u32 via_table_id,
226                                            ip4_address_t * ip, u8 mask,
227                                            u8 is_add)
228 {
229   fib_route_path_t *rpaths = 0, *rpath;
230   u32 in_fib_index, via_fib_index;
231
232   fib_prefix_t prefix = {
233     .fp_addr.ip4.as_u32 = ip->as_u32,
234     .fp_len = mask,
235     .fp_proto = FIB_PROTOCOL_IP4,
236   };
237
238   via_fib_index = fib_table_find (FIB_PROTOCOL_IP4, via_table_id);
239   if (via_fib_index == ~0)
240     {
241       clib_warning ("couldn't resolve via table id to index");
242       return;
243     }
244   in_fib_index = fib_table_find (FIB_PROTOCOL_IP4, in_table_id);
245   if (in_fib_index == ~0)
246     {
247       clib_warning ("couldn't resolve in table id to index");
248       return;
249     }
250
251   vec_add2 (rpaths, rpath, 1);
252   clib_memset (rpath, 0, sizeof (*rpath));
253   rpath->frp_weight = 1;
254   rpath->frp_fib_index = via_fib_index;
255   rpath->frp_proto = DPO_PROTO_IP4;
256   rpath->frp_sw_if_index = ~0;
257   rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
258
259   if (is_add)
260     fib_table_entry_path_add2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
261                                FIB_ENTRY_FLAG_NONE, rpath);
262   else
263     fib_table_entry_path_remove2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
264                                   rpath);
265   vec_free (rpaths);
266 }
267
268 static int
269 session_test_endpoint_cfg (vlib_main_t * vm, unformat_input_t * input)
270 {
271   session_endpoint_cfg_t client_sep = SESSION_ENDPOINT_CFG_NULL;
272   u32 server_index, client_index, sw_if_index[2], tries = 0;
273   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
274   u16 dummy_server_port = 1234, dummy_client_port = 5678;
275   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
276   ip4_address_t intf_addr[3];
277   transport_connection_t *tc;
278   stream_session_t *s;
279   clib_error_t *error;
280   u8 *appns_id;
281
282   /*
283    * Create the loopbacks
284    */
285   intf_addr[0].as_u32 = clib_host_to_net_u32 (0x01010101),
286     session_create_lookpback (0, &sw_if_index[0], &intf_addr[0]);
287
288   intf_addr[1].as_u32 = clib_host_to_net_u32 (0x02020202),
289     session_create_lookpback (1, &sw_if_index[1], &intf_addr[1]);
290
291   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
292                                              1 /* is_add */ );
293   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
294                                              1 /* is_add */ );
295
296   /*
297    * Insert namespace
298    */
299   appns_id = format (0, "appns1");
300   vnet_app_namespace_add_del_args_t ns_args = {
301     .ns_id = appns_id,
302     .secret = dummy_secret,
303     .sw_if_index = sw_if_index[1],
304     .ip4_fib_id = 0,
305     .is_add = 1
306   };
307   error = vnet_app_namespace_add_del (&ns_args);
308   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
309                 clib_error_get_code (error));
310
311   /*
312    * Attach client/server
313    */
314   clib_memset (options, 0, sizeof (options));
315   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
316   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
317
318   vnet_app_attach_args_t attach_args = {
319     .api_client_index = ~0,
320     .options = options,
321     .namespace_id = 0,
322     .session_cb_vft = &dummy_session_cbs,
323     .name = format (0, "session_test_client"),
324   };
325
326   error = vnet_application_attach (&attach_args);
327   SESSION_TEST ((error == 0), "client app attached");
328   client_index = attach_args.app_index;
329   vec_free (attach_args.name);
330
331   attach_args.name = format (0, "session_test_server");
332   attach_args.namespace_id = appns_id;
333   attach_args.options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
334   error = vnet_application_attach (&attach_args);
335   SESSION_TEST ((error == 0), "server app attached: %U", format_clib_error,
336                 error);
337   vec_free (attach_args.name);
338   server_index = attach_args.app_index;
339
340   server_sep.is_ip4 = 1;
341   server_sep.port = dummy_server_port;
342   vnet_bind_args_t bind_args = {
343     .sep = server_sep,
344     .app_index = server_index,
345   };
346   error = vnet_bind (&bind_args);
347   SESSION_TEST ((error == 0), "server bind should work");
348
349   /*
350    * Connect and force lcl ip
351    */
352   client_sep.is_ip4 = 1;
353   client_sep.ip.ip4.as_u32 = clib_host_to_net_u32 (0x02020202);
354   client_sep.port = dummy_server_port;
355   client_sep.peer.is_ip4 = 1;
356   client_sep.peer.ip.ip4.as_u32 = clib_host_to_net_u32 (0x01010101);
357   client_sep.peer.port = dummy_client_port;
358   client_sep.transport_proto = TRANSPORT_PROTO_TCP;
359
360   vnet_connect_args_t connect_args = {
361     .sep_ext = client_sep,
362     .app_index = client_index,
363   };
364
365   connected_session_index = connected_session_thread = ~0;
366   accepted_session_index = accepted_session_thread = ~0;
367   error = vnet_connect (&connect_args);
368   SESSION_TEST ((error == 0), "connect should work");
369
370   /* wait for stuff to happen */
371   while ((connected_session_index == ~0
372           || vec_len (tcp_main.wrk_ctx[0].pending_acks)) && ++tries < 100)
373     vlib_process_suspend (vm, 100e-3);
374   clib_warning ("waited %.1f seconds for connections", tries / 10.0);
375   SESSION_TEST ((connected_session_index != ~0), "session should exist");
376   SESSION_TEST ((connected_session_thread != ~0), "thread should exist");
377   SESSION_TEST ((accepted_session_index != ~0), "session should exist");
378   SESSION_TEST ((accepted_session_thread != ~0), "thread should exist");
379   s = session_get (connected_session_index, connected_session_thread);
380   tc = session_get_transport (s);
381   SESSION_TEST ((tc != 0), "transport should exist");
382   SESSION_TEST ((memcmp (&tc->lcl_ip, &client_sep.peer.ip,
383                          sizeof (tc->lcl_ip)) == 0), "ips should be equal");
384   SESSION_TEST ((tc->lcl_port == dummy_client_port), "ports should be equal");
385
386   /* These sessions, because of the way they're established are pinned to
387    * main thread, even when we have workers and we avoid polling main thread,
388    * i.e., we can't cleanup pending disconnects, so force cleanup for both
389    */
390   stream_session_cleanup (s);
391   s = session_get (accepted_session_index, accepted_session_thread);
392   stream_session_cleanup (s);
393
394   vnet_app_detach_args_t detach_args = {
395     .app_index = server_index,
396   };
397   vnet_application_detach (&detach_args);
398   detach_args.app_index = client_index;
399   vnet_application_detach (&detach_args);
400
401   /* Allow the disconnects to finish before removing the routes. */
402   vlib_process_suspend (vm, 10e-3);
403
404   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
405                                              0 /* is_add */ );
406   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
407                                              0 /* is_add */ );
408
409   session_delete_loopback (sw_if_index[0]);
410   session_delete_loopback (sw_if_index[1]);
411   return 0;
412 }
413
414 static int
415 session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
416 {
417   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
418   u32 server_index, server_st_index, server_local_st_index;
419   u32 dummy_port = 1234, client_index, server_wrk_index;
420   u32 dummy_api_context = 4321, dummy_client_api_index = 1234;
421   u32 dummy_server_api_index = ~0, sw_if_index = 0;
422   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
423   session_endpoint_t client_sep = SESSION_ENDPOINT_NULL;
424   session_endpoint_t intf_sep = SESSION_ENDPOINT_NULL;
425   clib_error_t *error = 0;
426   u8 *ns_id = format (0, "appns1");
427   app_namespace_t *app_ns;
428   application_t *server;
429   stream_session_t *s;
430   u64 handle;
431   int code;
432
433   server_sep.is_ip4 = 1;
434   server_sep.port = dummy_port;
435   client_sep.is_ip4 = 1;
436   client_sep.port = dummy_port;
437   clib_memset (options, 0, sizeof (options));
438
439   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
440   vnet_app_attach_args_t attach_args = {
441     .api_client_index = ~0,
442     .options = options,
443     .namespace_id = 0,
444     .session_cb_vft = &dummy_session_cbs,
445     .name = format (0, "session_test"),
446   };
447
448   vnet_bind_args_t bind_args = {
449     .sep = server_sep,
450     .app_index = 0,
451   };
452
453   vnet_connect_args_t connect_args = {
454     .app_index = 0,
455     .api_context = 0,
456   };
457   clib_memcpy (&connect_args.sep, &client_sep, sizeof (client_sep));
458
459   vnet_unbind_args_t unbind_args = {
460     .handle = bind_args.handle,
461     .app_index = 0,
462   };
463
464   vnet_app_detach_args_t detach_args = {
465     .app_index = 0,
466   };
467
468   ip4_address_t intf_addr = {
469     .as_u32 = clib_host_to_net_u32 (0x07000105),
470   };
471
472   intf_sep.ip.ip4 = intf_addr;
473   intf_sep.is_ip4 = 1;
474   intf_sep.port = dummy_port;
475
476   /*
477    * Insert namespace and lookup
478    */
479
480   vnet_app_namespace_add_del_args_t ns_args = {
481     .ns_id = ns_id,
482     .secret = dummy_secret,
483     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
484     .is_add = 1
485   };
486   error = vnet_app_namespace_add_del (&ns_args);
487   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
488                 clib_error_get_code (error));
489
490   app_ns = app_namespace_get_from_id (ns_id);
491   SESSION_TEST ((app_ns != 0), "should find ns %v status", ns_id);
492   SESSION_TEST ((app_ns->ns_secret == dummy_secret), "secret should be %d",
493                 dummy_secret);
494   SESSION_TEST ((app_ns->sw_if_index == APP_NAMESPACE_INVALID_INDEX),
495                 "sw_if_index should be invalid");
496
497   /*
498    * Try application attach with wrong secret
499    */
500
501   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
502   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
503   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret - 1;
504   attach_args.namespace_id = ns_id;
505   attach_args.api_client_index = dummy_server_api_index;
506
507   error = vnet_application_attach (&attach_args);
508   SESSION_TEST ((error != 0), "app attachment should fail");
509   code = clib_error_get_code (error);
510   SESSION_TEST ((code == VNET_API_ERROR_APP_WRONG_NS_SECRET),
511                 "code should be wrong ns secret: %d", code);
512
513   /*
514    * Attach server with global default scope
515    */
516   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
517   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
518   options[APP_OPTIONS_NAMESPACE_SECRET] = 0;
519   attach_args.namespace_id = 0;
520   attach_args.api_client_index = dummy_server_api_index;
521   error = vnet_application_attach (&attach_args);
522   SESSION_TEST ((error == 0), "server attachment should work");
523   server_index = attach_args.app_index;
524   server = application_get (server_index);
525   server_wrk_index = application_get_default_worker (server)->wrk_index;
526   SESSION_TEST ((server->ns_index == 0),
527                 "server should be in the default ns");
528
529   bind_args.app_index = server_index;
530   error = vnet_bind (&bind_args);
531   SESSION_TEST ((error == 0), "server bind should work");
532
533   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
534   s = session_lookup_listener (server_st_index, &server_sep);
535   SESSION_TEST ((s != 0), "listener should exist in global table");
536   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
537                 " that of the server");
538   server_local_st_index = application_local_session_table (server);
539   SESSION_TEST ((server_local_st_index == APP_INVALID_INDEX),
540                 "server shouldn't have access to local table");
541
542   unbind_args.app_index = server_index;
543   unbind_args.handle = bind_args.handle;
544   error = vnet_unbind (&unbind_args);
545   SESSION_TEST ((error == 0), "unbind should work");
546
547   s = session_lookup_listener (server_st_index, &server_sep);
548   SESSION_TEST ((s == 0), "listener should not exist in global table");
549
550   detach_args.app_index = server_index;
551   vnet_application_detach (&detach_args);
552
553   /*
554    * Attach server with local and global scope
555    */
556   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
557   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
558   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
559   attach_args.namespace_id = ns_id;
560   attach_args.api_client_index = dummy_server_api_index;
561   error = vnet_application_attach (&attach_args);
562   SESSION_TEST ((error == 0), "server attachment should work");
563   server_index = attach_args.app_index;
564   server = application_get (server_index);
565   server_wrk_index = application_get_default_worker (server)->wrk_index;
566   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
567                 "server should be in the right ns");
568
569   bind_args.app_index = server_index;
570   error = vnet_bind (&bind_args);
571   SESSION_TEST ((error == 0), "bind should work");
572   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
573   s = session_lookup_listener (server_st_index, &server_sep);
574   SESSION_TEST ((s != 0), "listener should exist in global table");
575   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
576                 " that of the server");
577   server_local_st_index = application_local_session_table (server);
578   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
579   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
580                 "listener should exist in local table");
581
582   /*
583    * Try client connect with 1) local scope 2) global scope
584    */
585   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
586   attach_args.api_client_index = dummy_client_api_index;
587   error = vnet_application_attach (&attach_args);
588   SESSION_TEST ((error == 0), "client attachment should work");
589   client_index = attach_args.app_index;
590   connect_args.api_context = dummy_api_context;
591   connect_args.app_index = client_index;
592   error = vnet_connect (&connect_args);
593   SESSION_TEST ((error != 0), "client connect should return error code");
594   code = clib_error_get_code (error);
595   SESSION_TEST ((code == VNET_API_ERROR_INVALID_VALUE),
596                 "error code should be invalid value (zero ip)");
597   SESSION_TEST ((dummy_segment_count == 0),
598                 "shouldn't have received request to map new segment");
599   connect_args.sep.ip.ip4.as_u8[0] = 127;
600   error = vnet_connect (&connect_args);
601   SESSION_TEST ((error == 0), "client connect should not return error code");
602   code = clib_error_get_code (error);
603   SESSION_TEST ((dummy_segment_count == 1),
604                 "should've received request to map new segment");
605   SESSION_TEST ((dummy_accept == 1), "should've received accept request");
606   detach_args.app_index = client_index;
607   vnet_application_detach (&detach_args);
608
609   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
610   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
611   attach_args.api_client_index = dummy_client_api_index;
612   error = vnet_application_attach (&attach_args);
613   SESSION_TEST ((error == 0), "client attachment should work");
614   error = vnet_connect (&connect_args);
615   SESSION_TEST ((error != 0), "client connect should return error code");
616   code = clib_error_get_code (error);
617   SESSION_TEST ((code == 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_unbind (&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_bind (&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_unbind (&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   code = clib_error_get_code (error);
680   SESSION_TEST ((code == VNET_API_ERROR_SESSION_CONNECT),
681                 "error code should be connect (not in same ns)");
682   detach_args.app_index = client_index;
683   vnet_application_detach (&detach_args);
684
685   /*
686    * Detach server
687    */
688   detach_args.app_index = server_index;
689   vnet_application_detach (&detach_args);
690
691   /*
692    * Create loopback interface
693    */
694   session_create_lookpback (0, &sw_if_index, &intf_addr);
695
696   /*
697    * Update namespace
698    */
699   ns_args.sw_if_index = sw_if_index;
700   error = vnet_app_namespace_add_del (&ns_args);
701   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
702                 clib_error_get_code (error));
703
704   /*
705    * Attach server with local and global scope
706    */
707   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
708   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
709   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
710   attach_args.namespace_id = ns_id;
711   attach_args.api_client_index = dummy_server_api_index;
712   error = vnet_application_attach (&attach_args);
713   SESSION_TEST ((error == 0), "server attachment should work");
714   server_index = attach_args.app_index;
715   server = application_get (server_index);
716   server_wrk_index = application_get_default_worker (server)->wrk_index;
717
718   bind_args.app_index = server_index;
719   error = vnet_bind (&bind_args);
720   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
721   s = session_lookup_listener (server_st_index, &server_sep);
722   SESSION_TEST ((s == 0), "zero listener should not exist in global table");
723
724   s = session_lookup_listener (server_st_index, &intf_sep);
725   SESSION_TEST ((s != 0), "intf listener should exist in global table");
726   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be "
727                 "that of the server");
728   server_local_st_index = application_local_session_table (server);
729   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
730   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
731                 "zero listener should exist in local table");
732   detach_args.app_index = server_index;
733   vnet_application_detach (&detach_args);
734
735   /*
736    * Cleanup
737    */
738   vec_free (attach_args.name);
739   vec_free (ns_id);
740   session_delete_loopback (sw_if_index);
741   return 0;
742 }
743
744 static int
745 session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
746 {
747   session_rules_table_t _srt, *srt = &_srt;
748   u16 lcl_port = 1234, rmt_port = 4321;
749   u32 action_index = 1, res;
750   ip4_address_t lcl_lkup, rmt_lkup;
751   clib_error_t *error;
752   int verbose = 0;
753
754   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
755     {
756       if (unformat (input, "verbose"))
757         verbose = 1;
758       else
759         {
760           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
761                            input);
762           return -1;
763         }
764     }
765
766   clib_memset (srt, 0, sizeof (*srt));
767   session_rules_table_init (srt);
768
769   ip4_address_t lcl_ip = {
770     .as_u32 = clib_host_to_net_u32 (0x01020304),
771   };
772   ip4_address_t rmt_ip = {
773     .as_u32 = clib_host_to_net_u32 (0x05060708),
774   };
775   ip4_address_t lcl_ip2 = {
776     .as_u32 = clib_host_to_net_u32 (0x02020202),
777   };
778   ip4_address_t rmt_ip2 = {
779     .as_u32 = clib_host_to_net_u32 (0x06060606),
780   };
781   ip4_address_t lcl_ip3 = {
782     .as_u32 = clib_host_to_net_u32 (0x03030303),
783   };
784   ip4_address_t rmt_ip3 = {
785     .as_u32 = clib_host_to_net_u32 (0x07070707),
786   };
787   fib_prefix_t lcl_pref = {
788     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
789     .fp_len = 16,
790     .fp_proto = FIB_PROTOCOL_IP4,
791   };
792   fib_prefix_t rmt_pref = {
793     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
794     .fp_len = 16,
795     .fp_proto = FIB_PROTOCOL_IP4,
796   };
797
798   session_rule_table_add_del_args_t args = {
799     .lcl = lcl_pref,
800     .rmt = rmt_pref,
801     .lcl_port = lcl_port,
802     .rmt_port = rmt_port,
803     .action_index = action_index++,
804     .is_add = 1,
805   };
806   error = session_rules_table_add_del (srt, &args);
807   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
808                 action_index - 1);
809
810   res =
811     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
812   SESSION_TEST ((res == 1),
813                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
814                 res);
815
816   /*
817    * 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
818    */
819   args.lcl.fp_addr.ip4 = lcl_ip;
820   args.lcl.fp_len = 24;
821   args.action_index = action_index++;
822   error = session_rules_table_add_del (srt, &args);
823   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
824                 action_index - 1);
825   args.rmt.fp_addr.ip4 = rmt_ip;
826   args.rmt.fp_len = 24;
827   args.action_index = action_index++;
828   error = session_rules_table_add_del (srt, &args);
829   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
830                 action_index - 1);
831
832   /*
833    * 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
834    */
835   args.lcl.fp_addr.ip4 = lcl_ip2;
836   args.lcl.fp_len = 24;
837   args.rmt.fp_addr.ip4 = rmt_ip2;
838   args.rmt.fp_len = 16;
839   args.action_index = action_index++;
840   error = session_rules_table_add_del (srt, &args);
841   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
842                 action_index - 1);
843   args.lcl.fp_addr.ip4 = lcl_ip3;
844   args.rmt.fp_addr.ip4 = rmt_ip3;
845   args.action_index = action_index++;
846   error = session_rules_table_add_del (srt, &args);
847   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
848                 action_index - 1);
849
850   /*
851    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
852    */
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), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
858                 "action %d", action_index - 1);
859
860   /*
861    * 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
862    * and  3.3.3.3 1234 7.7.7.7 4321
863    */
864   res =
865     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
866   SESSION_TEST ((res == 3),
867                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
868                 res);
869
870   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
871   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
872   res =
873     session_rules_table_lookup4 (srt, &lcl_lkup,
874                                  &rmt_lkup, lcl_port, rmt_port);
875   SESSION_TEST ((res == 1),
876                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
877                 res);
878
879   res =
880     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
881   SESSION_TEST ((res == 6),
882                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
883                 "should be 6 (updated): %d", res);
884
885   /*
886    * Add 1.2.3.4/24 * 5.6.7.8/24 *
887    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
888    */
889   args.lcl.fp_addr.ip4 = lcl_ip;
890   args.rmt.fp_addr.ip4 = rmt_ip;
891   args.lcl.fp_len = 24;
892   args.rmt.fp_len = 24;
893   args.lcl_port = 0;
894   args.rmt_port = 0;
895   args.action_index = action_index++;
896   error = session_rules_table_add_del (srt, &args);
897   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
898                 action_index - 1);
899   res =
900     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
901   SESSION_TEST ((res == 7),
902                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
903                 " be 7 (lpm dst): %d", res);
904   res =
905     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
906                                  lcl_port + 1, rmt_port);
907   SESSION_TEST ((res == 7),
908                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
909                 res);
910
911   /*
912    * Del 1.2.3.4/24 * 5.6.7.8/24 *
913    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
914    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
915    * 1.2.3.4 1235 5.6.7.8 4322
916    */
917   args.is_add = 0;
918   error = session_rules_table_add_del (srt, &args);
919   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
920
921   args.lcl.fp_addr.ip4 = lcl_ip;
922   args.rmt.fp_addr.ip4 = rmt_ip;
923   args.lcl.fp_len = 16;
924   args.rmt.fp_len = 16;
925   args.lcl_port = 0;
926   args.rmt_port = 0;
927   args.action_index = action_index++;
928   args.is_add = 1;
929   error = session_rules_table_add_del (srt, &args);
930   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
931                 action_index - 1);
932
933   args.lcl.fp_addr.ip4 = lcl_ip;
934   args.rmt.fp_addr.ip4 = rmt_ip;
935   args.lcl.fp_len = 24;
936   args.rmt.fp_len = 24;
937   args.lcl_port = lcl_port + 1;
938   args.rmt_port = rmt_port;
939   args.action_index = action_index++;
940   args.is_add = 1;
941   error = session_rules_table_add_del (srt, &args);
942   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
943                 action_index - 1);
944
945   if (verbose)
946     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
947
948   res =
949     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
950   SESSION_TEST ((res == 3),
951                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
952                 res);
953   res =
954     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
955                                  lcl_port + 1, rmt_port);
956   SESSION_TEST ((res == 9),
957                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
958                 res);
959   res =
960     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
961                                  lcl_port + 1, rmt_port + 1);
962   SESSION_TEST ((res == 8),
963                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
964                 res);
965
966   /*
967    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
968    * Lookup 1.2.3.4 1234 5.6.7.8 4321
969    */
970   args.lcl_port = 1234;
971   args.rmt_port = 4321;
972   args.lcl.fp_len = 16;
973   args.rmt.fp_len = 16;
974   args.is_add = 0;
975   error = session_rules_table_add_del (srt, &args);
976   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
977   res =
978     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
979   SESSION_TEST ((res == 3),
980                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
981                 res);
982
983   args.lcl_port = 0;
984   args.rmt_port = 0;
985   args.is_add = 0;
986   error = session_rules_table_add_del (srt, &args);
987   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
988   res =
989     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
990   SESSION_TEST ((res == 3),
991                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
992                 res);
993
994   /*
995    * Delete 1.2.3.4/24 1234 5.6.7.5/24
996    */
997   args.lcl.fp_addr.ip4 = lcl_ip;
998   args.rmt.fp_addr.ip4 = rmt_ip;
999   args.lcl.fp_len = 24;
1000   args.rmt.fp_len = 24;
1001   args.lcl_port = 1234;
1002   args.rmt_port = 4321;
1003   args.is_add = 0;
1004   error = session_rules_table_add_del (srt, &args);
1005   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
1006   res =
1007     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
1008   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
1009
1010   return 0;
1011 }
1012
1013 static int
1014 session_test_rules (vlib_main_t * vm, unformat_input_t * input)
1015 {
1016   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
1017   u64 options[APP_OPTIONS_N_OPTIONS];
1018   u16 lcl_port = 1234, rmt_port = 4321;
1019   u32 server_index, server_index2;
1020   u32 dummy_server_api_index = ~0;
1021   transport_connection_t *tc;
1022   u32 dummy_port = 1111;
1023   clib_error_t *error = 0;
1024   u8 is_filtered = 0, *ns_id = format (0, "appns1");
1025   stream_session_t *listener, *s;
1026   app_namespace_t *default_ns = app_namespace_get_default ();
1027   u32 local_ns_index = default_ns->local_table_index;
1028   int verbose = 0, rv;
1029   app_namespace_t *app_ns;
1030   u64 handle;
1031
1032   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1033     {
1034       if (unformat (input, "verbose"))
1035         verbose = 1;
1036       else
1037         {
1038           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1039                            input);
1040           return -1;
1041         }
1042     }
1043
1044   server_sep.is_ip4 = 1;
1045   server_sep.port = dummy_port;
1046   clib_memset (options, 0, sizeof (options));
1047
1048   vnet_app_attach_args_t attach_args = {
1049     .api_client_index = ~0,
1050     .options = options,
1051     .namespace_id = 0,
1052     .session_cb_vft = &dummy_session_cbs,
1053     .name = format (0, "session_test"),
1054   };
1055
1056   vnet_bind_args_t bind_args = {
1057     .sep = server_sep,
1058     .app_index = 0,
1059   };
1060
1061   /*
1062    * Attach server with global and local default scope
1063    */
1064   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1065   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1066   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1067   attach_args.namespace_id = 0;
1068   attach_args.api_client_index = dummy_server_api_index;
1069   error = vnet_application_attach (&attach_args);
1070   SESSION_TEST ((error == 0), "server attached");
1071   server_index = attach_args.app_index;
1072
1073   bind_args.app_index = server_index;
1074   error = vnet_bind (&bind_args);
1075   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
1076                 &server_sep.ip, 1, server_sep.port);
1077   listener = listen_session_get_from_handle (bind_args.handle);
1078   ip4_address_t lcl_ip = {
1079     .as_u32 = clib_host_to_net_u32 (0x01020304),
1080   };
1081   ip4_address_t rmt_ip = {
1082     .as_u32 = clib_host_to_net_u32 (0x05060708),
1083   };
1084   fib_prefix_t lcl_pref = {
1085     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
1086     .fp_len = 16,
1087     .fp_proto = FIB_PROTOCOL_IP4,
1088   };
1089   fib_prefix_t rmt_pref = {
1090     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1091     .fp_len = 16,
1092     .fp_proto = FIB_PROTOCOL_IP4,
1093   };
1094
1095   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1096                                       &rmt_pref.fp_addr.ip4, lcl_port,
1097                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1098                                       &is_filtered);
1099   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
1100
1101   /*
1102    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
1103    */
1104   session_rule_add_del_args_t args = {
1105     .table_args.lcl = lcl_pref,
1106     .table_args.rmt = rmt_pref,
1107     .table_args.lcl_port = lcl_port,
1108     .table_args.rmt_port = rmt_port,
1109     .table_args.action_index = server_index,
1110     .table_args.is_add = 1,
1111     .appns_index = 0,
1112   };
1113   error = vnet_session_rule_add_del (&args);
1114   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
1115                 args.table_args.action_index);
1116
1117   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
1118                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
1119                                    TRANSPORT_PROTO_TCP);
1120   SESSION_TEST ((tc->c_index == listener->connection_index),
1121                 "optimized lookup should return the listener");
1122   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1123                                       &rmt_pref.fp_addr.ip4, lcl_port,
1124                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1125                                       &is_filtered);
1126   SESSION_TEST ((tc->c_index == listener->connection_index),
1127                 "lookup should return the listener");
1128   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
1129                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
1130   SESSION_TEST ((s->connection_index == listener->connection_index),
1131                 "safe lookup should return the listener");
1132   session_endpoint_t sep = {
1133     .ip = rmt_pref.fp_addr,
1134     .is_ip4 = 1,
1135     .port = rmt_port,
1136     .transport_proto = TRANSPORT_PROTO_TCP,
1137   };
1138   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1139   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1140                 "should not work (global scope)");
1141
1142   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1143                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1144                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1145                                       &is_filtered);
1146   SESSION_TEST ((tc == 0),
1147                 "optimized lookup for wrong lcl port + 1 should not work");
1148
1149   /*
1150    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
1151    */
1152   args.table_args.lcl_port = 0;
1153   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
1154   error = vnet_session_rule_add_del (&args);
1155   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
1156                 args.table_args.action_index);
1157   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1158                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1159                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1160                                       &is_filtered);
1161   SESSION_TEST ((tc->c_index == listener->connection_index),
1162                 "optimized lookup for lcl port + 1 should work");
1163   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1164   SESSION_TEST ((handle == server_index), "local session endpoint lookup "
1165                 "should work (lcl ip was zeroed)");
1166
1167   /*
1168    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1169    */
1170   args.table_args.lcl_port = 1234;
1171   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1172   args.table_args.lcl.fp_len = 30;
1173   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1174   args.table_args.rmt.fp_len = 30;
1175   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1176   error = vnet_session_rule_add_del (&args);
1177   SESSION_TEST ((error == 0), "Add 1.2.3.4/30 1234 5.6.7.8/30 4321 action %d",
1178                 args.table_args.action_index);
1179
1180   if (verbose)
1181     {
1182       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1183                                        TRANSPORT_PROTO_TCP);
1184       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1185                                              TRANSPORT_PROTO_TCP);
1186     }
1187
1188   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1189                                       &rmt_pref.fp_addr.ip4, lcl_port,
1190                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1191                                       &is_filtered);
1192   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
1193                 "should fail (deny rule)");
1194   SESSION_TEST ((is_filtered == 1), "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   rv = clib_error_get_code (error);
1257   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1258                 "connect should be filtered");
1259
1260   sep.ip.ip4.as_u32 -= 1 << 24;
1261
1262   /*
1263    * Delete masking rule: 1.2.3.4/32 1234 5.6.7.8/32 4321 allow
1264    */
1265   args.table_args.is_add = 0;
1266   args.table_args.lcl_port = 1234;
1267   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1268   args.table_args.lcl.fp_len = 32;
1269   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1270   args.table_args.rmt.fp_len = 32;
1271   error = vnet_session_rule_add_del (&args);
1272   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 allow");
1273
1274
1275   /*
1276    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
1277    */
1278   args.table_args.is_add = 1;
1279   args.table_args.lcl_port = 0;
1280   args.table_args.lcl.fp_len = 0;
1281   args.table_args.rmt.fp_len = 16;
1282   args.table_args.action_index = -1;
1283   error = vnet_session_rule_add_del (&args);
1284   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
1285                 args.table_args.action_index);
1286
1287   if (verbose)
1288     {
1289       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1290                                        TRANSPORT_PROTO_TCP);
1291       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1292                                              TRANSPORT_PROTO_TCP);
1293     }
1294
1295   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1296   SESSION_TEST ((handle == SESSION_DROP_HANDLE),
1297                 "local session endpoint lookup should return deny");
1298
1299   /*
1300    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
1301    */
1302   args.table_args.is_add = 0;
1303   args.table_args.lcl_port = 1234;
1304   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1305   args.table_args.lcl.fp_len = 30;
1306   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1307   args.table_args.rmt.fp_len = 30;
1308   error = vnet_session_rule_add_del (&args);
1309   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1310
1311   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1312   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1313                 "local session endpoint lookup should return invalid");
1314
1315   /*
1316    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
1317    * 1.2.3.4/16 1234 5.6.7.8/16 4321
1318    */
1319   args.table_args.is_add = 0;
1320   args.table_args.lcl_port = 0;
1321   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1322   args.table_args.lcl.fp_len = 0;
1323   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1324   args.table_args.rmt.fp_len = 16;
1325   args.table_args.rmt_port = 4321;
1326   error = vnet_session_rule_add_del (&args);
1327   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
1328   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1329   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1330                 "should not work (removed)");
1331
1332   args.table_args.is_add = 0;
1333   args.table_args.lcl = lcl_pref;
1334
1335   args.table_args.is_add = 0;
1336   args.table_args.lcl_port = 0;
1337   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1338   args.table_args.lcl.fp_len = 16;
1339   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1340   args.table_args.rmt.fp_len = 16;
1341   args.table_args.rmt_port = 4321;
1342   error = vnet_session_rule_add_del (&args);
1343   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
1344   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1345                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1346                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1347                                       &is_filtered);
1348   SESSION_TEST ((tc == 0),
1349                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
1350                 "work (del)");
1351
1352   args.table_args.is_add = 0;
1353   args.table_args.lcl_port = 1234;
1354   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1355   args.table_args.lcl.fp_len = 16;
1356   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1357   args.table_args.rmt.fp_len = 16;
1358   args.table_args.rmt_port = 4321;
1359   error = vnet_session_rule_add_del (&args);
1360   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
1361   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1362                                       &rmt_pref.fp_addr.ip4, lcl_port,
1363                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1364                                       &is_filtered);
1365   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
1366                 "not work (del + deny)");
1367
1368   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1369   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1370                                       &rmt_pref.fp_addr.ip4, lcl_port,
1371                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1372                                       &is_filtered);
1373   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
1374                 " not work (no-rule)");
1375
1376   /*
1377    * Test tags. Add/overwrite/del rule with tag
1378    */
1379   args.table_args.is_add = 1;
1380   args.table_args.lcl_port = 1234;
1381   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1382   args.table_args.lcl.fp_len = 16;
1383   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1384   args.table_args.rmt.fp_len = 16;
1385   args.table_args.rmt_port = 4321;
1386   args.table_args.tag = format (0, "test_rule");
1387   args.table_args.action_index = server_index;
1388   error = vnet_session_rule_add_del (&args);
1389   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
1390                 "tag test_rule");
1391   if (verbose)
1392     {
1393       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1394                                        TRANSPORT_PROTO_TCP);
1395       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1396                                              TRANSPORT_PROTO_TCP);
1397     }
1398   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1399                                       &rmt_pref.fp_addr.ip4, lcl_port,
1400                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1401                                       &is_filtered);
1402   SESSION_TEST ((tc->c_index == listener->connection_index),
1403                 "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
1404
1405   vec_free (args.table_args.tag);
1406   args.table_args.lcl_port = 1234;
1407   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1408   args.table_args.lcl.fp_len = 16;
1409   args.table_args.tag = format (0, "test_rule_overwrite");
1410   error = vnet_session_rule_add_del (&args);
1411   SESSION_TEST ((error == 0),
1412                 "Overwrite 1.2.3.4/16 1234 5.6.7.8/16 4321 deny tag test_rule"
1413                 " should work");
1414   if (verbose)
1415     {
1416       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1417                                        TRANSPORT_PROTO_TCP);
1418       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1419                                              TRANSPORT_PROTO_TCP);
1420     }
1421
1422   args.table_args.is_add = 0;
1423   args.table_args.lcl_port += 1;
1424   error = vnet_session_rule_add_del (&args);
1425   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
1426                 "tag %v", args.table_args.tag);
1427   if (verbose)
1428     {
1429       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1430                                        TRANSPORT_PROTO_TCP);
1431       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1432                                              TRANSPORT_PROTO_TCP);
1433     }
1434   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1435                                       &rmt_pref.fp_addr.ip4, lcl_port,
1436                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1437                                       &is_filtered);
1438   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/32 4321 should not"
1439                 " work (del)");
1440
1441
1442   /*
1443    * Test local rules with multiple namespaces
1444    */
1445
1446   /*
1447    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1448    */
1449   args.table_args.is_add = 1;
1450   args.table_args.lcl_port = 1234;
1451   args.table_args.rmt_port = 0;
1452   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1453   args.table_args.lcl.fp_len = 32;
1454   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1455   args.table_args.rmt.fp_len = 32;
1456   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1457   args.table_args.tag = 0;
1458   args.scope = SESSION_RULE_SCOPE_LOCAL;
1459   error = vnet_session_rule_add_del (&args);
1460   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
1461                 args.table_args.action_index);
1462   /*
1463    * Add 'white' rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1464    */
1465   args.table_args.is_add = 1;
1466   args.table_args.lcl_port = 1234;
1467   args.table_args.rmt_port = 4321;
1468   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1469   args.table_args.lcl.fp_len = 32;
1470   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1471   args.table_args.rmt.fp_len = 32;
1472   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
1473   error = vnet_session_rule_add_del (&args);
1474
1475   if (verbose)
1476     {
1477       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1478                                              TRANSPORT_PROTO_TCP);
1479     }
1480
1481   vnet_app_namespace_add_del_args_t ns_args = {
1482     .ns_id = ns_id,
1483     .secret = 0,
1484     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
1485     .is_add = 1
1486   };
1487   error = vnet_app_namespace_add_del (&ns_args);
1488   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
1489                 clib_error_get_code (error));
1490   app_ns = app_namespace_get_from_id (ns_id);
1491
1492   attach_args.namespace_id = ns_id;
1493   attach_args.api_client_index = dummy_server_api_index - 1;
1494   error = vnet_application_attach (&attach_args);
1495   SESSION_TEST ((error == 0), "server2 attached");
1496   server_index2 = attach_args.app_index;
1497
1498   /*
1499    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1500    */
1501   args.table_args.lcl_port = 1234;
1502   args.table_args.rmt_port = 0;
1503   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1504   args.table_args.lcl.fp_len = 32;
1505   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1506   args.table_args.rmt.fp_len = 32;
1507   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1508   args.appns_index = app_namespace_index (app_ns);
1509
1510   error = vnet_session_rule_add_del (&args);
1511   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d "
1512                 "in test namespace", args.table_args.action_index);
1513   /*
1514    * Lookup default namespace
1515    */
1516   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1517   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1518                 "lookup for 1.2.3.4/32 1234 5.6.7.8/32 4321 in local table "
1519                 "should return allow (invalid)");
1520
1521   sep.port += 1;
1522   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1523   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1524                 "5.6.7.8/16 432*2* in local table should return deny");
1525
1526
1527   connect_args.app_index = server_index;
1528   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
1529
1530   error = vnet_connect (&connect_args);
1531   SESSION_TEST ((error != 0), "connect should fail");
1532   rv = clib_error_get_code (error);
1533   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1534                 "connect should be filtered");
1535
1536   /*
1537    * Lookup test namespace
1538    */
1539   handle = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1540   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1541                 "5.6.7.8/16 4321 in local table should return deny");
1542
1543   connect_args.app_index = server_index;
1544   error = vnet_connect (&connect_args);
1545   SESSION_TEST ((error != 0), "connect should fail");
1546   rv = clib_error_get_code (error);
1547   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1548                 "connect should be filtered");
1549
1550   args.table_args.is_add = 0;
1551   vnet_session_rule_add_del (&args);
1552
1553   args.appns_index = 0;
1554   args.table_args.is_add = 0;
1555   vnet_session_rule_add_del (&args);
1556
1557   args.table_args.rmt_port = 4321;
1558   vnet_session_rule_add_del (&args);
1559   /*
1560    * Final Cleanup
1561    */
1562   vec_free (args.table_args.tag);
1563   vnet_app_detach_args_t detach_args = {
1564     .app_index = server_index,
1565   };
1566   vnet_application_detach (&detach_args);
1567
1568   detach_args.app_index = server_index2;
1569   vnet_application_detach (&detach_args);
1570
1571   vec_free (ns_id);
1572   vec_free (attach_args.name);
1573   return 0;
1574 }
1575
1576 static int
1577 session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
1578 {
1579   u64 options[APP_OPTIONS_N_OPTIONS];
1580   char *show_listeners = "sh session listeners tcp verbose";
1581   char *show_local_listeners = "sh app ns table default";
1582   unformat_input_t tmp_input;
1583   u32 server_index, app_index;
1584   u32 dummy_server_api_index = ~0, sw_if_index = 0;
1585   clib_error_t *error = 0;
1586   u8 is_filtered = 0;
1587   stream_session_t *s;
1588   transport_connection_t *tc;
1589   u16 lcl_port = 1234, rmt_port = 4321;
1590   app_namespace_t *app_ns;
1591   int verbose = 0;
1592
1593   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1594     {
1595       if (unformat (input, "verbose"))
1596         verbose = 1;
1597       else
1598         {
1599           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1600                            input);
1601           return -1;
1602         }
1603     }
1604
1605   ip4_address_t lcl_ip = {
1606     .as_u32 = clib_host_to_net_u32 (0x01020304),
1607   };
1608   ip4_address_t rmt_ip = {
1609     .as_u32 = clib_host_to_net_u32 (0x05060708),
1610   };
1611   fib_prefix_t rmt_pref = {
1612     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1613     .fp_len = 16,
1614     .fp_proto = FIB_PROTOCOL_IP4,
1615   };
1616   session_endpoint_t sep = {
1617     .ip = rmt_pref.fp_addr,
1618     .is_ip4 = 1,
1619     .port = rmt_port,
1620     .transport_proto = TRANSPORT_PROTO_TCP,
1621   };
1622
1623   /*
1624    * Create loopback interface
1625    */
1626   session_create_lookpback (0, &sw_if_index, &lcl_ip);
1627
1628   app_ns = app_namespace_get_default ();
1629   app_ns->sw_if_index = sw_if_index;
1630
1631   clib_memset (options, 0, sizeof (options));
1632   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1633   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
1634   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
1635   options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
1636   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1637   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1638   vnet_app_attach_args_t attach_args = {
1639     .api_client_index = ~0,
1640     .options = options,
1641     .namespace_id = 0,
1642     .session_cb_vft = &dummy_session_cbs,
1643     .name = format (0, "session_test"),
1644   };
1645
1646   attach_args.api_client_index = dummy_server_api_index;
1647   error = vnet_application_attach (&attach_args);
1648   SESSION_TEST ((error == 0), "server attachment should work");
1649   server_index = attach_args.app_index;
1650
1651   if (verbose)
1652     {
1653       unformat_init_string (&tmp_input, show_listeners,
1654                             strlen (show_listeners));
1655       vlib_cli_input (vm, &tmp_input, 0, 0);
1656       unformat_init_string (&tmp_input, show_local_listeners,
1657                             strlen (show_local_listeners));
1658       vlib_cli_input (vm, &tmp_input, 0, 0);
1659     }
1660
1661   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
1662                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
1663   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
1664                 "successful");
1665   s = listen_session_get (tc->s_index);
1666   SESSION_TEST ((s->app_index == server_index), "lookup should return"
1667                 " the server");
1668
1669   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
1670                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
1671   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
1672                 " not work");
1673
1674   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1675   SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
1676                 " should work");
1677
1678   vnet_app_detach_args_t detach_args = {
1679     .app_index = server_index,
1680   };
1681   vnet_application_detach (&detach_args);
1682
1683   if (verbose)
1684     {
1685       unformat_init_string (&tmp_input, show_listeners,
1686                             strlen (show_listeners));
1687       vlib_cli_input (vm, &tmp_input, 0, 0);
1688       unformat_init_string (&tmp_input, show_local_listeners,
1689                             strlen (show_local_listeners));
1690       vlib_cli_input (vm, &tmp_input, 0, 0);
1691     }
1692
1693   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1694   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
1695                 "local session endpoint lookup should not work after detach");
1696   if (verbose)
1697     unformat_free (&tmp_input);
1698   vec_free (attach_args.name);
1699   return 0;
1700 }
1701
1702 static clib_error_t *
1703 session_test (vlib_main_t * vm,
1704               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1705 {
1706   int res = 0;
1707
1708   vnet_session_enable_disable (vm, 1);
1709
1710   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1711     {
1712       if (unformat (input, "basic"))
1713         res = session_test_basic (vm, input);
1714       else if (unformat (input, "namespace"))
1715         res = session_test_namespace (vm, input);
1716       else if (unformat (input, "rules-table"))
1717         res = session_test_rule_table (vm, input);
1718       else if (unformat (input, "rules"))
1719         res = session_test_rules (vm, input);
1720       else if (unformat (input, "proxy"))
1721         res = session_test_proxy (vm, input);
1722       else if (unformat (input, "endpt-cfg"))
1723         res = session_test_endpoint_cfg (vm, input);
1724       else if (unformat (input, "all"))
1725         {
1726           if ((res = session_test_basic (vm, input)))
1727             goto done;
1728           if ((res = session_test_namespace (vm, input)))
1729             goto done;
1730           if ((res = session_test_rule_table (vm, input)))
1731             goto done;
1732           if ((res = session_test_rules (vm, input)))
1733             goto done;
1734           if ((res = session_test_proxy (vm, input)))
1735             goto done;
1736           if ((res = session_test_endpoint_cfg (vm, input)))
1737             goto done;
1738         }
1739       else
1740         break;
1741     }
1742
1743 done:
1744   if (res)
1745     return clib_error_return (0, "Session unit test failed");
1746   return 0;
1747 }
1748
1749 /* *INDENT-OFF* */
1750 VLIB_CLI_COMMAND (tcp_test_command, static) =
1751 {
1752   .path = "test session",
1753   .short_help = "internal session unit tests",
1754   .function = session_test,
1755 };
1756 /* *INDENT-ON* */
1757
1758 /*
1759  * fd.io coding-style-patch-verification: ON
1760  *
1761  * Local Variables:
1762  * eval: (c-set-style "gnu")
1763  * End:
1764  */