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