session: cleanup application interface
[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 (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                                   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, u64 segment_handle)
67 {
68   dummy_segment_count = 1;
69   return 0;
70 }
71
72 int
73 dummy_del_segment_callback (u32 client_index, u64 segment_handle)
74 {
75   dummy_segment_count = 0;
76   return 0;
77 }
78
79 void
80 dummy_session_disconnect_callback (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 (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 (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   u32 server_index;
165   int error = 0;
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_listen_args_t bind_args = {
186     .sep = server_sep,
187     .app_index = 0,
188   };
189
190   bind_args.app_index = server_index;
191   error = vnet_listen (&bind_args);
192   SESSION_TEST ((error == 0), "server bind4 should work");
193   bind4_handle = bind_args.handle;
194
195   error = vnet_listen (&bind_args);
196   SESSION_TEST ((error != 0), "double server bind4 should not work");
197
198   bind_args.sep.is_ip4 = 0;
199   error = vnet_listen (&bind_args);
200   SESSION_TEST ((error == 0), "server bind6 should work");
201   bind6_handle = bind_args.handle;
202
203   error = vnet_listen (&bind_args);
204   SESSION_TEST ((error != 0), "double server bind6 should not work");
205
206   vnet_unlisten_args_t unbind_args = {
207     .handle = bind4_handle,
208     .app_index = server_index,
209   };
210   error = vnet_unlisten (&unbind_args);
211   SESSION_TEST ((error == 0), "unbind4 should work");
212
213   unbind_args.handle = bind6_handle;
214   error = vnet_unlisten (&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     .api_client_index = ~0,
220   };
221   vnet_application_detach (&detach_args);
222   return 0;
223 }
224
225 static void
226 session_add_del_route_via_lookup_in_table (u32 in_table_id, u32 via_table_id,
227                                            ip4_address_t * ip, u8 mask,
228                                            u8 is_add)
229 {
230   fib_route_path_t *rpaths = 0, *rpath;
231   u32 in_fib_index, via_fib_index;
232
233   fib_prefix_t prefix = {
234     .fp_addr.ip4.as_u32 = ip->as_u32,
235     .fp_len = mask,
236     .fp_proto = FIB_PROTOCOL_IP4,
237   };
238
239   via_fib_index = fib_table_find (FIB_PROTOCOL_IP4, via_table_id);
240   if (via_fib_index == ~0)
241     {
242       clib_warning ("couldn't resolve via table id to index");
243       return;
244     }
245   in_fib_index = fib_table_find (FIB_PROTOCOL_IP4, in_table_id);
246   if (in_fib_index == ~0)
247     {
248       clib_warning ("couldn't resolve in table id to index");
249       return;
250     }
251
252   vec_add2 (rpaths, rpath, 1);
253   clib_memset (rpath, 0, sizeof (*rpath));
254   rpath->frp_weight = 1;
255   rpath->frp_fib_index = via_fib_index;
256   rpath->frp_proto = DPO_PROTO_IP4;
257   rpath->frp_sw_if_index = ~0;
258   rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
259
260   if (is_add)
261     fib_table_entry_path_add2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
262                                FIB_ENTRY_FLAG_NONE, rpath);
263   else
264     fib_table_entry_path_remove2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
265                                   rpath);
266   vec_free (rpaths);
267 }
268
269 static int
270 session_test_endpoint_cfg (vlib_main_t * vm, unformat_input_t * input)
271 {
272   session_endpoint_cfg_t client_sep = SESSION_ENDPOINT_CFG_NULL;
273   u32 server_index, client_index, sw_if_index[2], tries = 0;
274   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
275   u16 dummy_server_port = 1234, dummy_client_port = 5678;
276   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
277   ip4_address_t intf_addr[3];
278   transport_connection_t *tc;
279   session_t *s;
280   u8 *appns_id;
281   int error;
282
283   /*
284    * Create the loopbacks
285    */
286   intf_addr[0].as_u32 = clib_host_to_net_u32 (0x01010101),
287     session_create_lookpback (0, &sw_if_index[0], &intf_addr[0]);
288
289   intf_addr[1].as_u32 = clib_host_to_net_u32 (0x02020202),
290     session_create_lookpback (1, &sw_if_index[1], &intf_addr[1]);
291
292   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
293                                              1 /* is_add */ );
294   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
295                                              1 /* is_add */ );
296
297   /*
298    * Insert namespace
299    */
300   appns_id = format (0, "appns1");
301   vnet_app_namespace_add_del_args_t ns_args = {
302     .ns_id = appns_id,
303     .secret = dummy_secret,
304     .sw_if_index = sw_if_index[1],
305     .ip4_fib_id = 0,
306     .is_add = 1
307   };
308   error = vnet_app_namespace_add_del (&ns_args);
309   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", 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_listen_args_t bind_args = {
343     .sep = server_sep,
344     .app_index = server_index,
345   };
346   error = vnet_listen (&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   session_transport_cleanup (s);
391   s = session_get (accepted_session_index, accepted_session_thread);
392   session_transport_cleanup (s);
393
394   vnet_app_detach_args_t detach_args = {
395     .app_index = server_index,
396     .api_client_index = ~0,
397   };
398   vnet_application_detach (&detach_args);
399   detach_args.app_index = client_index;
400   vnet_application_detach (&detach_args);
401
402   /* Allow the disconnects to finish before removing the routes. */
403   vlib_process_suspend (vm, 10e-3);
404
405   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
406                                              0 /* is_add */ );
407   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
408                                              0 /* is_add */ );
409
410   session_delete_loopback (sw_if_index[0]);
411   session_delete_loopback (sw_if_index[1]);
412   return 0;
413 }
414
415 static int
416 session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
417 {
418   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
419   u32 server_index, server_st_index, server_local_st_index;
420   u32 dummy_port = 1234, client_index, server_wrk_index;
421   u32 dummy_api_context = 4321, dummy_client_api_index = ~0;
422   u32 dummy_server_api_index = ~0, sw_if_index = 0;
423   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
424   session_endpoint_t client_sep = SESSION_ENDPOINT_NULL;
425   session_endpoint_t intf_sep = SESSION_ENDPOINT_NULL;
426   u8 *ns_id = format (0, "appns1");
427   app_namespace_t *app_ns;
428   application_t *server;
429   session_t *s;
430   u64 handle;
431   int error = 0;
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_listen_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_unlisten_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     .api_client_index = ~0,
467   };
468
469   ip4_address_t intf_addr = {
470     .as_u32 = clib_host_to_net_u32 (0x07000105),
471   };
472
473   intf_sep.ip.ip4 = intf_addr;
474   intf_sep.is_ip4 = 1;
475   intf_sep.port = dummy_port;
476
477   /*
478    * Insert namespace and lookup
479    */
480
481   vnet_app_namespace_add_del_args_t ns_args = {
482     .ns_id = ns_id,
483     .secret = dummy_secret,
484     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
485     .is_add = 1
486   };
487   error = vnet_app_namespace_add_del (&ns_args);
488   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", 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   SESSION_TEST ((error == VNET_API_ERROR_APP_WRONG_NS_SECRET),
510                 "code should be wrong ns secret: %d", error);
511
512   /*
513    * Attach server with global default scope
514    */
515   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
516   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
517   options[APP_OPTIONS_NAMESPACE_SECRET] = 0;
518   attach_args.namespace_id = 0;
519   attach_args.api_client_index = dummy_server_api_index;
520   error = vnet_application_attach (&attach_args);
521   SESSION_TEST ((error == 0), "server attachment should work");
522   server_index = attach_args.app_index;
523   server = application_get (server_index);
524   server_wrk_index = application_get_default_worker (server)->wrk_index;
525   SESSION_TEST ((server->ns_index == 0),
526                 "server should be in the default ns");
527
528   bind_args.app_index = server_index;
529   error = vnet_listen (&bind_args);
530   SESSION_TEST ((error == 0), "server bind should work");
531
532   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
533   s = session_lookup_listener (server_st_index, &server_sep);
534   SESSION_TEST ((s != 0), "listener should exist in global table");
535   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
536                 " that of the server");
537   server_local_st_index = application_local_session_table (server);
538   SESSION_TEST ((server_local_st_index == APP_INVALID_INDEX),
539                 "server shouldn't have access to local table");
540
541   unbind_args.app_index = server_index;
542   unbind_args.handle = bind_args.handle;
543   error = vnet_unlisten (&unbind_args);
544   SESSION_TEST ((error == 0), "unbind should work");
545
546   s = session_lookup_listener (server_st_index, &server_sep);
547   SESSION_TEST ((s == 0), "listener should not exist in global table");
548
549   detach_args.app_index = server_index;
550   vnet_application_detach (&detach_args);
551
552   /*
553    * Attach server with local and global scope
554    */
555   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
556   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
557   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
558   attach_args.namespace_id = ns_id;
559   attach_args.api_client_index = dummy_server_api_index;
560   error = vnet_application_attach (&attach_args);
561   SESSION_TEST ((error == 0), "server attachment should work");
562   server_index = attach_args.app_index;
563   server = application_get (server_index);
564   server_wrk_index = application_get_default_worker (server)->wrk_index;
565   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
566                 "server should be in the right ns");
567
568   bind_args.app_index = server_index;
569   error = vnet_listen (&bind_args);
570   SESSION_TEST ((error == 0), "bind should work");
571   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
572   s = session_lookup_listener (server_st_index, &server_sep);
573   SESSION_TEST ((s != 0), "listener should exist in global table");
574   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
575                 " that of the server");
576   server_local_st_index = application_local_session_table (server);
577   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
578   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
579                 "listener should exist in local table");
580
581   /*
582    * Try client connect with 1) local scope 2) global scope
583    */
584   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
585   attach_args.api_client_index = dummy_client_api_index;
586   error = vnet_application_attach (&attach_args);
587   SESSION_TEST ((error == 0), "client attachment should work");
588   client_index = attach_args.app_index;
589   connect_args.api_context = dummy_api_context;
590   connect_args.app_index = client_index;
591   error = vnet_connect (&connect_args);
592   SESSION_TEST ((error != 0), "client connect should return error code");
593   SESSION_TEST ((error == VNET_API_ERROR_INVALID_VALUE),
594                 "error code should be invalid value (zero ip)");
595   SESSION_TEST ((dummy_segment_count == 0),
596                 "shouldn't have received request to map new segment");
597   connect_args.sep.ip.ip4.as_u8[0] = 127;
598   error = vnet_connect (&connect_args);
599   SESSION_TEST ((error == 0), "client connect should not return error code");
600   SESSION_TEST ((dummy_segment_count == 1),
601                 "should've received request to map new segment");
602   SESSION_TEST ((dummy_accept == 1), "should've received accept request");
603   detach_args.app_index = client_index;
604   vnet_application_detach (&detach_args);
605
606   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
607   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
608   attach_args.api_client_index = dummy_client_api_index;
609   error = vnet_application_attach (&attach_args);
610   SESSION_TEST ((error == 0), "client attachment should work");
611   error = vnet_connect (&connect_args);
612   SESSION_TEST ((error != 0), "client connect should return error code");
613   SESSION_TEST ((error == VNET_API_ERROR_SESSION_CONNECT),
614                 "error code should be connect (nothing in local scope)");
615   detach_args.app_index = client_index;
616   vnet_application_detach (&detach_args);
617
618   /*
619    * Unbind and detach server and then re-attach with local scope only
620    */
621   unbind_args.handle = bind_args.handle;
622   unbind_args.app_index = server_index;
623   error = vnet_unlisten (&unbind_args);
624   SESSION_TEST ((error == 0), "unbind should work");
625
626   s = session_lookup_listener (server_st_index, &server_sep);
627   SESSION_TEST ((s == 0), "listener should not exist in global table");
628   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
629   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
630                 "listener should not exist in local table");
631
632   detach_args.app_index = server_index;
633   vnet_application_detach (&detach_args);
634
635   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
636   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
637   attach_args.api_client_index = dummy_server_api_index;
638   error = vnet_application_attach (&attach_args);
639   SESSION_TEST ((error == 0), "app attachment should work");
640   server_index = attach_args.app_index;
641   server = application_get (server_index);
642   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
643                 "app should be in the right ns");
644
645   bind_args.app_index = server_index;
646   error = vnet_listen (&bind_args);
647   SESSION_TEST ((error == 0), "bind should work");
648
649   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
650   s = session_lookup_listener (server_st_index, &server_sep);
651   SESSION_TEST ((s == 0), "listener should not exist in global table");
652   server_local_st_index = application_local_session_table (server);
653   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
654   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
655                 "listener should exist in local table");
656
657   unbind_args.handle = bind_args.handle;
658   error = vnet_unlisten (&unbind_args);
659   SESSION_TEST ((error == 0), "unbind should work");
660
661   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
662   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
663                 "listener should not exist in local table");
664
665   /*
666    * Client attach + connect in default ns with local scope
667    */
668   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
669   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
670   attach_args.namespace_id = 0;
671   attach_args.api_client_index = dummy_client_api_index;
672   vnet_application_attach (&attach_args);
673   error = vnet_connect (&connect_args);
674   SESSION_TEST ((error != 0), "client connect should return error code");
675   SESSION_TEST ((error == VNET_API_ERROR_SESSION_CONNECT),
676                 "error code should be connect (not in same ns)");
677   detach_args.app_index = client_index;
678   vnet_application_detach (&detach_args);
679
680   /*
681    * Detach server
682    */
683   detach_args.app_index = server_index;
684   vnet_application_detach (&detach_args);
685
686   /*
687    * Create loopback interface
688    */
689   session_create_lookpback (0, &sw_if_index, &intf_addr);
690
691   /*
692    * Update namespace with interface
693    */
694   ns_args.sw_if_index = sw_if_index;
695   error = vnet_app_namespace_add_del (&ns_args);
696   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", error);
697
698   /*
699    * Attach server with local and global scope
700    */
701   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
702   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
703   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
704   attach_args.namespace_id = ns_id;
705   attach_args.api_client_index = dummy_server_api_index;
706   error = vnet_application_attach (&attach_args);
707   SESSION_TEST ((error == 0), "server attachment should work");
708   server_index = attach_args.app_index;
709   server = application_get (server_index);
710   server_wrk_index = application_get_default_worker (server)->wrk_index;
711
712   bind_args.app_index = server_index;
713   error = vnet_listen (&bind_args);
714   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
715   s = session_lookup_listener (server_st_index, &server_sep);
716   SESSION_TEST ((s == 0), "zero listener should not exist in global table");
717
718   s = session_lookup_listener (server_st_index, &intf_sep);
719   SESSION_TEST ((s != 0), "intf listener should exist in global table");
720   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be "
721                 "that of the server");
722   server_local_st_index = application_local_session_table (server);
723   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
724   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
725                 "zero listener should exist in local table");
726   detach_args.app_index = server_index;
727   vnet_application_detach (&detach_args);
728
729   /*
730    * Cleanup
731    */
732   vec_free (attach_args.name);
733   vec_free (ns_id);
734   session_delete_loopback (sw_if_index);
735   return 0;
736 }
737
738 static int
739 session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
740 {
741   session_rules_table_t _srt, *srt = &_srt;
742   u16 lcl_port = 1234, rmt_port = 4321;
743   u32 action_index = 1, res;
744   ip4_address_t lcl_lkup, rmt_lkup;
745   int verbose = 0, error;
746
747   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
748     {
749       if (unformat (input, "verbose"))
750         verbose = 1;
751       else
752         {
753           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
754                            input);
755           return -1;
756         }
757     }
758
759   clib_memset (srt, 0, sizeof (*srt));
760   session_rules_table_init (srt);
761
762   ip4_address_t lcl_ip = {
763     .as_u32 = clib_host_to_net_u32 (0x01020304),
764   };
765   ip4_address_t rmt_ip = {
766     .as_u32 = clib_host_to_net_u32 (0x05060708),
767   };
768   ip4_address_t lcl_ip2 = {
769     .as_u32 = clib_host_to_net_u32 (0x02020202),
770   };
771   ip4_address_t rmt_ip2 = {
772     .as_u32 = clib_host_to_net_u32 (0x06060606),
773   };
774   ip4_address_t lcl_ip3 = {
775     .as_u32 = clib_host_to_net_u32 (0x03030303),
776   };
777   ip4_address_t rmt_ip3 = {
778     .as_u32 = clib_host_to_net_u32 (0x07070707),
779   };
780   fib_prefix_t lcl_pref = {
781     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
782     .fp_len = 16,
783     .fp_proto = FIB_PROTOCOL_IP4,
784   };
785   fib_prefix_t rmt_pref = {
786     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
787     .fp_len = 16,
788     .fp_proto = FIB_PROTOCOL_IP4,
789   };
790
791   session_rule_table_add_del_args_t args = {
792     .lcl = lcl_pref,
793     .rmt = rmt_pref,
794     .lcl_port = lcl_port,
795     .rmt_port = rmt_port,
796     .action_index = action_index++,
797     .is_add = 1,
798   };
799   error = session_rules_table_add_del (srt, &args);
800   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
801                 action_index - 1);
802
803   res =
804     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
805   SESSION_TEST ((res == 1),
806                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
807                 res);
808
809   /*
810    * 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
811    */
812   args.lcl.fp_addr.ip4 = lcl_ip;
813   args.lcl.fp_len = 24;
814   args.action_index = action_index++;
815   error = session_rules_table_add_del (srt, &args);
816   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
817                 action_index - 1);
818   args.rmt.fp_addr.ip4 = rmt_ip;
819   args.rmt.fp_len = 24;
820   args.action_index = action_index++;
821   error = session_rules_table_add_del (srt, &args);
822   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
823                 action_index - 1);
824
825   /*
826    * 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
827    */
828   args.lcl.fp_addr.ip4 = lcl_ip2;
829   args.lcl.fp_len = 24;
830   args.rmt.fp_addr.ip4 = rmt_ip2;
831   args.rmt.fp_len = 16;
832   args.action_index = action_index++;
833   error = session_rules_table_add_del (srt, &args);
834   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
835                 action_index - 1);
836   args.lcl.fp_addr.ip4 = lcl_ip3;
837   args.rmt.fp_addr.ip4 = rmt_ip3;
838   args.action_index = action_index++;
839   error = session_rules_table_add_del (srt, &args);
840   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
841                 action_index - 1);
842
843   /*
844    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
845    */
846   args.lcl.fp_addr.ip4 = lcl_ip3;
847   args.rmt.fp_addr.ip4 = rmt_ip3;
848   args.action_index = action_index++;
849   error = session_rules_table_add_del (srt, &args);
850   SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
851                 "action %d", action_index - 1);
852
853   /*
854    * 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
855    * and  3.3.3.3 1234 7.7.7.7 4321
856    */
857   res =
858     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
859   SESSION_TEST ((res == 3),
860                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
861                 res);
862
863   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
864   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
865   res =
866     session_rules_table_lookup4 (srt, &lcl_lkup,
867                                  &rmt_lkup, lcl_port, rmt_port);
868   SESSION_TEST ((res == 1),
869                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
870                 res);
871
872   res =
873     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
874   SESSION_TEST ((res == 6),
875                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
876                 "should be 6 (updated): %d", res);
877
878   /*
879    * Add 1.2.3.4/24 * 5.6.7.8/24 *
880    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
881    */
882   args.lcl.fp_addr.ip4 = lcl_ip;
883   args.rmt.fp_addr.ip4 = rmt_ip;
884   args.lcl.fp_len = 24;
885   args.rmt.fp_len = 24;
886   args.lcl_port = 0;
887   args.rmt_port = 0;
888   args.action_index = action_index++;
889   error = session_rules_table_add_del (srt, &args);
890   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
891                 action_index - 1);
892   res =
893     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
894   SESSION_TEST ((res == 7),
895                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
896                 " be 7 (lpm dst): %d", res);
897   res =
898     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
899                                  lcl_port + 1, rmt_port);
900   SESSION_TEST ((res == 7),
901                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
902                 res);
903
904   /*
905    * Del 1.2.3.4/24 * 5.6.7.8/24 *
906    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
907    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
908    * 1.2.3.4 1235 5.6.7.8 4322
909    */
910   args.is_add = 0;
911   error = session_rules_table_add_del (srt, &args);
912   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
913
914   args.lcl.fp_addr.ip4 = lcl_ip;
915   args.rmt.fp_addr.ip4 = rmt_ip;
916   args.lcl.fp_len = 16;
917   args.rmt.fp_len = 16;
918   args.lcl_port = 0;
919   args.rmt_port = 0;
920   args.action_index = action_index++;
921   args.is_add = 1;
922   error = session_rules_table_add_del (srt, &args);
923   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
924                 action_index - 1);
925
926   args.lcl.fp_addr.ip4 = lcl_ip;
927   args.rmt.fp_addr.ip4 = rmt_ip;
928   args.lcl.fp_len = 24;
929   args.rmt.fp_len = 24;
930   args.lcl_port = lcl_port + 1;
931   args.rmt_port = rmt_port;
932   args.action_index = action_index++;
933   args.is_add = 1;
934   error = session_rules_table_add_del (srt, &args);
935   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
936                 action_index - 1);
937
938   if (verbose)
939     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
940
941   res =
942     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
943   SESSION_TEST ((res == 3),
944                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
945                 res);
946   res =
947     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
948                                  lcl_port + 1, rmt_port);
949   SESSION_TEST ((res == 9),
950                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
951                 res);
952   res =
953     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
954                                  lcl_port + 1, rmt_port + 1);
955   SESSION_TEST ((res == 8),
956                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
957                 res);
958
959   /*
960    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
961    * Lookup 1.2.3.4 1234 5.6.7.8 4321
962    */
963   args.lcl_port = 1234;
964   args.rmt_port = 4321;
965   args.lcl.fp_len = 16;
966   args.rmt.fp_len = 16;
967   args.is_add = 0;
968   error = session_rules_table_add_del (srt, &args);
969   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
970   res =
971     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
972   SESSION_TEST ((res == 3),
973                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
974                 res);
975
976   args.lcl_port = 0;
977   args.rmt_port = 0;
978   args.is_add = 0;
979   error = session_rules_table_add_del (srt, &args);
980   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
981   res =
982     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
983   SESSION_TEST ((res == 3),
984                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
985                 res);
986
987   /*
988    * Delete 1.2.3.4/24 1234 5.6.7.5/24
989    */
990   args.lcl.fp_addr.ip4 = lcl_ip;
991   args.rmt.fp_addr.ip4 = rmt_ip;
992   args.lcl.fp_len = 24;
993   args.rmt.fp_len = 24;
994   args.lcl_port = 1234;
995   args.rmt_port = 4321;
996   args.is_add = 0;
997   error = session_rules_table_add_del (srt, &args);
998   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
999   res =
1000     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
1001   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
1002
1003   return 0;
1004 }
1005
1006 static int
1007 session_test_rules (vlib_main_t * vm, unformat_input_t * input)
1008 {
1009   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
1010   u64 options[APP_OPTIONS_N_OPTIONS];
1011   u16 lcl_port = 1234, rmt_port = 4321;
1012   u32 server_index, server_index2;
1013   u32 dummy_server_api_index = ~0;
1014   transport_connection_t *tc;
1015   u32 dummy_port = 1111;
1016   u8 is_filtered = 0, *ns_id = format (0, "appns1");
1017   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;
1021   app_namespace_t *app_ns;
1022   app_listener_t *al;
1023   int error = 0;
1024   u64 handle;
1025
1026   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1027     {
1028       if (unformat (input, "verbose"))
1029         verbose = 1;
1030       else
1031         {
1032           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1033                            input);
1034           return -1;
1035         }
1036     }
1037
1038   server_sep.is_ip4 = 1;
1039   server_sep.port = dummy_port;
1040   clib_memset (options, 0, sizeof (options));
1041
1042   vnet_app_attach_args_t attach_args = {
1043     .api_client_index = ~0,
1044     .options = options,
1045     .namespace_id = 0,
1046     .session_cb_vft = &dummy_session_cbs,
1047     .name = format (0, "session_test"),
1048   };
1049
1050   vnet_listen_args_t bind_args = {
1051     .sep = server_sep,
1052     .app_index = 0,
1053   };
1054
1055   /*
1056    * Attach server with global and local default scope
1057    */
1058   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1059   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1060   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1061   attach_args.namespace_id = 0;
1062   attach_args.api_client_index = dummy_server_api_index;
1063   error = vnet_application_attach (&attach_args);
1064   SESSION_TEST ((error == 0), "server attached");
1065   server_index = attach_args.app_index;
1066
1067   bind_args.app_index = server_index;
1068   error = vnet_listen (&bind_args);
1069   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
1070                 &server_sep.ip, 1, server_sep.port);
1071   al = app_listener_get_w_handle (bind_args.handle);
1072   listener = app_listener_get_session (al);
1073   ip4_address_t lcl_ip = {
1074     .as_u32 = clib_host_to_net_u32 (0x01020304),
1075   };
1076   ip4_address_t rmt_ip = {
1077     .as_u32 = clib_host_to_net_u32 (0x05060708),
1078   };
1079   fib_prefix_t lcl_pref = {
1080     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
1081     .fp_len = 16,
1082     .fp_proto = FIB_PROTOCOL_IP4,
1083   };
1084   fib_prefix_t rmt_pref = {
1085     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1086     .fp_len = 16,
1087     .fp_proto = FIB_PROTOCOL_IP4,
1088   };
1089
1090   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1091                                       &rmt_pref.fp_addr.ip4, lcl_port,
1092                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1093                                       &is_filtered);
1094   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
1095
1096   /*
1097    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
1098    */
1099   session_rule_add_del_args_t args = {
1100     .table_args.lcl = lcl_pref,
1101     .table_args.rmt = rmt_pref,
1102     .table_args.lcl_port = lcl_port,
1103     .table_args.rmt_port = rmt_port,
1104     .table_args.action_index = server_index,
1105     .table_args.is_add = 1,
1106     .appns_index = 0,
1107   };
1108   error = vnet_session_rule_add_del (&args);
1109   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
1110                 args.table_args.action_index);
1111
1112   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
1113                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
1114                                    TRANSPORT_PROTO_TCP);
1115   SESSION_TEST ((tc->c_index == listener->connection_index),
1116                 "optimized lookup should return the listener");
1117   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1118                                       &rmt_pref.fp_addr.ip4, lcl_port,
1119                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1120                                       &is_filtered);
1121   SESSION_TEST ((tc->c_index == listener->connection_index),
1122                 "lookup should return the listener");
1123   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
1124                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
1125   SESSION_TEST ((s->connection_index == listener->connection_index),
1126                 "safe lookup should return the listener");
1127   session_endpoint_t sep = {
1128     .ip = rmt_pref.fp_addr,
1129     .is_ip4 = 1,
1130     .port = rmt_port,
1131     .transport_proto = TRANSPORT_PROTO_TCP,
1132   };
1133   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1134   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1135                 "should not work (global scope)");
1136
1137   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1138                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1139                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1140                                       &is_filtered);
1141   SESSION_TEST ((tc == 0),
1142                 "optimized lookup for wrong lcl port + 1 should not work");
1143
1144   /*
1145    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
1146    */
1147   args.table_args.lcl_port = 0;
1148   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
1149   error = vnet_session_rule_add_del (&args);
1150   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
1151                 args.table_args.action_index);
1152   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1153                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1154                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1155                                       &is_filtered);
1156   SESSION_TEST ((tc->c_index == listener->connection_index),
1157                 "optimized lookup for lcl port + 1 should work");
1158   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1159   SESSION_TEST ((handle == server_index), "local session endpoint lookup "
1160                 "should work (lcl ip was zeroed)");
1161
1162   /*
1163    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1164    */
1165   args.table_args.lcl_port = 1234;
1166   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1167   args.table_args.lcl.fp_len = 30;
1168   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1169   args.table_args.rmt.fp_len = 30;
1170   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1171   error = vnet_session_rule_add_del (&args);
1172   SESSION_TEST ((error == 0), "Add 1.2.3.4/30 1234 5.6.7.8/30 4321 action %d",
1173                 args.table_args.action_index);
1174
1175   if (verbose)
1176     {
1177       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1178                                        TRANSPORT_PROTO_TCP);
1179       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1180                                              TRANSPORT_PROTO_TCP);
1181     }
1182
1183   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1184                                       &rmt_pref.fp_addr.ip4, lcl_port,
1185                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1186                                       &is_filtered);
1187   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
1188                 "should fail (deny rule)");
1189   SESSION_TEST ((is_filtered == SESSION_LOOKUP_RESULT_FILTERED),
1190                 "lookup should be filtered (deny)");
1191
1192   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1193   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1194                 "5.6.7.8/16 4321 in local table should return deny");
1195
1196   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1197                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1198                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1199                                       &is_filtered);
1200   SESSION_TEST ((tc->c_index == listener->connection_index),
1201                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should work");
1202
1203   /*
1204    * "Mask" deny rule with more specific allow:
1205    * Add allow rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -3 (allow)
1206    */
1207   args.table_args.is_add = 1;
1208   args.table_args.lcl_port = 1234;
1209   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1210   args.table_args.lcl.fp_len = 32;
1211   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1212   args.table_args.rmt.fp_len = 32;
1213   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
1214   error = vnet_session_rule_add_del (&args);
1215   SESSION_TEST ((error == 0), "Add masking rule 1.2.3.4/30 1234 5.6.7.8/32 "
1216                 "4321 action %d", args.table_args.action_index);
1217
1218   is_filtered = 0;
1219   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1220                                       &rmt_pref.fp_addr.ip4, lcl_port,
1221                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1222                                       &is_filtered);
1223   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
1224                 "should fail (allow without app)");
1225   SESSION_TEST ((is_filtered == 0), "lookup should NOT be filtered");
1226
1227   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1228   SESSION_TEST ((handle == SESSION_INVALID_HANDLE), "lookup for 1.2.3.4/32 "
1229                 "1234 5.6.7.8/32 4321 in local table should return invalid");
1230
1231   if (verbose)
1232     {
1233       vlib_cli_output (vm, "Local rules");
1234       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1235                                              TRANSPORT_PROTO_TCP);
1236     }
1237
1238   sep.ip.ip4.as_u32 += 1 << 24;
1239   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1240   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234"
1241                 " 5.6.7.9/32 4321 in local table should return deny");
1242
1243   vnet_connect_args_t connect_args = {
1244     .app_index = attach_args.app_index,
1245     .api_context = 0,
1246   };
1247   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
1248
1249   /* Try connecting */
1250   error = vnet_connect (&connect_args);
1251   SESSION_TEST ((error != 0), "connect should fail");
1252   SESSION_TEST ((error == VNET_API_ERROR_APP_CONNECT_FILTERED),
1253                 "connect should be filtered");
1254
1255   sep.ip.ip4.as_u32 -= 1 << 24;
1256
1257   /*
1258    * Delete masking rule: 1.2.3.4/32 1234 5.6.7.8/32 4321 allow
1259    */
1260   args.table_args.is_add = 0;
1261   args.table_args.lcl_port = 1234;
1262   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1263   args.table_args.lcl.fp_len = 32;
1264   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1265   args.table_args.rmt.fp_len = 32;
1266   error = vnet_session_rule_add_del (&args);
1267   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 allow");
1268
1269
1270   /*
1271    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
1272    */
1273   args.table_args.is_add = 1;
1274   args.table_args.lcl_port = 0;
1275   args.table_args.lcl.fp_len = 0;
1276   args.table_args.rmt.fp_len = 16;
1277   args.table_args.action_index = -1;
1278   error = vnet_session_rule_add_del (&args);
1279   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
1280                 args.table_args.action_index);
1281
1282   if (verbose)
1283     {
1284       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1285                                        TRANSPORT_PROTO_TCP);
1286       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1287                                              TRANSPORT_PROTO_TCP);
1288     }
1289
1290   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1291   SESSION_TEST ((handle == SESSION_DROP_HANDLE),
1292                 "local session endpoint lookup should return deny");
1293
1294   /*
1295    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
1296    */
1297   args.table_args.is_add = 0;
1298   args.table_args.lcl_port = 1234;
1299   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1300   args.table_args.lcl.fp_len = 30;
1301   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1302   args.table_args.rmt.fp_len = 30;
1303   error = vnet_session_rule_add_del (&args);
1304   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1305
1306   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1307   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1308                 "local session endpoint lookup should return invalid");
1309
1310   /*
1311    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
1312    * 1.2.3.4/16 1234 5.6.7.8/16 4321
1313    */
1314   args.table_args.is_add = 0;
1315   args.table_args.lcl_port = 0;
1316   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1317   args.table_args.lcl.fp_len = 0;
1318   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1319   args.table_args.rmt.fp_len = 16;
1320   args.table_args.rmt_port = 4321;
1321   error = vnet_session_rule_add_del (&args);
1322   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
1323   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1324   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1325                 "should not work (removed)");
1326
1327   args.table_args.is_add = 0;
1328   args.table_args.lcl = lcl_pref;
1329
1330   args.table_args.is_add = 0;
1331   args.table_args.lcl_port = 0;
1332   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1333   args.table_args.lcl.fp_len = 16;
1334   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1335   args.table_args.rmt.fp_len = 16;
1336   args.table_args.rmt_port = 4321;
1337   error = vnet_session_rule_add_del (&args);
1338   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
1339   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1340                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1341                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1342                                       &is_filtered);
1343   SESSION_TEST ((tc == 0),
1344                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
1345                 "work (del)");
1346
1347   args.table_args.is_add = 0;
1348   args.table_args.lcl_port = 1234;
1349   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1350   args.table_args.lcl.fp_len = 16;
1351   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1352   args.table_args.rmt.fp_len = 16;
1353   args.table_args.rmt_port = 4321;
1354   error = vnet_session_rule_add_del (&args);
1355   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
1356   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1357                                       &rmt_pref.fp_addr.ip4, lcl_port,
1358                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1359                                       &is_filtered);
1360   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
1361                 "not work (del + deny)");
1362
1363   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1364   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1365                                       &rmt_pref.fp_addr.ip4, lcl_port,
1366                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1367                                       &is_filtered);
1368   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
1369                 " not work (no-rule)");
1370
1371   /*
1372    * Test tags. Add/overwrite/del rule with tag
1373    */
1374   args.table_args.is_add = 1;
1375   args.table_args.lcl_port = 1234;
1376   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1377   args.table_args.lcl.fp_len = 16;
1378   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1379   args.table_args.rmt.fp_len = 16;
1380   args.table_args.rmt_port = 4321;
1381   args.table_args.tag = format (0, "test_rule");
1382   args.table_args.action_index = server_index;
1383   error = vnet_session_rule_add_del (&args);
1384   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
1385                 "tag test_rule");
1386   if (verbose)
1387     {
1388       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1389                                        TRANSPORT_PROTO_TCP);
1390       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1391                                              TRANSPORT_PROTO_TCP);
1392     }
1393   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1394                                       &rmt_pref.fp_addr.ip4, lcl_port,
1395                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1396                                       &is_filtered);
1397   SESSION_TEST ((tc->c_index == listener->connection_index),
1398                 "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
1399
1400   vec_free (args.table_args.tag);
1401   args.table_args.lcl_port = 1234;
1402   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1403   args.table_args.lcl.fp_len = 16;
1404   args.table_args.tag = format (0, "test_rule_overwrite");
1405   error = vnet_session_rule_add_del (&args);
1406   SESSION_TEST ((error == 0),
1407                 "Overwrite 1.2.3.4/16 1234 5.6.7.8/16 4321 deny tag test_rule"
1408                 " should work");
1409   if (verbose)
1410     {
1411       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1412                                        TRANSPORT_PROTO_TCP);
1413       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1414                                              TRANSPORT_PROTO_TCP);
1415     }
1416
1417   args.table_args.is_add = 0;
1418   args.table_args.lcl_port += 1;
1419   error = vnet_session_rule_add_del (&args);
1420   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
1421                 "tag %v", args.table_args.tag);
1422   if (verbose)
1423     {
1424       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1425                                        TRANSPORT_PROTO_TCP);
1426       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1427                                              TRANSPORT_PROTO_TCP);
1428     }
1429   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1430                                       &rmt_pref.fp_addr.ip4, lcl_port,
1431                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1432                                       &is_filtered);
1433   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/32 4321 should not"
1434                 " work (del)");
1435
1436
1437   /*
1438    * Test local rules with multiple namespaces
1439    */
1440
1441   /*
1442    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1443    */
1444   args.table_args.is_add = 1;
1445   args.table_args.lcl_port = 1234;
1446   args.table_args.rmt_port = 0;
1447   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1448   args.table_args.lcl.fp_len = 32;
1449   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1450   args.table_args.rmt.fp_len = 32;
1451   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1452   args.table_args.tag = 0;
1453   args.scope = SESSION_RULE_SCOPE_LOCAL;
1454   error = vnet_session_rule_add_del (&args);
1455   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
1456                 args.table_args.action_index);
1457   /*
1458    * Add 'white' rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1459    */
1460   args.table_args.is_add = 1;
1461   args.table_args.lcl_port = 1234;
1462   args.table_args.rmt_port = 4321;
1463   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1464   args.table_args.lcl.fp_len = 32;
1465   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1466   args.table_args.rmt.fp_len = 32;
1467   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
1468   error = vnet_session_rule_add_del (&args);
1469
1470   if (verbose)
1471     {
1472       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1473                                              TRANSPORT_PROTO_TCP);
1474     }
1475
1476   vnet_app_namespace_add_del_args_t ns_args = {
1477     .ns_id = ns_id,
1478     .secret = 0,
1479     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
1480     .is_add = 1
1481   };
1482   error = vnet_app_namespace_add_del (&ns_args);
1483   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d", error);
1484   app_ns = app_namespace_get_from_id (ns_id);
1485
1486   attach_args.namespace_id = ns_id;
1487   attach_args.api_client_index = dummy_server_api_index;
1488   error = vnet_application_attach (&attach_args);
1489   SESSION_TEST ((error == 0), "server2 attached");
1490   server_index2 = attach_args.app_index;
1491
1492   /*
1493    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1494    */
1495   args.table_args.lcl_port = 1234;
1496   args.table_args.rmt_port = 0;
1497   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1498   args.table_args.lcl.fp_len = 32;
1499   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1500   args.table_args.rmt.fp_len = 32;
1501   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1502   args.appns_index = app_namespace_index (app_ns);
1503
1504   error = vnet_session_rule_add_del (&args);
1505   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d "
1506                 "in test namespace", args.table_args.action_index);
1507   /*
1508    * Lookup default namespace
1509    */
1510   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1511   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1512                 "lookup for 1.2.3.4/32 1234 5.6.7.8/32 4321 in local table "
1513                 "should return allow (invalid)");
1514
1515   sep.port += 1;
1516   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1517   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1518                 "5.6.7.8/16 432*2* in local table should return deny");
1519
1520
1521   connect_args.app_index = server_index;
1522   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
1523
1524   error = vnet_connect (&connect_args);
1525   SESSION_TEST ((error != 0), "connect should fail");
1526   SESSION_TEST ((error == VNET_API_ERROR_APP_CONNECT_FILTERED),
1527                 "connect should be filtered");
1528
1529   /*
1530    * Lookup test namespace
1531    */
1532   handle = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1533   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1534                 "5.6.7.8/16 4321 in local table should return deny");
1535
1536   connect_args.app_index = server_index;
1537   error = vnet_connect (&connect_args);
1538   SESSION_TEST ((error != 0), "connect should fail");
1539   SESSION_TEST ((error == 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     .api_client_index = ~0,
1558   };
1559   vnet_application_detach (&detach_args);
1560
1561   detach_args.app_index = server_index2;
1562   vnet_application_detach (&detach_args);
1563
1564   vec_free (ns_id);
1565   vec_free (attach_args.name);
1566   return 0;
1567 }
1568
1569 static int
1570 session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
1571 {
1572   u64 options[APP_OPTIONS_N_OPTIONS];
1573   char *show_listeners = "sh session listeners tcp verbose";
1574   char *show_local_listeners = "sh app ns table default";
1575   unformat_input_t tmp_input;
1576   u32 server_index, app_index;
1577   u32 dummy_server_api_index = ~0, sw_if_index = 0;
1578   u8 is_filtered = 0;
1579   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, error = 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     .api_client_index = ~0,
1673   };
1674   vnet_application_detach (&detach_args);
1675
1676   if (verbose)
1677     {
1678       unformat_init_string (&tmp_input, show_listeners,
1679                             strlen (show_listeners));
1680       vlib_cli_input (vm, &tmp_input, 0, 0);
1681       unformat_init_string (&tmp_input, show_local_listeners,
1682                             strlen (show_local_listeners));
1683       vlib_cli_input (vm, &tmp_input, 0, 0);
1684     }
1685
1686   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1687   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
1688                 "local session endpoint lookup should not work after detach");
1689   if (verbose)
1690     unformat_free (&tmp_input);
1691   vec_free (attach_args.name);
1692   return 0;
1693 }
1694
1695 static clib_error_t *
1696 session_test (vlib_main_t * vm,
1697               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1698 {
1699   int res = 0;
1700
1701   vnet_session_enable_disable (vm, 1);
1702
1703   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1704     {
1705       if (unformat (input, "basic"))
1706         res = session_test_basic (vm, input);
1707       else if (unformat (input, "namespace"))
1708         res = session_test_namespace (vm, input);
1709       else if (unformat (input, "rules-table"))
1710         res = session_test_rule_table (vm, input);
1711       else if (unformat (input, "rules"))
1712         res = session_test_rules (vm, input);
1713       else if (unformat (input, "proxy"))
1714         res = session_test_proxy (vm, input);
1715       else if (unformat (input, "endpt-cfg"))
1716         res = session_test_endpoint_cfg (vm, input);
1717       else if (unformat (input, "all"))
1718         {
1719           if ((res = session_test_basic (vm, input)))
1720             goto done;
1721           if ((res = session_test_namespace (vm, input)))
1722             goto done;
1723           if ((res = session_test_rule_table (vm, input)))
1724             goto done;
1725           if ((res = session_test_rules (vm, input)))
1726             goto done;
1727           if ((res = session_test_proxy (vm, input)))
1728             goto done;
1729           if ((res = session_test_endpoint_cfg (vm, input)))
1730             goto done;
1731         }
1732       else
1733         break;
1734     }
1735
1736 done:
1737   if (res)
1738     return clib_error_return (0, "Session unit test failed");
1739   return 0;
1740 }
1741
1742 /* *INDENT-OFF* */
1743 VLIB_CLI_COMMAND (tcp_test_command, static) =
1744 {
1745   .path = "test session",
1746   .short_help = "internal session unit tests",
1747   .function = session_test,
1748 };
1749 /* *INDENT-ON* */
1750
1751 /*
1752  * fd.io coding-style-patch-verification: ON
1753  *
1754  * Local Variables:
1755  * eval: (c-set-style "gnu")
1756  * End:
1757  */