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