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