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