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