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