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