session: segment handle in accept/connect notifications
[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
23 #define SESSION_TEST_I(_cond, _comment, _args...)               \
24 ({                                                              \
25   int _evald = (_cond);                                         \
26   if (!(_evald)) {                                              \
27     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
28             __LINE__, ##_args);                                 \
29   } else {                                                      \
30     fformat(stderr, "PASS:%d: " _comment "\n",                  \
31             __LINE__, ##_args);                                 \
32   }                                                             \
33   _evald;                                                       \
34 })
35
36 #define SESSION_TEST(_cond, _comment, _args...)                 \
37 {                                                               \
38     if (!SESSION_TEST_I(_cond, _comment, ##_args)) {            \
39         return 1;                                               \
40     }                                                           \
41 }
42
43 void
44 dummy_session_reset_callback (stream_session_t * s)
45 {
46   clib_warning ("called...");
47 }
48
49 volatile u32 connected_session_index = ~0;
50 volatile u32 connected_session_thread = ~0;
51 int
52 dummy_session_connected_callback (u32 app_index, u32 api_context,
53                                   stream_session_t * s, u8 is_fail)
54 {
55   if (s)
56     {
57       connected_session_index = s->session_index;
58       connected_session_thread = s->thread_index;
59     }
60   return 0;
61 }
62
63 static u32 dummy_segment_count;
64
65 int
66 dummy_add_segment_callback (u32 client_index, u64 segment_handle)
67 {
68   dummy_segment_count = 1;
69   return 0;
70 }
71
72 int
73 dummy_del_segment_callback (u32 client_index, u64 segment_handle)
74 {
75   dummy_segment_count = 0;
76   return 0;
77 }
78
79 void
80 dummy_session_disconnect_callback (stream_session_t * s)
81 {
82   clib_warning ("called...");
83 }
84
85 static u32 dummy_accept;
86 volatile u32 accepted_session_index;
87 volatile u32 accepted_session_thread;
88
89 int
90 dummy_session_accept_callback (stream_session_t * s)
91 {
92   dummy_accept = 1;
93   accepted_session_index = s->session_index;
94   accepted_session_thread = s->thread_index;
95   s->session_state = SESSION_STATE_READY;
96   return 0;
97 }
98
99 int
100 dummy_server_rx_callback (stream_session_t * s)
101 {
102   clib_warning ("called...");
103   return -1;
104 }
105
106 /* *INDENT-OFF* */
107 static session_cb_vft_t dummy_session_cbs = {
108   .session_reset_callback = dummy_session_reset_callback,
109   .session_connected_callback = dummy_session_connected_callback,
110   .session_accept_callback = dummy_session_accept_callback,
111   .session_disconnect_callback = dummy_session_disconnect_callback,
112   .builtin_app_rx_callback = dummy_server_rx_callback,
113   .add_segment_callback = dummy_add_segment_callback,
114   .del_segment_callback = dummy_del_segment_callback,
115 };
116 /* *INDENT-ON* */
117
118 static int
119 session_create_lookpback (u32 table_id, u32 * sw_if_index,
120                           ip4_address_t * intf_addr)
121 {
122   u8 intf_mac[6];
123
124   clib_memset (intf_mac, 0, sizeof (intf_mac));
125
126   if (vnet_create_loopback_interface (sw_if_index, intf_mac, 0, 0))
127     {
128       clib_warning ("couldn't create loopback. stopping the test!");
129       return -1;
130     }
131
132   if (table_id != 0)
133     {
134       ip_table_create (FIB_PROTOCOL_IP4, table_id, 0, 0);
135       ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id, 0);
136     }
137
138   vnet_sw_interface_set_flags (vnet_get_main (), *sw_if_index,
139                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
140
141   if (ip4_add_del_interface_address (vlib_get_main (), *sw_if_index,
142                                      intf_addr, 24, 0))
143     {
144       clib_warning ("couldn't assign loopback ip %U", format_ip4_address,
145                     intf_addr);
146       return -1;
147     }
148
149   return 0;
150 }
151
152 static void
153 session_delete_loopback (u32 sw_if_index)
154 {
155   /* fails spectacularly  */
156   /* vnet_delete_loopback_interface (sw_if_index); */
157 }
158
159 static int
160 session_test_basic (vlib_main_t * vm, unformat_input_t * input)
161 {
162   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
163   u64 options[APP_OPTIONS_N_OPTIONS], bind4_handle, bind6_handle;
164   clib_error_t *error = 0;
165   u32 server_index;
166
167   clib_memset (options, 0, sizeof (options));
168   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
169   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
170   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
171   vnet_app_attach_args_t attach_args = {
172     .api_client_index = ~0,
173     .options = options,
174     .namespace_id = 0,
175     .session_cb_vft = &dummy_session_cbs,
176     .name = format (0, "session_test"),
177   };
178
179   error = vnet_application_attach (&attach_args);
180   SESSION_TEST ((error == 0), "app attached");
181   server_index = attach_args.app_index;
182   vec_free (attach_args.name);
183
184   server_sep.is_ip4 = 1;
185   vnet_bind_args_t bind_args = {
186     .sep = server_sep,
187     .app_index = 0,
188   };
189
190   bind_args.app_index = server_index;
191   error = vnet_bind (&bind_args);
192   SESSION_TEST ((error == 0), "server bind4 should work");
193   bind4_handle = bind_args.handle;
194
195   error = vnet_bind (&bind_args);
196   SESSION_TEST ((error != 0), "double server bind4 should not work");
197
198   bind_args.sep.is_ip4 = 0;
199   error = vnet_bind (&bind_args);
200   SESSION_TEST ((error == 0), "server bind6 should work");
201   bind6_handle = bind_args.handle;
202
203   error = vnet_bind (&bind_args);
204   SESSION_TEST ((error != 0), "double server bind6 should not work");
205
206   vnet_unbind_args_t unbind_args = {
207     .handle = bind4_handle,
208     .app_index = server_index,
209   };
210   error = vnet_unbind (&unbind_args);
211   SESSION_TEST ((error == 0), "unbind4 should work");
212
213   unbind_args.handle = bind6_handle;
214   error = vnet_unbind (&unbind_args);
215   SESSION_TEST ((error == 0), "unbind6 should work");
216
217   vnet_app_detach_args_t detach_args = {
218     .app_index = server_index,
219     .api_client_index = ~0,
220   };
221   vnet_application_detach (&detach_args);
222   return 0;
223 }
224
225 static void
226 session_add_del_route_via_lookup_in_table (u32 in_table_id, u32 via_table_id,
227                                            ip4_address_t * ip, u8 mask,
228                                            u8 is_add)
229 {
230   fib_route_path_t *rpaths = 0, *rpath;
231   u32 in_fib_index, via_fib_index;
232
233   fib_prefix_t prefix = {
234     .fp_addr.ip4.as_u32 = ip->as_u32,
235     .fp_len = mask,
236     .fp_proto = FIB_PROTOCOL_IP4,
237   };
238
239   via_fib_index = fib_table_find (FIB_PROTOCOL_IP4, via_table_id);
240   if (via_fib_index == ~0)
241     {
242       clib_warning ("couldn't resolve via table id to index");
243       return;
244     }
245   in_fib_index = fib_table_find (FIB_PROTOCOL_IP4, in_table_id);
246   if (in_fib_index == ~0)
247     {
248       clib_warning ("couldn't resolve in table id to index");
249       return;
250     }
251
252   vec_add2 (rpaths, rpath, 1);
253   clib_memset (rpath, 0, sizeof (*rpath));
254   rpath->frp_weight = 1;
255   rpath->frp_fib_index = via_fib_index;
256   rpath->frp_proto = DPO_PROTO_IP4;
257   rpath->frp_sw_if_index = ~0;
258   rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
259
260   if (is_add)
261     fib_table_entry_path_add2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
262                                FIB_ENTRY_FLAG_NONE, rpath);
263   else
264     fib_table_entry_path_remove2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
265                                   rpath);
266   vec_free (rpaths);
267 }
268
269 static int
270 session_test_endpoint_cfg (vlib_main_t * vm, unformat_input_t * input)
271 {
272   session_endpoint_cfg_t client_sep = SESSION_ENDPOINT_CFG_NULL;
273   u32 server_index, client_index, sw_if_index[2], tries = 0;
274   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
275   u16 dummy_server_port = 1234, dummy_client_port = 5678;
276   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
277   ip4_address_t intf_addr[3];
278   transport_connection_t *tc;
279   stream_session_t *s;
280   clib_error_t *error;
281   u8 *appns_id;
282
283   /*
284    * Create the loopbacks
285    */
286   intf_addr[0].as_u32 = clib_host_to_net_u32 (0x01010101),
287     session_create_lookpback (0, &sw_if_index[0], &intf_addr[0]);
288
289   intf_addr[1].as_u32 = clib_host_to_net_u32 (0x02020202),
290     session_create_lookpback (1, &sw_if_index[1], &intf_addr[1]);
291
292   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
293                                              1 /* is_add */ );
294   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
295                                              1 /* is_add */ );
296
297   /*
298    * Insert namespace
299    */
300   appns_id = format (0, "appns1");
301   vnet_app_namespace_add_del_args_t ns_args = {
302     .ns_id = appns_id,
303     .secret = dummy_secret,
304     .sw_if_index = sw_if_index[1],
305     .ip4_fib_id = 0,
306     .is_add = 1
307   };
308   error = vnet_app_namespace_add_del (&ns_args);
309   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
310                 clib_error_get_code (error));
311
312   /*
313    * Attach client/server
314    */
315   clib_memset (options, 0, sizeof (options));
316   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
317   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
318
319   vnet_app_attach_args_t attach_args = {
320     .api_client_index = ~0,
321     .options = options,
322     .namespace_id = 0,
323     .session_cb_vft = &dummy_session_cbs,
324     .name = format (0, "session_test_client"),
325   };
326
327   error = vnet_application_attach (&attach_args);
328   SESSION_TEST ((error == 0), "client app attached");
329   client_index = attach_args.app_index;
330   vec_free (attach_args.name);
331
332   attach_args.name = format (0, "session_test_server");
333   attach_args.namespace_id = appns_id;
334   attach_args.options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
335   error = vnet_application_attach (&attach_args);
336   SESSION_TEST ((error == 0), "server app attached: %U", format_clib_error,
337                 error);
338   vec_free (attach_args.name);
339   server_index = attach_args.app_index;
340
341   server_sep.is_ip4 = 1;
342   server_sep.port = dummy_server_port;
343   vnet_bind_args_t bind_args = {
344     .sep = server_sep,
345     .app_index = server_index,
346   };
347   error = vnet_bind (&bind_args);
348   SESSION_TEST ((error == 0), "server bind should work");
349
350   /*
351    * Connect and force lcl ip
352    */
353   client_sep.is_ip4 = 1;
354   client_sep.ip.ip4.as_u32 = clib_host_to_net_u32 (0x02020202);
355   client_sep.port = dummy_server_port;
356   client_sep.peer.is_ip4 = 1;
357   client_sep.peer.ip.ip4.as_u32 = clib_host_to_net_u32 (0x01010101);
358   client_sep.peer.port = dummy_client_port;
359   client_sep.transport_proto = TRANSPORT_PROTO_TCP;
360
361   vnet_connect_args_t connect_args = {
362     .sep_ext = client_sep,
363     .app_index = client_index,
364   };
365
366   connected_session_index = connected_session_thread = ~0;
367   accepted_session_index = accepted_session_thread = ~0;
368   error = vnet_connect (&connect_args);
369   SESSION_TEST ((error == 0), "connect should work");
370
371   /* wait for stuff to happen */
372   while ((connected_session_index == ~0
373           || vec_len (tcp_main.wrk_ctx[0].pending_acks)) && ++tries < 100)
374     vlib_process_suspend (vm, 100e-3);
375   clib_warning ("waited %.1f seconds for connections", tries / 10.0);
376   SESSION_TEST ((connected_session_index != ~0), "session should exist");
377   SESSION_TEST ((connected_session_thread != ~0), "thread should exist");
378   SESSION_TEST ((accepted_session_index != ~0), "session should exist");
379   SESSION_TEST ((accepted_session_thread != ~0), "thread should exist");
380   s = session_get (connected_session_index, connected_session_thread);
381   tc = session_get_transport (s);
382   SESSION_TEST ((tc != 0), "transport should exist");
383   SESSION_TEST ((memcmp (&tc->lcl_ip, &client_sep.peer.ip,
384                          sizeof (tc->lcl_ip)) == 0), "ips should be equal");
385   SESSION_TEST ((tc->lcl_port == dummy_client_port), "ports should be equal");
386
387   /* These sessions, because of the way they're established are pinned to
388    * main thread, even when we have workers and we avoid polling main thread,
389    * i.e., we can't cleanup pending disconnects, so force cleanup for both
390    */
391   stream_session_cleanup (s);
392   s = session_get (accepted_session_index, accepted_session_thread);
393   stream_session_cleanup (s);
394
395   vnet_app_detach_args_t detach_args = {
396     .app_index = server_index,
397     .api_client_index = ~0,
398   };
399   vnet_application_detach (&detach_args);
400   detach_args.app_index = client_index;
401   vnet_application_detach (&detach_args);
402
403   /* Allow the disconnects to finish before removing the routes. */
404   vlib_process_suspend (vm, 10e-3);
405
406   session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
407                                              0 /* is_add */ );
408   session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
409                                              0 /* is_add */ );
410
411   session_delete_loopback (sw_if_index[0]);
412   session_delete_loopback (sw_if_index[1]);
413   return 0;
414 }
415
416 static int
417 session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
418 {
419   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
420   u32 server_index, server_st_index, server_local_st_index;
421   u32 dummy_port = 1234, client_index, server_wrk_index;
422   u32 dummy_api_context = 4321, dummy_client_api_index = ~0;
423   u32 dummy_server_api_index = ~0, sw_if_index = 0;
424   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
425   session_endpoint_t client_sep = SESSION_ENDPOINT_NULL;
426   session_endpoint_t intf_sep = SESSION_ENDPOINT_NULL;
427   clib_error_t *error = 0;
428   u8 *ns_id = format (0, "appns1");
429   app_namespace_t *app_ns;
430   application_t *server;
431   stream_session_t *s;
432   u64 handle;
433   int code;
434
435   server_sep.is_ip4 = 1;
436   server_sep.port = dummy_port;
437   client_sep.is_ip4 = 1;
438   client_sep.port = dummy_port;
439   clib_memset (options, 0, sizeof (options));
440
441   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
442   vnet_app_attach_args_t attach_args = {
443     .api_client_index = ~0,
444     .options = options,
445     .namespace_id = 0,
446     .session_cb_vft = &dummy_session_cbs,
447     .name = format (0, "session_test"),
448   };
449
450   vnet_bind_args_t bind_args = {
451     .sep = server_sep,
452     .app_index = 0,
453   };
454
455   vnet_connect_args_t connect_args = {
456     .app_index = 0,
457     .api_context = 0,
458   };
459   clib_memcpy (&connect_args.sep, &client_sep, sizeof (client_sep));
460
461   vnet_unbind_args_t unbind_args = {
462     .handle = bind_args.handle,
463     .app_index = 0,
464   };
465
466   vnet_app_detach_args_t detach_args = {
467     .app_index = 0,
468     .api_client_index = ~0,
469   };
470
471   ip4_address_t intf_addr = {
472     .as_u32 = clib_host_to_net_u32 (0x07000105),
473   };
474
475   intf_sep.ip.ip4 = intf_addr;
476   intf_sep.is_ip4 = 1;
477   intf_sep.port = dummy_port;
478
479   /*
480    * Insert namespace and lookup
481    */
482
483   vnet_app_namespace_add_del_args_t ns_args = {
484     .ns_id = ns_id,
485     .secret = dummy_secret,
486     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
487     .is_add = 1
488   };
489   error = vnet_app_namespace_add_del (&ns_args);
490   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
491                 clib_error_get_code (error));
492
493   app_ns = app_namespace_get_from_id (ns_id);
494   SESSION_TEST ((app_ns != 0), "should find ns %v status", ns_id);
495   SESSION_TEST ((app_ns->ns_secret == dummy_secret), "secret should be %d",
496                 dummy_secret);
497   SESSION_TEST ((app_ns->sw_if_index == APP_NAMESPACE_INVALID_INDEX),
498                 "sw_if_index should be invalid");
499
500   /*
501    * Try application attach with wrong secret
502    */
503
504   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
505   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
506   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret - 1;
507   attach_args.namespace_id = ns_id;
508   attach_args.api_client_index = dummy_server_api_index;
509
510   error = vnet_application_attach (&attach_args);
511   SESSION_TEST ((error != 0), "app attachment should fail");
512   code = clib_error_get_code (error);
513   SESSION_TEST ((code == VNET_API_ERROR_APP_WRONG_NS_SECRET),
514                 "code should be wrong ns secret: %d", code);
515
516   /*
517    * Attach server with global default scope
518    */
519   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
520   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
521   options[APP_OPTIONS_NAMESPACE_SECRET] = 0;
522   attach_args.namespace_id = 0;
523   attach_args.api_client_index = dummy_server_api_index;
524   error = vnet_application_attach (&attach_args);
525   SESSION_TEST ((error == 0), "server attachment should work");
526   server_index = attach_args.app_index;
527   server = application_get (server_index);
528   server_wrk_index = application_get_default_worker (server)->wrk_index;
529   SESSION_TEST ((server->ns_index == 0),
530                 "server should be in the default ns");
531
532   bind_args.app_index = server_index;
533   error = vnet_bind (&bind_args);
534   SESSION_TEST ((error == 0), "server bind should work");
535
536   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
537   s = session_lookup_listener (server_st_index, &server_sep);
538   SESSION_TEST ((s != 0), "listener should exist in global table");
539   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
540                 " that of the server");
541   server_local_st_index = application_local_session_table (server);
542   SESSION_TEST ((server_local_st_index == APP_INVALID_INDEX),
543                 "server shouldn't have access to local table");
544
545   unbind_args.app_index = server_index;
546   unbind_args.handle = bind_args.handle;
547   error = vnet_unbind (&unbind_args);
548   SESSION_TEST ((error == 0), "unbind should work");
549
550   s = session_lookup_listener (server_st_index, &server_sep);
551   SESSION_TEST ((s == 0), "listener should not exist in global table");
552
553   detach_args.app_index = server_index;
554   vnet_application_detach (&detach_args);
555
556   /*
557    * Attach server with local and global scope
558    */
559   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
560   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
561   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
562   attach_args.namespace_id = ns_id;
563   attach_args.api_client_index = dummy_server_api_index;
564   error = vnet_application_attach (&attach_args);
565   SESSION_TEST ((error == 0), "server attachment should work");
566   server_index = attach_args.app_index;
567   server = application_get (server_index);
568   server_wrk_index = application_get_default_worker (server)->wrk_index;
569   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
570                 "server should be in the right ns");
571
572   bind_args.app_index = server_index;
573   error = vnet_bind (&bind_args);
574   SESSION_TEST ((error == 0), "bind should work");
575   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
576   s = session_lookup_listener (server_st_index, &server_sep);
577   SESSION_TEST ((s != 0), "listener should exist in global table");
578   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be"
579                 " that of the server");
580   server_local_st_index = application_local_session_table (server);
581   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
582   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
583                 "listener should exist in local table");
584
585   /*
586    * Try client connect with 1) local scope 2) global scope
587    */
588   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
589   attach_args.api_client_index = dummy_client_api_index;
590   error = vnet_application_attach (&attach_args);
591   SESSION_TEST ((error == 0), "client attachment should work");
592   client_index = attach_args.app_index;
593   connect_args.api_context = dummy_api_context;
594   connect_args.app_index = client_index;
595   error = vnet_connect (&connect_args);
596   SESSION_TEST ((error != 0), "client connect should return error code");
597   code = clib_error_get_code (error);
598   SESSION_TEST ((code == VNET_API_ERROR_INVALID_VALUE),
599                 "error code should be invalid value (zero ip)");
600   SESSION_TEST ((dummy_segment_count == 0),
601                 "shouldn't have received request to map new segment");
602   connect_args.sep.ip.ip4.as_u8[0] = 127;
603   error = vnet_connect (&connect_args);
604   SESSION_TEST ((error == 0), "client connect should not return error code");
605   code = clib_error_get_code (error);
606   SESSION_TEST ((dummy_segment_count == 1),
607                 "should've received request to map new segment");
608   SESSION_TEST ((dummy_accept == 1), "should've received accept request");
609   detach_args.app_index = client_index;
610   vnet_application_detach (&detach_args);
611
612   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
613   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
614   attach_args.api_client_index = dummy_client_api_index;
615   error = vnet_application_attach (&attach_args);
616   SESSION_TEST ((error == 0), "client attachment should work");
617   error = vnet_connect (&connect_args);
618   SESSION_TEST ((error != 0), "client connect should return error code");
619   code = clib_error_get_code (error);
620   SESSION_TEST ((code == 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_unbind (&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_bind (&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_unbind (&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   code = clib_error_get_code (error);
683   SESSION_TEST ((code == VNET_API_ERROR_SESSION_CONNECT),
684                 "error code should be connect (not in same ns)");
685   detach_args.app_index = client_index;
686   vnet_application_detach (&detach_args);
687
688   /*
689    * Detach server
690    */
691   detach_args.app_index = server_index;
692   vnet_application_detach (&detach_args);
693
694   /*
695    * Create loopback interface
696    */
697   session_create_lookpback (0, &sw_if_index, &intf_addr);
698
699   /*
700    * Update namespace
701    */
702   ns_args.sw_if_index = sw_if_index;
703   error = vnet_app_namespace_add_del (&ns_args);
704   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
705                 clib_error_get_code (error));
706
707   /*
708    * Attach server with local and global scope
709    */
710   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
711   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
712   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
713   attach_args.namespace_id = ns_id;
714   attach_args.api_client_index = dummy_server_api_index;
715   error = vnet_application_attach (&attach_args);
716   SESSION_TEST ((error == 0), "server attachment should work");
717   server_index = attach_args.app_index;
718   server = application_get (server_index);
719   server_wrk_index = application_get_default_worker (server)->wrk_index;
720
721   bind_args.app_index = server_index;
722   error = vnet_bind (&bind_args);
723   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
724   s = session_lookup_listener (server_st_index, &server_sep);
725   SESSION_TEST ((s == 0), "zero listener should not exist in global table");
726
727   s = session_lookup_listener (server_st_index, &intf_sep);
728   SESSION_TEST ((s != 0), "intf listener should exist in global table");
729   SESSION_TEST ((s->app_wrk_index == server_wrk_index), "app_index should be "
730                 "that of the server");
731   server_local_st_index = application_local_session_table (server);
732   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
733   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
734                 "zero listener should exist in local table");
735   detach_args.app_index = server_index;
736   vnet_application_detach (&detach_args);
737
738   /*
739    * Cleanup
740    */
741   vec_free (attach_args.name);
742   vec_free (ns_id);
743   session_delete_loopback (sw_if_index);
744   return 0;
745 }
746
747 static int
748 session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
749 {
750   session_rules_table_t _srt, *srt = &_srt;
751   u16 lcl_port = 1234, rmt_port = 4321;
752   u32 action_index = 1, res;
753   ip4_address_t lcl_lkup, rmt_lkup;
754   clib_error_t *error;
755   int verbose = 0;
756
757   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
758     {
759       if (unformat (input, "verbose"))
760         verbose = 1;
761       else
762         {
763           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
764                            input);
765           return -1;
766         }
767     }
768
769   clib_memset (srt, 0, sizeof (*srt));
770   session_rules_table_init (srt);
771
772   ip4_address_t lcl_ip = {
773     .as_u32 = clib_host_to_net_u32 (0x01020304),
774   };
775   ip4_address_t rmt_ip = {
776     .as_u32 = clib_host_to_net_u32 (0x05060708),
777   };
778   ip4_address_t lcl_ip2 = {
779     .as_u32 = clib_host_to_net_u32 (0x02020202),
780   };
781   ip4_address_t rmt_ip2 = {
782     .as_u32 = clib_host_to_net_u32 (0x06060606),
783   };
784   ip4_address_t lcl_ip3 = {
785     .as_u32 = clib_host_to_net_u32 (0x03030303),
786   };
787   ip4_address_t rmt_ip3 = {
788     .as_u32 = clib_host_to_net_u32 (0x07070707),
789   };
790   fib_prefix_t lcl_pref = {
791     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
792     .fp_len = 16,
793     .fp_proto = FIB_PROTOCOL_IP4,
794   };
795   fib_prefix_t rmt_pref = {
796     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
797     .fp_len = 16,
798     .fp_proto = FIB_PROTOCOL_IP4,
799   };
800
801   session_rule_table_add_del_args_t args = {
802     .lcl = lcl_pref,
803     .rmt = rmt_pref,
804     .lcl_port = lcl_port,
805     .rmt_port = rmt_port,
806     .action_index = action_index++,
807     .is_add = 1,
808   };
809   error = session_rules_table_add_del (srt, &args);
810   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
811                 action_index - 1);
812
813   res =
814     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
815   SESSION_TEST ((res == 1),
816                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
817                 res);
818
819   /*
820    * 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
821    */
822   args.lcl.fp_addr.ip4 = lcl_ip;
823   args.lcl.fp_len = 24;
824   args.action_index = action_index++;
825   error = session_rules_table_add_del (srt, &args);
826   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
827                 action_index - 1);
828   args.rmt.fp_addr.ip4 = rmt_ip;
829   args.rmt.fp_len = 24;
830   args.action_index = action_index++;
831   error = session_rules_table_add_del (srt, &args);
832   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
833                 action_index - 1);
834
835   /*
836    * 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
837    */
838   args.lcl.fp_addr.ip4 = lcl_ip2;
839   args.lcl.fp_len = 24;
840   args.rmt.fp_addr.ip4 = rmt_ip2;
841   args.rmt.fp_len = 16;
842   args.action_index = action_index++;
843   error = session_rules_table_add_del (srt, &args);
844   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
845                 action_index - 1);
846   args.lcl.fp_addr.ip4 = lcl_ip3;
847   args.rmt.fp_addr.ip4 = rmt_ip3;
848   args.action_index = action_index++;
849   error = session_rules_table_add_del (srt, &args);
850   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
851                 action_index - 1);
852
853   /*
854    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
855    */
856   args.lcl.fp_addr.ip4 = lcl_ip3;
857   args.rmt.fp_addr.ip4 = rmt_ip3;
858   args.action_index = action_index++;
859   error = session_rules_table_add_del (srt, &args);
860   SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
861                 "action %d", action_index - 1);
862
863   /*
864    * 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
865    * and  3.3.3.3 1234 7.7.7.7 4321
866    */
867   res =
868     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
869   SESSION_TEST ((res == 3),
870                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
871                 res);
872
873   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
874   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
875   res =
876     session_rules_table_lookup4 (srt, &lcl_lkup,
877                                  &rmt_lkup, lcl_port, rmt_port);
878   SESSION_TEST ((res == 1),
879                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
880                 res);
881
882   res =
883     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
884   SESSION_TEST ((res == 6),
885                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
886                 "should be 6 (updated): %d", res);
887
888   /*
889    * Add 1.2.3.4/24 * 5.6.7.8/24 *
890    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
891    */
892   args.lcl.fp_addr.ip4 = lcl_ip;
893   args.rmt.fp_addr.ip4 = rmt_ip;
894   args.lcl.fp_len = 24;
895   args.rmt.fp_len = 24;
896   args.lcl_port = 0;
897   args.rmt_port = 0;
898   args.action_index = action_index++;
899   error = session_rules_table_add_del (srt, &args);
900   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
901                 action_index - 1);
902   res =
903     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
904   SESSION_TEST ((res == 7),
905                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
906                 " be 7 (lpm dst): %d", res);
907   res =
908     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
909                                  lcl_port + 1, rmt_port);
910   SESSION_TEST ((res == 7),
911                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
912                 res);
913
914   /*
915    * Del 1.2.3.4/24 * 5.6.7.8/24 *
916    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
917    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
918    * 1.2.3.4 1235 5.6.7.8 4322
919    */
920   args.is_add = 0;
921   error = session_rules_table_add_del (srt, &args);
922   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
923
924   args.lcl.fp_addr.ip4 = lcl_ip;
925   args.rmt.fp_addr.ip4 = rmt_ip;
926   args.lcl.fp_len = 16;
927   args.rmt.fp_len = 16;
928   args.lcl_port = 0;
929   args.rmt_port = 0;
930   args.action_index = action_index++;
931   args.is_add = 1;
932   error = session_rules_table_add_del (srt, &args);
933   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
934                 action_index - 1);
935
936   args.lcl.fp_addr.ip4 = lcl_ip;
937   args.rmt.fp_addr.ip4 = rmt_ip;
938   args.lcl.fp_len = 24;
939   args.rmt.fp_len = 24;
940   args.lcl_port = lcl_port + 1;
941   args.rmt_port = rmt_port;
942   args.action_index = action_index++;
943   args.is_add = 1;
944   error = session_rules_table_add_del (srt, &args);
945   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
946                 action_index - 1);
947
948   if (verbose)
949     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
950
951   res =
952     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
953   SESSION_TEST ((res == 3),
954                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
955                 res);
956   res =
957     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
958                                  lcl_port + 1, rmt_port);
959   SESSION_TEST ((res == 9),
960                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
961                 res);
962   res =
963     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
964                                  lcl_port + 1, rmt_port + 1);
965   SESSION_TEST ((res == 8),
966                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
967                 res);
968
969   /*
970    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
971    * Lookup 1.2.3.4 1234 5.6.7.8 4321
972    */
973   args.lcl_port = 1234;
974   args.rmt_port = 4321;
975   args.lcl.fp_len = 16;
976   args.rmt.fp_len = 16;
977   args.is_add = 0;
978   error = session_rules_table_add_del (srt, &args);
979   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
980   res =
981     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
982   SESSION_TEST ((res == 3),
983                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
984                 res);
985
986   args.lcl_port = 0;
987   args.rmt_port = 0;
988   args.is_add = 0;
989   error = session_rules_table_add_del (srt, &args);
990   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
991   res =
992     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
993   SESSION_TEST ((res == 3),
994                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
995                 res);
996
997   /*
998    * Delete 1.2.3.4/24 1234 5.6.7.5/24
999    */
1000   args.lcl.fp_addr.ip4 = lcl_ip;
1001   args.rmt.fp_addr.ip4 = rmt_ip;
1002   args.lcl.fp_len = 24;
1003   args.rmt.fp_len = 24;
1004   args.lcl_port = 1234;
1005   args.rmt_port = 4321;
1006   args.is_add = 0;
1007   error = session_rules_table_add_del (srt, &args);
1008   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
1009   res =
1010     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
1011   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
1012
1013   return 0;
1014 }
1015
1016 static int
1017 session_test_rules (vlib_main_t * vm, unformat_input_t * input)
1018 {
1019   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
1020   u64 options[APP_OPTIONS_N_OPTIONS];
1021   u16 lcl_port = 1234, rmt_port = 4321;
1022   u32 server_index, server_index2;
1023   u32 dummy_server_api_index = ~0;
1024   transport_connection_t *tc;
1025   u32 dummy_port = 1111;
1026   clib_error_t *error = 0;
1027   u8 is_filtered = 0, *ns_id = format (0, "appns1");
1028   stream_session_t *listener, *s;
1029   app_namespace_t *default_ns = app_namespace_get_default ();
1030   u32 local_ns_index = default_ns->local_table_index;
1031   int verbose = 0, rv;
1032   app_namespace_t *app_ns;
1033   u64 handle;
1034
1035   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1036     {
1037       if (unformat (input, "verbose"))
1038         verbose = 1;
1039       else
1040         {
1041           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1042                            input);
1043           return -1;
1044         }
1045     }
1046
1047   server_sep.is_ip4 = 1;
1048   server_sep.port = dummy_port;
1049   clib_memset (options, 0, sizeof (options));
1050
1051   vnet_app_attach_args_t attach_args = {
1052     .api_client_index = ~0,
1053     .options = options,
1054     .namespace_id = 0,
1055     .session_cb_vft = &dummy_session_cbs,
1056     .name = format (0, "session_test"),
1057   };
1058
1059   vnet_bind_args_t bind_args = {
1060     .sep = server_sep,
1061     .app_index = 0,
1062   };
1063
1064   /*
1065    * Attach server with global and local default scope
1066    */
1067   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1068   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1069   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1070   attach_args.namespace_id = 0;
1071   attach_args.api_client_index = dummy_server_api_index;
1072   error = vnet_application_attach (&attach_args);
1073   SESSION_TEST ((error == 0), "server attached");
1074   server_index = attach_args.app_index;
1075
1076   bind_args.app_index = server_index;
1077   error = vnet_bind (&bind_args);
1078   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
1079                 &server_sep.ip, 1, server_sep.port);
1080   listener = listen_session_get_from_handle (bind_args.handle);
1081   ip4_address_t lcl_ip = {
1082     .as_u32 = clib_host_to_net_u32 (0x01020304),
1083   };
1084   ip4_address_t rmt_ip = {
1085     .as_u32 = clib_host_to_net_u32 (0x05060708),
1086   };
1087   fib_prefix_t lcl_pref = {
1088     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
1089     .fp_len = 16,
1090     .fp_proto = FIB_PROTOCOL_IP4,
1091   };
1092   fib_prefix_t rmt_pref = {
1093     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1094     .fp_len = 16,
1095     .fp_proto = FIB_PROTOCOL_IP4,
1096   };
1097
1098   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1099                                       &rmt_pref.fp_addr.ip4, lcl_port,
1100                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1101                                       &is_filtered);
1102   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
1103
1104   /*
1105    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
1106    */
1107   session_rule_add_del_args_t args = {
1108     .table_args.lcl = lcl_pref,
1109     .table_args.rmt = rmt_pref,
1110     .table_args.lcl_port = lcl_port,
1111     .table_args.rmt_port = rmt_port,
1112     .table_args.action_index = server_index,
1113     .table_args.is_add = 1,
1114     .appns_index = 0,
1115   };
1116   error = vnet_session_rule_add_del (&args);
1117   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
1118                 args.table_args.action_index);
1119
1120   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
1121                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
1122                                    TRANSPORT_PROTO_TCP);
1123   SESSION_TEST ((tc->c_index == listener->connection_index),
1124                 "optimized lookup should return the listener");
1125   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1126                                       &rmt_pref.fp_addr.ip4, lcl_port,
1127                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1128                                       &is_filtered);
1129   SESSION_TEST ((tc->c_index == listener->connection_index),
1130                 "lookup should return the listener");
1131   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
1132                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
1133   SESSION_TEST ((s->connection_index == listener->connection_index),
1134                 "safe lookup should return the listener");
1135   session_endpoint_t sep = {
1136     .ip = rmt_pref.fp_addr,
1137     .is_ip4 = 1,
1138     .port = rmt_port,
1139     .transport_proto = TRANSPORT_PROTO_TCP,
1140   };
1141   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1142   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1143                 "should not work (global scope)");
1144
1145   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1146                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1147                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1148                                       &is_filtered);
1149   SESSION_TEST ((tc == 0),
1150                 "optimized lookup for wrong lcl port + 1 should not work");
1151
1152   /*
1153    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
1154    */
1155   args.table_args.lcl_port = 0;
1156   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
1157   error = vnet_session_rule_add_del (&args);
1158   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
1159                 args.table_args.action_index);
1160   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1161                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1162                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1163                                       &is_filtered);
1164   SESSION_TEST ((tc->c_index == listener->connection_index),
1165                 "optimized lookup for lcl port + 1 should work");
1166   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1167   SESSION_TEST ((handle == server_index), "local session endpoint lookup "
1168                 "should work (lcl ip was zeroed)");
1169
1170   /*
1171    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1172    */
1173   args.table_args.lcl_port = 1234;
1174   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1175   args.table_args.lcl.fp_len = 30;
1176   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1177   args.table_args.rmt.fp_len = 30;
1178   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1179   error = vnet_session_rule_add_del (&args);
1180   SESSION_TEST ((error == 0), "Add 1.2.3.4/30 1234 5.6.7.8/30 4321 action %d",
1181                 args.table_args.action_index);
1182
1183   if (verbose)
1184     {
1185       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1186                                        TRANSPORT_PROTO_TCP);
1187       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1188                                              TRANSPORT_PROTO_TCP);
1189     }
1190
1191   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1192                                       &rmt_pref.fp_addr.ip4, lcl_port,
1193                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1194                                       &is_filtered);
1195   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
1196                 "should fail (deny rule)");
1197   SESSION_TEST ((is_filtered == 1), "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   rv = clib_error_get_code (error);
1260   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1261                 "connect should be filtered");
1262
1263   sep.ip.ip4.as_u32 -= 1 << 24;
1264
1265   /*
1266    * Delete masking rule: 1.2.3.4/32 1234 5.6.7.8/32 4321 allow
1267    */
1268   args.table_args.is_add = 0;
1269   args.table_args.lcl_port = 1234;
1270   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1271   args.table_args.lcl.fp_len = 32;
1272   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1273   args.table_args.rmt.fp_len = 32;
1274   error = vnet_session_rule_add_del (&args);
1275   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 allow");
1276
1277
1278   /*
1279    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
1280    */
1281   args.table_args.is_add = 1;
1282   args.table_args.lcl_port = 0;
1283   args.table_args.lcl.fp_len = 0;
1284   args.table_args.rmt.fp_len = 16;
1285   args.table_args.action_index = -1;
1286   error = vnet_session_rule_add_del (&args);
1287   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
1288                 args.table_args.action_index);
1289
1290   if (verbose)
1291     {
1292       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1293                                        TRANSPORT_PROTO_TCP);
1294       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1295                                              TRANSPORT_PROTO_TCP);
1296     }
1297
1298   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1299   SESSION_TEST ((handle == SESSION_DROP_HANDLE),
1300                 "local session endpoint lookup should return deny");
1301
1302   /*
1303    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
1304    */
1305   args.table_args.is_add = 0;
1306   args.table_args.lcl_port = 1234;
1307   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1308   args.table_args.lcl.fp_len = 30;
1309   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1310   args.table_args.rmt.fp_len = 30;
1311   error = vnet_session_rule_add_del (&args);
1312   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1313
1314   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1315   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1316                 "local session endpoint lookup should return invalid");
1317
1318   /*
1319    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
1320    * 1.2.3.4/16 1234 5.6.7.8/16 4321
1321    */
1322   args.table_args.is_add = 0;
1323   args.table_args.lcl_port = 0;
1324   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1325   args.table_args.lcl.fp_len = 0;
1326   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1327   args.table_args.rmt.fp_len = 16;
1328   args.table_args.rmt_port = 4321;
1329   error = vnet_session_rule_add_del (&args);
1330   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
1331   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1332   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1333                 "should not work (removed)");
1334
1335   args.table_args.is_add = 0;
1336   args.table_args.lcl = lcl_pref;
1337
1338   args.table_args.is_add = 0;
1339   args.table_args.lcl_port = 0;
1340   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1341   args.table_args.lcl.fp_len = 16;
1342   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1343   args.table_args.rmt.fp_len = 16;
1344   args.table_args.rmt_port = 4321;
1345   error = vnet_session_rule_add_del (&args);
1346   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
1347   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1348                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1349                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1350                                       &is_filtered);
1351   SESSION_TEST ((tc == 0),
1352                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
1353                 "work (del)");
1354
1355   args.table_args.is_add = 0;
1356   args.table_args.lcl_port = 1234;
1357   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1358   args.table_args.lcl.fp_len = 16;
1359   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1360   args.table_args.rmt.fp_len = 16;
1361   args.table_args.rmt_port = 4321;
1362   error = vnet_session_rule_add_del (&args);
1363   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
1364   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1365                                       &rmt_pref.fp_addr.ip4, lcl_port,
1366                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1367                                       &is_filtered);
1368   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
1369                 "not work (del + deny)");
1370
1371   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1372   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1373                                       &rmt_pref.fp_addr.ip4, lcl_port,
1374                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1375                                       &is_filtered);
1376   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
1377                 " not work (no-rule)");
1378
1379   /*
1380    * Test tags. Add/overwrite/del rule with tag
1381    */
1382   args.table_args.is_add = 1;
1383   args.table_args.lcl_port = 1234;
1384   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1385   args.table_args.lcl.fp_len = 16;
1386   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1387   args.table_args.rmt.fp_len = 16;
1388   args.table_args.rmt_port = 4321;
1389   args.table_args.tag = format (0, "test_rule");
1390   args.table_args.action_index = server_index;
1391   error = vnet_session_rule_add_del (&args);
1392   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
1393                 "tag test_rule");
1394   if (verbose)
1395     {
1396       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1397                                        TRANSPORT_PROTO_TCP);
1398       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1399                                              TRANSPORT_PROTO_TCP);
1400     }
1401   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1402                                       &rmt_pref.fp_addr.ip4, lcl_port,
1403                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1404                                       &is_filtered);
1405   SESSION_TEST ((tc->c_index == listener->connection_index),
1406                 "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
1407
1408   vec_free (args.table_args.tag);
1409   args.table_args.lcl_port = 1234;
1410   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1411   args.table_args.lcl.fp_len = 16;
1412   args.table_args.tag = format (0, "test_rule_overwrite");
1413   error = vnet_session_rule_add_del (&args);
1414   SESSION_TEST ((error == 0),
1415                 "Overwrite 1.2.3.4/16 1234 5.6.7.8/16 4321 deny tag test_rule"
1416                 " should work");
1417   if (verbose)
1418     {
1419       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1420                                        TRANSPORT_PROTO_TCP);
1421       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1422                                              TRANSPORT_PROTO_TCP);
1423     }
1424
1425   args.table_args.is_add = 0;
1426   args.table_args.lcl_port += 1;
1427   error = vnet_session_rule_add_del (&args);
1428   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
1429                 "tag %v", args.table_args.tag);
1430   if (verbose)
1431     {
1432       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1433                                        TRANSPORT_PROTO_TCP);
1434       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1435                                              TRANSPORT_PROTO_TCP);
1436     }
1437   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1438                                       &rmt_pref.fp_addr.ip4, lcl_port,
1439                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1440                                       &is_filtered);
1441   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/32 4321 should not"
1442                 " work (del)");
1443
1444
1445   /*
1446    * Test local rules with multiple namespaces
1447    */
1448
1449   /*
1450    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1451    */
1452   args.table_args.is_add = 1;
1453   args.table_args.lcl_port = 1234;
1454   args.table_args.rmt_port = 0;
1455   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1456   args.table_args.lcl.fp_len = 32;
1457   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1458   args.table_args.rmt.fp_len = 32;
1459   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1460   args.table_args.tag = 0;
1461   args.scope = SESSION_RULE_SCOPE_LOCAL;
1462   error = vnet_session_rule_add_del (&args);
1463   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
1464                 args.table_args.action_index);
1465   /*
1466    * Add 'white' rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1467    */
1468   args.table_args.is_add = 1;
1469   args.table_args.lcl_port = 1234;
1470   args.table_args.rmt_port = 4321;
1471   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1472   args.table_args.lcl.fp_len = 32;
1473   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1474   args.table_args.rmt.fp_len = 32;
1475   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
1476   error = vnet_session_rule_add_del (&args);
1477
1478   if (verbose)
1479     {
1480       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1481                                              TRANSPORT_PROTO_TCP);
1482     }
1483
1484   vnet_app_namespace_add_del_args_t ns_args = {
1485     .ns_id = ns_id,
1486     .secret = 0,
1487     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
1488     .is_add = 1
1489   };
1490   error = vnet_app_namespace_add_del (&ns_args);
1491   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
1492                 clib_error_get_code (error));
1493   app_ns = app_namespace_get_from_id (ns_id);
1494
1495   attach_args.namespace_id = ns_id;
1496   attach_args.api_client_index = dummy_server_api_index;
1497   error = vnet_application_attach (&attach_args);
1498   SESSION_TEST ((error == 0), "server2 attached");
1499   server_index2 = attach_args.app_index;
1500
1501   /*
1502    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1503    */
1504   args.table_args.lcl_port = 1234;
1505   args.table_args.rmt_port = 0;
1506   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1507   args.table_args.lcl.fp_len = 32;
1508   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1509   args.table_args.rmt.fp_len = 32;
1510   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1511   args.appns_index = app_namespace_index (app_ns);
1512
1513   error = vnet_session_rule_add_del (&args);
1514   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d "
1515                 "in test namespace", args.table_args.action_index);
1516   /*
1517    * Lookup default namespace
1518    */
1519   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1520   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1521                 "lookup for 1.2.3.4/32 1234 5.6.7.8/32 4321 in local table "
1522                 "should return allow (invalid)");
1523
1524   sep.port += 1;
1525   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1526   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1527                 "5.6.7.8/16 432*2* in local table should return deny");
1528
1529
1530   connect_args.app_index = server_index;
1531   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
1532
1533   error = vnet_connect (&connect_args);
1534   SESSION_TEST ((error != 0), "connect should fail");
1535   rv = clib_error_get_code (error);
1536   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1537                 "connect should be filtered");
1538
1539   /*
1540    * Lookup test namespace
1541    */
1542   handle = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1543   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1544                 "5.6.7.8/16 4321 in local table should return deny");
1545
1546   connect_args.app_index = server_index;
1547   error = vnet_connect (&connect_args);
1548   SESSION_TEST ((error != 0), "connect should fail");
1549   rv = clib_error_get_code (error);
1550   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1551                 "connect should be filtered");
1552
1553   args.table_args.is_add = 0;
1554   vnet_session_rule_add_del (&args);
1555
1556   args.appns_index = 0;
1557   args.table_args.is_add = 0;
1558   vnet_session_rule_add_del (&args);
1559
1560   args.table_args.rmt_port = 4321;
1561   vnet_session_rule_add_del (&args);
1562   /*
1563    * Final Cleanup
1564    */
1565   vec_free (args.table_args.tag);
1566   vnet_app_detach_args_t detach_args = {
1567     .app_index = server_index,
1568     .api_client_index = ~0,
1569   };
1570   vnet_application_detach (&detach_args);
1571
1572   detach_args.app_index = server_index2;
1573   vnet_application_detach (&detach_args);
1574
1575   vec_free (ns_id);
1576   vec_free (attach_args.name);
1577   return 0;
1578 }
1579
1580 static int
1581 session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
1582 {
1583   u64 options[APP_OPTIONS_N_OPTIONS];
1584   char *show_listeners = "sh session listeners tcp verbose";
1585   char *show_local_listeners = "sh app ns table default";
1586   unformat_input_t tmp_input;
1587   u32 server_index, app_index;
1588   u32 dummy_server_api_index = ~0, sw_if_index = 0;
1589   clib_error_t *error = 0;
1590   u8 is_filtered = 0;
1591   stream_session_t *s;
1592   transport_connection_t *tc;
1593   u16 lcl_port = 1234, rmt_port = 4321;
1594   app_namespace_t *app_ns;
1595   int verbose = 0;
1596
1597   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1598     {
1599       if (unformat (input, "verbose"))
1600         verbose = 1;
1601       else
1602         {
1603           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1604                            input);
1605           return -1;
1606         }
1607     }
1608
1609   ip4_address_t lcl_ip = {
1610     .as_u32 = clib_host_to_net_u32 (0x01020304),
1611   };
1612   ip4_address_t rmt_ip = {
1613     .as_u32 = clib_host_to_net_u32 (0x05060708),
1614   };
1615   fib_prefix_t rmt_pref = {
1616     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1617     .fp_len = 16,
1618     .fp_proto = FIB_PROTOCOL_IP4,
1619   };
1620   session_endpoint_t sep = {
1621     .ip = rmt_pref.fp_addr,
1622     .is_ip4 = 1,
1623     .port = rmt_port,
1624     .transport_proto = TRANSPORT_PROTO_TCP,
1625   };
1626
1627   /*
1628    * Create loopback interface
1629    */
1630   session_create_lookpback (0, &sw_if_index, &lcl_ip);
1631
1632   app_ns = app_namespace_get_default ();
1633   app_ns->sw_if_index = sw_if_index;
1634
1635   clib_memset (options, 0, sizeof (options));
1636   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1637   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
1638   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
1639   options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
1640   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1641   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1642   vnet_app_attach_args_t attach_args = {
1643     .api_client_index = ~0,
1644     .options = options,
1645     .namespace_id = 0,
1646     .session_cb_vft = &dummy_session_cbs,
1647     .name = format (0, "session_test"),
1648   };
1649
1650   attach_args.api_client_index = dummy_server_api_index;
1651   error = vnet_application_attach (&attach_args);
1652   SESSION_TEST ((error == 0), "server attachment should work");
1653   server_index = attach_args.app_index;
1654
1655   if (verbose)
1656     {
1657       unformat_init_string (&tmp_input, show_listeners,
1658                             strlen (show_listeners));
1659       vlib_cli_input (vm, &tmp_input, 0, 0);
1660       unformat_init_string (&tmp_input, show_local_listeners,
1661                             strlen (show_local_listeners));
1662       vlib_cli_input (vm, &tmp_input, 0, 0);
1663     }
1664
1665   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
1666                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
1667   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
1668                 "successful");
1669   s = listen_session_get (tc->s_index);
1670   SESSION_TEST ((s->app_index == server_index), "lookup should return"
1671                 " the server");
1672
1673   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
1674                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
1675   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
1676                 " not work");
1677
1678   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1679   SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
1680                 " should work");
1681
1682   vnet_app_detach_args_t detach_args = {
1683     .app_index = server_index,
1684     .api_client_index = ~0,
1685   };
1686   vnet_application_detach (&detach_args);
1687
1688   if (verbose)
1689     {
1690       unformat_init_string (&tmp_input, show_listeners,
1691                             strlen (show_listeners));
1692       vlib_cli_input (vm, &tmp_input, 0, 0);
1693       unformat_init_string (&tmp_input, show_local_listeners,
1694                             strlen (show_local_listeners));
1695       vlib_cli_input (vm, &tmp_input, 0, 0);
1696     }
1697
1698   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1699   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
1700                 "local session endpoint lookup should not work after detach");
1701   if (verbose)
1702     unformat_free (&tmp_input);
1703   vec_free (attach_args.name);
1704   return 0;
1705 }
1706
1707 static clib_error_t *
1708 session_test (vlib_main_t * vm,
1709               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1710 {
1711   int res = 0;
1712
1713   vnet_session_enable_disable (vm, 1);
1714
1715   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1716     {
1717       if (unformat (input, "basic"))
1718         res = session_test_basic (vm, input);
1719       else if (unformat (input, "namespace"))
1720         res = session_test_namespace (vm, input);
1721       else if (unformat (input, "rules-table"))
1722         res = session_test_rule_table (vm, input);
1723       else if (unformat (input, "rules"))
1724         res = session_test_rules (vm, input);
1725       else if (unformat (input, "proxy"))
1726         res = session_test_proxy (vm, input);
1727       else if (unformat (input, "endpt-cfg"))
1728         res = session_test_endpoint_cfg (vm, input);
1729       else if (unformat (input, "all"))
1730         {
1731           if ((res = session_test_basic (vm, input)))
1732             goto done;
1733           if ((res = session_test_namespace (vm, input)))
1734             goto done;
1735           if ((res = session_test_rule_table (vm, input)))
1736             goto done;
1737           if ((res = session_test_rules (vm, input)))
1738             goto done;
1739           if ((res = session_test_proxy (vm, input)))
1740             goto done;
1741           if ((res = session_test_endpoint_cfg (vm, input)))
1742             goto done;
1743         }
1744       else
1745         break;
1746     }
1747
1748 done:
1749   if (res)
1750     return clib_error_return (0, "Session unit test failed");
1751   return 0;
1752 }
1753
1754 /* *INDENT-OFF* */
1755 VLIB_CLI_COMMAND (tcp_test_command, static) =
1756 {
1757   .path = "test session",
1758   .short_help = "internal session unit tests",
1759   .function = session_test,
1760 };
1761 /* *INDENT-ON* */
1762
1763 /*
1764  * fd.io coding-style-patch-verification: ON
1765  *
1766  * Local Variables:
1767  * eval: (c-set-style "gnu")
1768  * End:
1769  */