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