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