session: allow builtin apps to register names
[vpp.git] / src / vnet / session / 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
22 #define SESSION_TEST_I(_cond, _comment, _args...)               \
23 ({                                                              \
24   int _evald = (_cond);                                         \
25   if (!(_evald)) {                                              \
26     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
27             __LINE__, ##_args);                                 \
28   } else {                                                      \
29     fformat(stderr, "PASS:%d: " _comment "\n",                  \
30             __LINE__, ##_args);                                 \
31   }                                                             \
32   _evald;                                                       \
33 })
34
35 #define SESSION_TEST(_cond, _comment, _args...)                 \
36 {                                                               \
37     if (!SESSION_TEST_I(_cond, _comment, ##_args)) {            \
38         return 1;                                               \
39     }                                                           \
40 }
41
42 void
43 dummy_session_reset_callback (stream_session_t * s)
44 {
45   clib_warning ("called...");
46 }
47
48 int
49 dummy_session_connected_callback (u32 app_index, u32 api_context,
50                                   stream_session_t * s, u8 is_fail)
51 {
52   clib_warning ("called...");
53   return -1;
54 }
55
56 static u32 dummy_segment_count;
57
58 int
59 dummy_add_segment_callback (u32 client_index, const ssvm_private_t * fs)
60 {
61   dummy_segment_count = 1;
62   return 0;
63 }
64
65 int
66 dummy_del_segment_callback (u32 client_index, const ssvm_private_t * fs)
67 {
68   dummy_segment_count = 0;
69   return 0;
70 }
71
72 void
73 dummy_session_disconnect_callback (stream_session_t * s)
74 {
75   clib_warning ("called...");
76 }
77
78 static u32 dummy_accept;
79
80 int
81 dummy_session_accept_callback (stream_session_t * s)
82 {
83   dummy_accept = 1;
84   s->session_state = SESSION_STATE_READY;
85   return 0;
86 }
87
88 int
89 dummy_server_rx_callback (stream_session_t * s)
90 {
91   clib_warning ("called...");
92   return -1;
93 }
94
95 /* *INDENT-OFF* */
96 static session_cb_vft_t dummy_session_cbs = {
97   .session_reset_callback = dummy_session_reset_callback,
98   .session_connected_callback = dummy_session_connected_callback,
99   .session_accept_callback = dummy_session_accept_callback,
100   .session_disconnect_callback = dummy_session_disconnect_callback,
101   .builtin_app_rx_callback = dummy_server_rx_callback,
102   .add_segment_callback = dummy_add_segment_callback,
103   .del_segment_callback = dummy_del_segment_callback,
104 };
105 /* *INDENT-ON* */
106
107 static int
108 session_create_lookpback (u32 table_id, u32 * sw_if_index,
109                           ip4_address_t * intf_addr)
110 {
111   u8 intf_mac[6];
112
113   memset (intf_mac, 0, sizeof (intf_mac));
114
115   if (vnet_create_loopback_interface (sw_if_index, intf_mac, 0, 0))
116     {
117       clib_warning ("couldn't create loopback. stopping the test!");
118       return -1;
119     }
120
121   if (table_id != 0)
122     ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id, 0);
123
124   vnet_sw_interface_set_flags (vnet_get_main (), *sw_if_index,
125                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
126
127   if (ip4_add_del_interface_address (vlib_get_main (), *sw_if_index,
128                                      intf_addr, 24, 0))
129     {
130       clib_warning ("couldn't assign loopback ip %U", format_ip4_address,
131                     intf_addr);
132       return -1;
133     }
134
135   return 0;
136 }
137
138 static void
139 session_delete_loopback (u32 sw_if_index)
140 {
141   /* fails spectacularly  */
142   /* vnet_delete_loopback_interface (sw_if_index); */
143 }
144
145 static int
146 session_test_basic (vlib_main_t * vm, unformat_input_t * input)
147 {
148   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
149   u64 options[APP_OPTIONS_N_OPTIONS], bind4_handle, bind6_handle;
150   clib_error_t *error = 0;
151   u32 server_index;
152
153   memset (options, 0, sizeof (options));
154   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
155   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
156   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
157   vnet_app_attach_args_t attach_args = {
158     .api_client_index = ~0,
159     .options = options,
160     .namespace_id = 0,
161     .session_cb_vft = &dummy_session_cbs,
162     .name = format (0, "session_test"),
163   };
164
165   error = vnet_application_attach (&attach_args);
166   SESSION_TEST ((error == 0), "app attached");
167   server_index = attach_args.app_index;
168   vec_free (attach_args.name);
169
170   server_sep.is_ip4 = 1;
171   vnet_bind_args_t bind_args = {
172     .sep = server_sep,
173     .app_index = 0,
174   };
175
176   bind_args.app_index = server_index;
177   error = vnet_bind (&bind_args);
178   SESSION_TEST ((error == 0), "server bind4 should work");
179   bind4_handle = bind_args.handle;
180
181   error = vnet_bind (&bind_args);
182   SESSION_TEST ((error != 0), "double server bind4 should not work");
183
184   bind_args.sep.is_ip4 = 0;
185   error = vnet_bind (&bind_args);
186   SESSION_TEST ((error == 0), "server bind6 should work");
187   bind6_handle = bind_args.handle;
188
189   error = vnet_bind (&bind_args);
190   SESSION_TEST ((error != 0), "double server bind6 should not work");
191
192   vnet_unbind_args_t unbind_args = {
193     .handle = bind4_handle,
194     .app_index = server_index,
195   };
196   error = vnet_unbind (&unbind_args);
197   SESSION_TEST ((error == 0), "unbind4 should work");
198
199   unbind_args.handle = bind6_handle;
200   error = vnet_unbind (&unbind_args);
201   SESSION_TEST ((error == 0), "unbind6 should work");
202
203   vnet_app_detach_args_t detach_args = {
204     .app_index = server_index,
205   };
206   vnet_application_detach (&detach_args);
207   return 0;
208 }
209
210 static int
211 session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
212 {
213   u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
214   u32 server_index, server_st_index, server_local_st_index;
215   u32 dummy_port = 1234, client_index;
216   u32 dummy_api_context = 4321, dummy_client_api_index = 1234;
217   u32 dummy_server_api_index = ~0, sw_if_index = 0;
218   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
219   session_endpoint_t client_sep = SESSION_ENDPOINT_NULL;
220   session_endpoint_t intf_sep = SESSION_ENDPOINT_NULL;
221   clib_error_t *error = 0;
222   u8 *ns_id = format (0, "appns1");
223   app_namespace_t *app_ns;
224   application_t *server;
225   stream_session_t *s;
226   u64 handle;
227   int code;
228
229   server_sep.is_ip4 = 1;
230   server_sep.port = dummy_port;
231   client_sep.is_ip4 = 1;
232   client_sep.port = dummy_port;
233   memset (options, 0, sizeof (options));
234
235   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
236   vnet_app_attach_args_t attach_args = {
237     .api_client_index = ~0,
238     .options = options,
239     .namespace_id = 0,
240     .session_cb_vft = &dummy_session_cbs,
241     .name = format (0, "session_test"),
242   };
243
244   vnet_bind_args_t bind_args = {
245     .sep = server_sep,
246     .app_index = 0,
247   };
248
249   vnet_connect_args_t connect_args = {
250     .app_index = 0,
251     .api_context = 0,
252   };
253   clib_memcpy (&connect_args.sep, &client_sep, sizeof (client_sep));
254
255   vnet_unbind_args_t unbind_args = {
256     .handle = bind_args.handle,
257     .app_index = 0,
258   };
259
260   vnet_app_detach_args_t detach_args = {
261     .app_index = 0,
262   };
263
264   ip4_address_t intf_addr = {
265     .as_u32 = clib_host_to_net_u32 (0x06000105),
266   };
267
268   intf_sep.ip.ip4 = intf_addr;
269   intf_sep.is_ip4 = 1;
270   intf_sep.port = dummy_port;
271
272   /*
273    * Insert namespace and lookup
274    */
275
276   vnet_app_namespace_add_del_args_t ns_args = {
277     .ns_id = ns_id,
278     .secret = dummy_secret,
279     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
280     .is_add = 1
281   };
282   error = vnet_app_namespace_add_del (&ns_args);
283   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
284                 clib_error_get_code (error));
285
286   app_ns = app_namespace_get_from_id (ns_id);
287   SESSION_TEST ((app_ns != 0), "should find ns %v status", ns_id);
288   SESSION_TEST ((app_ns->ns_secret == dummy_secret), "secret should be %d",
289                 dummy_secret);
290   SESSION_TEST ((app_ns->sw_if_index == APP_NAMESPACE_INVALID_INDEX),
291                 "sw_if_index should be invalid");
292
293   /*
294    * Try application attach with wrong secret
295    */
296
297   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
298   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
299   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret - 1;
300   attach_args.namespace_id = ns_id;
301   attach_args.api_client_index = dummy_server_api_index;
302
303   error = vnet_application_attach (&attach_args);
304   SESSION_TEST ((error != 0), "app attachment should fail");
305   code = clib_error_get_code (error);
306   SESSION_TEST ((code == VNET_API_ERROR_APP_WRONG_NS_SECRET),
307                 "code should be wrong ns secret: %d", code);
308
309   /*
310    * Attach server with global default scope
311    */
312   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
313   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
314   options[APP_OPTIONS_NAMESPACE_SECRET] = 0;
315   attach_args.namespace_id = 0;
316   attach_args.api_client_index = dummy_server_api_index;
317   error = vnet_application_attach (&attach_args);
318   SESSION_TEST ((error == 0), "server attachment should work");
319   server_index = attach_args.app_index;
320   server = application_get (server_index);
321   SESSION_TEST ((server->ns_index == 0),
322                 "server should be in the default ns");
323
324   bind_args.app_index = server_index;
325   error = vnet_bind (&bind_args);
326   SESSION_TEST ((error == 0), "server bind should work");
327
328   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
329   s = session_lookup_listener (server_st_index, &server_sep);
330   SESSION_TEST ((s != 0), "listener should exist in global table");
331   SESSION_TEST ((s->app_index == server_index), "app_index should be that of "
332                 "the server");
333   server_local_st_index = application_local_session_table (server);
334   SESSION_TEST ((server_local_st_index == APP_INVALID_INDEX),
335                 "server shouldn't have access to local table");
336
337   unbind_args.app_index = server_index;
338   unbind_args.handle = bind_args.handle;
339   error = vnet_unbind (&unbind_args);
340   SESSION_TEST ((error == 0), "unbind should work");
341
342   s = session_lookup_listener (server_st_index, &server_sep);
343   SESSION_TEST ((s == 0), "listener should not exist in global table");
344
345   detach_args.app_index = server_index;
346   vnet_application_detach (&detach_args);
347
348   /*
349    * Attach server with local and global scope
350    */
351   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
352   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
353   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
354   attach_args.namespace_id = ns_id;
355   attach_args.api_client_index = dummy_server_api_index;
356   error = vnet_application_attach (&attach_args);
357   SESSION_TEST ((error == 0), "server attachment should work");
358   server_index = attach_args.app_index;
359   server = application_get (server_index);
360   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
361                 "server should be in the right ns");
362
363   bind_args.app_index = server_index;
364   error = vnet_bind (&bind_args);
365   SESSION_TEST ((error == 0), "bind should work");
366   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
367   s = session_lookup_listener (server_st_index, &server_sep);
368   SESSION_TEST ((s != 0), "listener should exist in global table");
369   SESSION_TEST ((s->app_index == server_index), "app_index should be that of "
370                 "the server");
371   server_local_st_index = application_local_session_table (server);
372   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
373   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
374                 "listener should exist in local table");
375
376   /*
377    * Try client connect with 1) local scope 2) global scope
378    */
379   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
380   attach_args.api_client_index = dummy_client_api_index;
381   error = vnet_application_attach (&attach_args);
382   SESSION_TEST ((error == 0), "client attachment should work");
383   client_index = attach_args.app_index;
384   connect_args.api_context = dummy_api_context;
385   connect_args.app_index = client_index;
386   error = vnet_connect (&connect_args);
387   SESSION_TEST ((error != 0), "client connect should return error code");
388   code = clib_error_get_code (error);
389   SESSION_TEST ((code == VNET_API_ERROR_INVALID_VALUE),
390                 "error code should be invalid value (zero ip)");
391   SESSION_TEST ((dummy_segment_count == 0),
392                 "shouldn't have received request to map new segment");
393   connect_args.sep.ip.ip4.as_u8[0] = 127;
394   error = vnet_connect (&connect_args);
395   SESSION_TEST ((error == 0), "client connect should not return error code");
396   code = clib_error_get_code (error);
397   SESSION_TEST ((dummy_segment_count == 1),
398                 "should've received request to map new segment");
399   SESSION_TEST ((dummy_accept == 1), "should've received accept request");
400   detach_args.app_index = client_index;
401   vnet_application_detach (&detach_args);
402
403   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
404   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
405   attach_args.api_client_index = dummy_client_api_index;
406   error = vnet_application_attach (&attach_args);
407   SESSION_TEST ((error == 0), "client attachment should work");
408   error = vnet_connect (&connect_args);
409   SESSION_TEST ((error != 0), "client connect should return error code");
410   code = clib_error_get_code (error);
411   SESSION_TEST ((code == VNET_API_ERROR_SESSION_CONNECT),
412                 "error code should be connect (nothing in local scope)");
413   detach_args.app_index = client_index;
414   vnet_application_detach (&detach_args);
415
416   /*
417    * Unbind and detach server and then re-attach with local scope only
418    */
419   unbind_args.handle = bind_args.handle;
420   unbind_args.app_index = server_index;
421   error = vnet_unbind (&unbind_args);
422   SESSION_TEST ((error == 0), "unbind should work");
423
424   s = session_lookup_listener (server_st_index, &server_sep);
425   SESSION_TEST ((s == 0), "listener should not exist in global table");
426   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
427   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
428                 "listener should not exist in local table");
429
430   detach_args.app_index = server_index;
431   vnet_application_detach (&detach_args);
432
433   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
434   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
435   attach_args.api_client_index = dummy_server_api_index;
436   error = vnet_application_attach (&attach_args);
437   SESSION_TEST ((error == 0), "app attachment should work");
438   server_index = attach_args.app_index;
439   server = application_get (server_index);
440   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
441                 "app should be in the right ns");
442
443   bind_args.app_index = server_index;
444   error = vnet_bind (&bind_args);
445   SESSION_TEST ((error == 0), "bind should work");
446
447   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
448   s = session_lookup_listener (server_st_index, &server_sep);
449   SESSION_TEST ((s == 0), "listener should not exist in global table");
450   server_local_st_index = application_local_session_table (server);
451   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
452   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
453                 "listener should exist in local table");
454
455   unbind_args.handle = bind_args.handle;
456   error = vnet_unbind (&unbind_args);
457   SESSION_TEST ((error == 0), "unbind should work");
458
459   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
460   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
461                 "listener should not exist in local table");
462
463   /*
464    * Client attach + connect in default ns with local scope
465    */
466   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
467   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
468   attach_args.namespace_id = 0;
469   attach_args.api_client_index = dummy_client_api_index;
470   vnet_application_attach (&attach_args);
471   error = vnet_connect (&connect_args);
472   SESSION_TEST ((error != 0), "client connect should return error code");
473   code = clib_error_get_code (error);
474   SESSION_TEST ((code == VNET_API_ERROR_SESSION_CONNECT),
475                 "error code should be connect (not in same ns)");
476   detach_args.app_index = client_index;
477   vnet_application_detach (&detach_args);
478
479   /*
480    * Detach server
481    */
482   detach_args.app_index = server_index;
483   vnet_application_detach (&detach_args);
484
485   /*
486    * Create loopback interface
487    */
488   session_create_lookpback (0, &sw_if_index, &intf_addr);
489
490   /*
491    * Update namespace
492    */
493   ns_args.sw_if_index = sw_if_index;
494   error = vnet_app_namespace_add_del (&ns_args);
495   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
496                 clib_error_get_code (error));
497
498   /*
499    * Attach server with local and global scope
500    */
501   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
502   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
503   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
504   attach_args.namespace_id = ns_id;
505   attach_args.api_client_index = dummy_server_api_index;
506   error = vnet_application_attach (&attach_args);
507   SESSION_TEST ((error == 0), "server attachment should work");
508   server_index = attach_args.app_index;
509
510   bind_args.app_index = server_index;
511   error = vnet_bind (&bind_args);
512   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
513   s = session_lookup_listener (server_st_index, &server_sep);
514   SESSION_TEST ((s == 0), "zero listener should not exist in global table");
515
516   s = session_lookup_listener (server_st_index, &intf_sep);
517   SESSION_TEST ((s != 0), "intf listener should exist in global table");
518   SESSION_TEST ((s->app_index == server_index), "app_index should be that of "
519                 "the server");
520   server_local_st_index = application_local_session_table (server);
521   handle = session_lookup_local_endpoint (server_local_st_index, &server_sep);
522   SESSION_TEST ((handle != SESSION_INVALID_HANDLE),
523                 "zero listener should exist in local table");
524   detach_args.app_index = server_index;
525   vnet_application_detach (&detach_args);
526
527   /*
528    * Cleanup
529    */
530   vec_free (attach_args.name);
531   vec_free (ns_id);
532   session_delete_loopback (sw_if_index);
533   return 0;
534 }
535
536 static int
537 session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
538 {
539   session_rules_table_t _srt, *srt = &_srt;
540   u16 lcl_port = 1234, rmt_port = 4321;
541   u32 action_index = 1, res;
542   ip4_address_t lcl_lkup, rmt_lkup;
543   clib_error_t *error;
544   int verbose = 0;
545
546   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
547     {
548       if (unformat (input, "verbose"))
549         verbose = 1;
550       else
551         {
552           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
553                            input);
554           return -1;
555         }
556     }
557
558   memset (srt, 0, sizeof (*srt));
559   session_rules_table_init (srt);
560
561   ip4_address_t lcl_ip = {
562     .as_u32 = clib_host_to_net_u32 (0x01020304),
563   };
564   ip4_address_t rmt_ip = {
565     .as_u32 = clib_host_to_net_u32 (0x05060708),
566   };
567   ip4_address_t lcl_ip2 = {
568     .as_u32 = clib_host_to_net_u32 (0x02020202),
569   };
570   ip4_address_t rmt_ip2 = {
571     .as_u32 = clib_host_to_net_u32 (0x06060606),
572   };
573   ip4_address_t lcl_ip3 = {
574     .as_u32 = clib_host_to_net_u32 (0x03030303),
575   };
576   ip4_address_t rmt_ip3 = {
577     .as_u32 = clib_host_to_net_u32 (0x07070707),
578   };
579   fib_prefix_t lcl_pref = {
580     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
581     .fp_len = 16,
582     .fp_proto = FIB_PROTOCOL_IP4,
583   };
584   fib_prefix_t rmt_pref = {
585     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
586     .fp_len = 16,
587     .fp_proto = FIB_PROTOCOL_IP4,
588   };
589
590   session_rule_table_add_del_args_t args = {
591     .lcl = lcl_pref,
592     .rmt = rmt_pref,
593     .lcl_port = lcl_port,
594     .rmt_port = rmt_port,
595     .action_index = action_index++,
596     .is_add = 1,
597   };
598   error = session_rules_table_add_del (srt, &args);
599   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
600                 action_index - 1);
601
602   res =
603     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
604   SESSION_TEST ((res == 1),
605                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
606                 res);
607
608   /*
609    * 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
610    */
611   args.lcl.fp_addr.ip4 = lcl_ip;
612   args.lcl.fp_len = 24;
613   args.action_index = action_index++;
614   error = session_rules_table_add_del (srt, &args);
615   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
616                 action_index - 1);
617   args.rmt.fp_addr.ip4 = rmt_ip;
618   args.rmt.fp_len = 24;
619   args.action_index = action_index++;
620   error = session_rules_table_add_del (srt, &args);
621   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
622                 action_index - 1);
623
624   /*
625    * 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
626    */
627   args.lcl.fp_addr.ip4 = lcl_ip2;
628   args.lcl.fp_len = 24;
629   args.rmt.fp_addr.ip4 = rmt_ip2;
630   args.rmt.fp_len = 16;
631   args.action_index = action_index++;
632   error = session_rules_table_add_del (srt, &args);
633   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
634                 action_index - 1);
635   args.lcl.fp_addr.ip4 = lcl_ip3;
636   args.rmt.fp_addr.ip4 = rmt_ip3;
637   args.action_index = action_index++;
638   error = session_rules_table_add_del (srt, &args);
639   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
640                 action_index - 1);
641
642   /*
643    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
644    */
645   args.lcl.fp_addr.ip4 = lcl_ip3;
646   args.rmt.fp_addr.ip4 = rmt_ip3;
647   args.action_index = action_index++;
648   error = session_rules_table_add_del (srt, &args);
649   SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
650                 "action %d", action_index - 1);
651
652   /*
653    * 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
654    * and  3.3.3.3 1234 7.7.7.7 4321
655    */
656   res =
657     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
658   SESSION_TEST ((res == 3),
659                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
660                 res);
661
662   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
663   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
664   res =
665     session_rules_table_lookup4 (srt, &lcl_lkup,
666                                  &rmt_lkup, lcl_port, rmt_port);
667   SESSION_TEST ((res == 1),
668                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
669                 res);
670
671   res =
672     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
673   SESSION_TEST ((res == 6),
674                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
675                 "should be 6 (updated): %d", res);
676
677   /*
678    * Add 1.2.3.4/24 * 5.6.7.8/24 *
679    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
680    */
681   args.lcl.fp_addr.ip4 = lcl_ip;
682   args.rmt.fp_addr.ip4 = rmt_ip;
683   args.lcl.fp_len = 24;
684   args.rmt.fp_len = 24;
685   args.lcl_port = 0;
686   args.rmt_port = 0;
687   args.action_index = action_index++;
688   error = session_rules_table_add_del (srt, &args);
689   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
690                 action_index - 1);
691   res =
692     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
693   SESSION_TEST ((res == 7),
694                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
695                 " be 7 (lpm dst): %d", res);
696   res =
697     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
698                                  lcl_port + 1, rmt_port);
699   SESSION_TEST ((res == 7),
700                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
701                 res);
702
703   /*
704    * Del 1.2.3.4/24 * 5.6.7.8/24 *
705    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
706    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
707    * 1.2.3.4 1235 5.6.7.8 4322
708    */
709   args.is_add = 0;
710   error = session_rules_table_add_del (srt, &args);
711   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
712
713   args.lcl.fp_addr.ip4 = lcl_ip;
714   args.rmt.fp_addr.ip4 = rmt_ip;
715   args.lcl.fp_len = 16;
716   args.rmt.fp_len = 16;
717   args.lcl_port = 0;
718   args.rmt_port = 0;
719   args.action_index = action_index++;
720   args.is_add = 1;
721   error = session_rules_table_add_del (srt, &args);
722   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
723                 action_index - 1);
724
725   args.lcl.fp_addr.ip4 = lcl_ip;
726   args.rmt.fp_addr.ip4 = rmt_ip;
727   args.lcl.fp_len = 24;
728   args.rmt.fp_len = 24;
729   args.lcl_port = lcl_port + 1;
730   args.rmt_port = rmt_port;
731   args.action_index = action_index++;
732   args.is_add = 1;
733   error = session_rules_table_add_del (srt, &args);
734   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
735                 action_index - 1);
736
737   if (verbose)
738     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
739
740   res =
741     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
742   SESSION_TEST ((res == 3),
743                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
744                 res);
745   res =
746     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
747                                  lcl_port + 1, rmt_port);
748   SESSION_TEST ((res == 9),
749                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
750                 res);
751   res =
752     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
753                                  lcl_port + 1, rmt_port + 1);
754   SESSION_TEST ((res == 8),
755                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
756                 res);
757
758   /*
759    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
760    * Lookup 1.2.3.4 1234 5.6.7.8 4321
761    */
762   args.lcl_port = 1234;
763   args.rmt_port = 4321;
764   args.lcl.fp_len = 16;
765   args.rmt.fp_len = 16;
766   args.is_add = 0;
767   error = session_rules_table_add_del (srt, &args);
768   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
769   res =
770     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
771   SESSION_TEST ((res == 3),
772                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
773                 res);
774
775   args.lcl_port = 0;
776   args.rmt_port = 0;
777   args.is_add = 0;
778   error = session_rules_table_add_del (srt, &args);
779   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
780   res =
781     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
782   SESSION_TEST ((res == 3),
783                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
784                 res);
785
786   /*
787    * Delete 1.2.3.4/24 1234 5.6.7.5/24
788    */
789   args.lcl.fp_addr.ip4 = lcl_ip;
790   args.rmt.fp_addr.ip4 = rmt_ip;
791   args.lcl.fp_len = 24;
792   args.rmt.fp_len = 24;
793   args.lcl_port = 1234;
794   args.rmt_port = 4321;
795   args.is_add = 0;
796   error = session_rules_table_add_del (srt, &args);
797   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
798   res =
799     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
800   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
801
802   return 0;
803 }
804
805 static int
806 session_test_rules (vlib_main_t * vm, unformat_input_t * input)
807 {
808   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
809   u64 options[APP_OPTIONS_N_OPTIONS];
810   u16 lcl_port = 1234, rmt_port = 4321;
811   u32 server_index, server_index2;
812   u32 dummy_server_api_index = ~0;
813   transport_connection_t *tc;
814   u32 dummy_port = 1111;
815   clib_error_t *error = 0;
816   u8 is_filtered = 0, *ns_id = format (0, "appns1");
817   stream_session_t *listener, *s;
818   app_namespace_t *default_ns = app_namespace_get_default ();
819   u32 local_ns_index = default_ns->local_table_index;
820   int verbose = 0, rv;
821   app_namespace_t *app_ns;
822   u64 handle;
823
824   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
825     {
826       if (unformat (input, "verbose"))
827         verbose = 1;
828       else
829         {
830           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
831                            input);
832           return -1;
833         }
834     }
835
836   server_sep.is_ip4 = 1;
837   server_sep.port = dummy_port;
838   memset (options, 0, sizeof (options));
839
840   vnet_app_attach_args_t attach_args = {
841     .api_client_index = ~0,
842     .options = options,
843     .namespace_id = 0,
844     .session_cb_vft = &dummy_session_cbs,
845     .name = format (0, "session_test"),
846   };
847
848   vnet_bind_args_t bind_args = {
849     .sep = server_sep,
850     .app_index = 0,
851   };
852
853   /*
854    * Attach server with global and local default scope
855    */
856   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
857   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
858   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
859   attach_args.namespace_id = 0;
860   attach_args.api_client_index = dummy_server_api_index;
861   error = vnet_application_attach (&attach_args);
862   SESSION_TEST ((error == 0), "server attached");
863   server_index = attach_args.app_index;
864
865   bind_args.app_index = server_index;
866   error = vnet_bind (&bind_args);
867   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
868                 &server_sep.ip, 1, server_sep.port);
869   listener = listen_session_get_from_handle (bind_args.handle);
870   ip4_address_t lcl_ip = {
871     .as_u32 = clib_host_to_net_u32 (0x01020304),
872   };
873   ip4_address_t rmt_ip = {
874     .as_u32 = clib_host_to_net_u32 (0x05060708),
875   };
876   fib_prefix_t lcl_pref = {
877     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
878     .fp_len = 16,
879     .fp_proto = FIB_PROTOCOL_IP4,
880   };
881   fib_prefix_t rmt_pref = {
882     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
883     .fp_len = 16,
884     .fp_proto = FIB_PROTOCOL_IP4,
885   };
886
887   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
888                                       &rmt_pref.fp_addr.ip4, lcl_port,
889                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
890                                       &is_filtered);
891   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
892
893   /*
894    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
895    */
896   session_rule_add_del_args_t args = {
897     .table_args.lcl = lcl_pref,
898     .table_args.rmt = rmt_pref,
899     .table_args.lcl_port = lcl_port,
900     .table_args.rmt_port = rmt_port,
901     .table_args.action_index = server_index,
902     .table_args.is_add = 1,
903     .appns_index = 0,
904   };
905   error = vnet_session_rule_add_del (&args);
906   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
907                 args.table_args.action_index);
908
909   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
910                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
911                                    TRANSPORT_PROTO_TCP);
912   SESSION_TEST ((tc->c_index == listener->connection_index),
913                 "optimized lookup should return the listener");
914   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
915                                       &rmt_pref.fp_addr.ip4, lcl_port,
916                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
917                                       &is_filtered);
918   SESSION_TEST ((tc->c_index == listener->connection_index),
919                 "lookup should return the listener");
920   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
921                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
922   SESSION_TEST ((s->connection_index == listener->connection_index),
923                 "safe lookup should return the listener");
924   session_endpoint_t sep = {
925     .ip = rmt_pref.fp_addr,
926     .is_ip4 = 1,
927     .port = rmt_port,
928     .transport_proto = TRANSPORT_PROTO_TCP,
929   };
930   handle = session_lookup_local_endpoint (local_ns_index, &sep);
931   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
932                 "should not work (global scope)");
933
934   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
935                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
936                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
937                                       &is_filtered);
938   SESSION_TEST ((tc == 0),
939                 "optimized lookup for wrong lcl port + 1 should not work");
940
941   /*
942    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
943    */
944   args.table_args.lcl_port = 0;
945   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
946   error = vnet_session_rule_add_del (&args);
947   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
948                 args.table_args.action_index);
949   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
950                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
951                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
952                                       &is_filtered);
953   SESSION_TEST ((tc->c_index == listener->connection_index),
954                 "optimized lookup for lcl port + 1 should work");
955   handle = session_lookup_local_endpoint (local_ns_index, &sep);
956   SESSION_TEST ((handle == server_index), "local session endpoint lookup "
957                 "should work (lcl ip was zeroed)");
958
959   /*
960    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
961    */
962   args.table_args.lcl_port = 1234;
963   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
964   args.table_args.lcl.fp_len = 30;
965   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
966   args.table_args.rmt.fp_len = 30;
967   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
968   error = vnet_session_rule_add_del (&args);
969   SESSION_TEST ((error == 0), "Add 1.2.3.4/30 1234 5.6.7.8/30 4321 action %d",
970                 args.table_args.action_index);
971
972   if (verbose)
973     {
974       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
975                                        TRANSPORT_PROTO_TCP);
976       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
977                                              TRANSPORT_PROTO_TCP);
978     }
979
980   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
981                                       &rmt_pref.fp_addr.ip4, lcl_port,
982                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
983                                       &is_filtered);
984   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
985                 "should fail (deny rule)");
986   SESSION_TEST ((is_filtered == 1), "lookup should be filtered (deny)");
987
988   handle = session_lookup_local_endpoint (local_ns_index, &sep);
989   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
990                 "5.6.7.8/16 4321 in local table should return deny");
991
992   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
993                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
994                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
995                                       &is_filtered);
996   SESSION_TEST ((tc->c_index == listener->connection_index),
997                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should work");
998
999   /*
1000    * "Mask" deny rule with more specific allow:
1001    * Add allow rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -3 (allow)
1002    */
1003   args.table_args.is_add = 1;
1004   args.table_args.lcl_port = 1234;
1005   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1006   args.table_args.lcl.fp_len = 32;
1007   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1008   args.table_args.rmt.fp_len = 32;
1009   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
1010   error = vnet_session_rule_add_del (&args);
1011   SESSION_TEST ((error == 0), "Add masking rule 1.2.3.4/30 1234 5.6.7.8/32 "
1012                 "4321 action %d", args.table_args.action_index);
1013
1014   is_filtered = 0;
1015   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1016                                       &rmt_pref.fp_addr.ip4, lcl_port,
1017                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1018                                       &is_filtered);
1019   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
1020                 "should fail (allow without app)");
1021   SESSION_TEST ((is_filtered == 0), "lookup should NOT be filtered");
1022
1023   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1024   SESSION_TEST ((handle == SESSION_INVALID_HANDLE), "lookup for 1.2.3.4/32 "
1025                 "1234 5.6.7.8/32 4321 in local table should return invalid");
1026
1027   if (verbose)
1028     {
1029       vlib_cli_output (vm, "Local rules");
1030       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1031                                              TRANSPORT_PROTO_TCP);
1032     }
1033
1034   sep.ip.ip4.as_u32 += 1 << 24;
1035   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1036   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234"
1037                 " 5.6.7.9/32 4321 in local table should return deny");
1038
1039   vnet_connect_args_t connect_args = {
1040     .app_index = attach_args.app_index,
1041     .api_context = 0,
1042   };
1043   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
1044
1045   /* Try connecting */
1046   error = vnet_connect (&connect_args);
1047   SESSION_TEST ((error != 0), "connect should fail");
1048   rv = clib_error_get_code (error);
1049   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1050                 "connect should be filtered");
1051
1052   sep.ip.ip4.as_u32 -= 1 << 24;
1053
1054   /*
1055    * Delete masking rule: 1.2.3.4/32 1234 5.6.7.8/32 4321 allow
1056    */
1057   args.table_args.is_add = 0;
1058   args.table_args.lcl_port = 1234;
1059   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1060   args.table_args.lcl.fp_len = 32;
1061   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1062   args.table_args.rmt.fp_len = 32;
1063   error = vnet_session_rule_add_del (&args);
1064   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 allow");
1065
1066
1067   /*
1068    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
1069    */
1070   args.table_args.is_add = 1;
1071   args.table_args.lcl_port = 0;
1072   args.table_args.lcl.fp_len = 0;
1073   args.table_args.rmt.fp_len = 16;
1074   args.table_args.action_index = -1;
1075   error = vnet_session_rule_add_del (&args);
1076   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
1077                 args.table_args.action_index);
1078
1079   if (verbose)
1080     {
1081       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1082                                        TRANSPORT_PROTO_TCP);
1083       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1084                                              TRANSPORT_PROTO_TCP);
1085     }
1086
1087   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1088   SESSION_TEST ((handle == SESSION_DROP_HANDLE),
1089                 "local session endpoint lookup should return deny");
1090
1091   /*
1092    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
1093    */
1094   args.table_args.is_add = 0;
1095   args.table_args.lcl_port = 1234;
1096   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1097   args.table_args.lcl.fp_len = 30;
1098   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1099   args.table_args.rmt.fp_len = 30;
1100   error = vnet_session_rule_add_del (&args);
1101   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1102
1103   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1104   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1105                 "local session endpoint lookup should return invalid");
1106
1107   /*
1108    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
1109    * 1.2.3.4/16 1234 5.6.7.8/16 4321
1110    */
1111   args.table_args.is_add = 0;
1112   args.table_args.lcl_port = 0;
1113   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1114   args.table_args.lcl.fp_len = 0;
1115   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1116   args.table_args.rmt.fp_len = 16;
1117   args.table_args.rmt_port = 4321;
1118   error = vnet_session_rule_add_del (&args);
1119   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
1120   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1121   SESSION_TEST ((handle != server_index), "local session endpoint lookup "
1122                 "should not work (removed)");
1123
1124   args.table_args.is_add = 0;
1125   args.table_args.lcl = lcl_pref;
1126
1127   args.table_args.is_add = 0;
1128   args.table_args.lcl_port = 0;
1129   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1130   args.table_args.lcl.fp_len = 16;
1131   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1132   args.table_args.rmt.fp_len = 16;
1133   args.table_args.rmt_port = 4321;
1134   error = vnet_session_rule_add_del (&args);
1135   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
1136   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1137                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1138                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1139                                       &is_filtered);
1140   SESSION_TEST ((tc == 0),
1141                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
1142                 "work (del)");
1143
1144   args.table_args.is_add = 0;
1145   args.table_args.lcl_port = 1234;
1146   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1147   args.table_args.lcl.fp_len = 16;
1148   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1149   args.table_args.rmt.fp_len = 16;
1150   args.table_args.rmt_port = 4321;
1151   error = vnet_session_rule_add_del (&args);
1152   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
1153   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1154                                       &rmt_pref.fp_addr.ip4, lcl_port,
1155                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1156                                       &is_filtered);
1157   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
1158                 "not work (del + deny)");
1159
1160   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1161   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1162                                       &rmt_pref.fp_addr.ip4, lcl_port,
1163                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1164                                       &is_filtered);
1165   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
1166                 " not work (no-rule)");
1167
1168   /*
1169    * Test tags. Add/overwrite/del rule with tag
1170    */
1171   args.table_args.is_add = 1;
1172   args.table_args.lcl_port = 1234;
1173   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1174   args.table_args.lcl.fp_len = 16;
1175   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1176   args.table_args.rmt.fp_len = 16;
1177   args.table_args.rmt_port = 4321;
1178   args.table_args.tag = format (0, "test_rule");
1179   args.table_args.action_index = server_index;
1180   error = vnet_session_rule_add_del (&args);
1181   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
1182                 "tag test_rule");
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   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1191                                       &rmt_pref.fp_addr.ip4, lcl_port,
1192                                       rmt_port, TRANSPORT_PROTO_TCP, 0,
1193                                       &is_filtered);
1194   SESSION_TEST ((tc->c_index == listener->connection_index),
1195                 "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
1196
1197   vec_free (args.table_args.tag);
1198   args.table_args.lcl_port = 1234;
1199   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1200   args.table_args.lcl.fp_len = 16;
1201   args.table_args.tag = format (0, "test_rule_overwrite");
1202   error = vnet_session_rule_add_del (&args);
1203   SESSION_TEST ((error == 0),
1204                 "Overwrite 1.2.3.4/16 1234 5.6.7.8/16 4321 deny tag test_rule"
1205                 " should work");
1206   if (verbose)
1207     {
1208       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1209                                        TRANSPORT_PROTO_TCP);
1210       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1211                                              TRANSPORT_PROTO_TCP);
1212     }
1213
1214   args.table_args.is_add = 0;
1215   args.table_args.lcl_port += 1;
1216   error = vnet_session_rule_add_del (&args);
1217   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
1218                 "tag %v", args.table_args.tag);
1219   if (verbose)
1220     {
1221       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1222                                        TRANSPORT_PROTO_TCP);
1223       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1224                                              TRANSPORT_PROTO_TCP);
1225     }
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 1.2.3.4/32 1234 5.6.7.8/32 4321 should not"
1231                 " work (del)");
1232
1233
1234   /*
1235    * Test local rules with multiple namespaces
1236    */
1237
1238   /*
1239    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1240    */
1241   args.table_args.is_add = 1;
1242   args.table_args.lcl_port = 1234;
1243   args.table_args.rmt_port = 0;
1244   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1245   args.table_args.lcl.fp_len = 32;
1246   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1247   args.table_args.rmt.fp_len = 32;
1248   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1249   args.table_args.tag = 0;
1250   args.scope = SESSION_RULE_SCOPE_LOCAL;
1251   error = vnet_session_rule_add_del (&args);
1252   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
1253                 args.table_args.action_index);
1254   /*
1255    * Add 'white' rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
1256    */
1257   args.table_args.is_add = 1;
1258   args.table_args.lcl_port = 1234;
1259   args.table_args.rmt_port = 4321;
1260   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1261   args.table_args.lcl.fp_len = 32;
1262   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1263   args.table_args.rmt.fp_len = 32;
1264   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_ALLOW;
1265   error = vnet_session_rule_add_del (&args);
1266
1267   if (verbose)
1268     {
1269       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1270                                              TRANSPORT_PROTO_TCP);
1271     }
1272
1273   vnet_app_namespace_add_del_args_t ns_args = {
1274     .ns_id = ns_id,
1275     .secret = 0,
1276     .sw_if_index = APP_NAMESPACE_INVALID_INDEX,
1277     .is_add = 1
1278   };
1279   error = vnet_app_namespace_add_del (&ns_args);
1280   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
1281                 clib_error_get_code (error));
1282   app_ns = app_namespace_get_from_id (ns_id);
1283
1284   attach_args.namespace_id = ns_id;
1285   attach_args.api_client_index = dummy_server_api_index - 1;
1286   error = vnet_application_attach (&attach_args);
1287   SESSION_TEST ((error == 0), "server2 attached");
1288   server_index2 = attach_args.app_index;
1289
1290   /*
1291    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 0 action -2 (drop)
1292    */
1293   args.table_args.lcl_port = 1234;
1294   args.table_args.rmt_port = 0;
1295   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1296   args.table_args.lcl.fp_len = 32;
1297   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1298   args.table_args.rmt.fp_len = 32;
1299   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
1300   args.appns_index = app_namespace_index (app_ns);
1301
1302   error = vnet_session_rule_add_del (&args);
1303   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d "
1304                 "in test namespace", args.table_args.action_index);
1305   /*
1306    * Lookup default namespace
1307    */
1308   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1309   SESSION_TEST ((handle == SESSION_INVALID_HANDLE),
1310                 "lookup for 1.2.3.4/32 1234 5.6.7.8/32 4321 in local table "
1311                 "should return allow (invalid)");
1312
1313   sep.port += 1;
1314   handle = session_lookup_local_endpoint (local_ns_index, &sep);
1315   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1316                 "5.6.7.8/16 432*2* in local table should return deny");
1317
1318
1319   connect_args.app_index = server_index;
1320   clib_memcpy (&connect_args.sep, &sep, sizeof (sep));
1321
1322   error = vnet_connect (&connect_args);
1323   SESSION_TEST ((error != 0), "connect should fail");
1324   rv = clib_error_get_code (error);
1325   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1326                 "connect should be filtered");
1327
1328   /*
1329    * Lookup test namespace
1330    */
1331   handle = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1332   SESSION_TEST ((handle == SESSION_DROP_HANDLE), "lookup for 1.2.3.4/32 1234 "
1333                 "5.6.7.8/16 4321 in local table should return deny");
1334
1335   connect_args.app_index = server_index;
1336   error = vnet_connect (&connect_args);
1337   SESSION_TEST ((error != 0), "connect should fail");
1338   rv = clib_error_get_code (error);
1339   SESSION_TEST ((rv == VNET_API_ERROR_APP_CONNECT_FILTERED),
1340                 "connect should be filtered");
1341
1342   args.table_args.is_add = 0;
1343   vnet_session_rule_add_del (&args);
1344
1345   args.appns_index = 0;
1346   args.table_args.is_add = 0;
1347   vnet_session_rule_add_del (&args);
1348
1349   args.table_args.rmt_port = 4321;
1350   vnet_session_rule_add_del (&args);
1351   /*
1352    * Final Cleanup
1353    */
1354   vec_free (args.table_args.tag);
1355   vnet_app_detach_args_t detach_args = {
1356     .app_index = server_index,
1357   };
1358   vnet_application_detach (&detach_args);
1359
1360   detach_args.app_index = server_index2;
1361   vnet_application_detach (&detach_args);
1362
1363   vec_free (ns_id);
1364   vec_free (attach_args.name);
1365   return 0;
1366 }
1367
1368 static int
1369 session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
1370 {
1371   u64 options[APP_OPTIONS_N_OPTIONS];
1372   char *show_listeners = "sh session listeners tcp verbose";
1373   char *show_local_listeners = "sh app ns table default";
1374   unformat_input_t tmp_input;
1375   u32 server_index, app_index;
1376   u32 dummy_server_api_index = ~0, sw_if_index = 0;
1377   clib_error_t *error = 0;
1378   u8 sst, is_filtered = 0;
1379   stream_session_t *s;
1380   transport_connection_t *tc;
1381   u16 lcl_port = 1234, rmt_port = 4321;
1382   app_namespace_t *app_ns;
1383   int verbose = 0;
1384
1385   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1386     {
1387       if (unformat (input, "verbose"))
1388         verbose = 1;
1389       else
1390         {
1391           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1392                            input);
1393           return -1;
1394         }
1395     }
1396
1397   ip4_address_t lcl_ip = {
1398     .as_u32 = clib_host_to_net_u32 (0x01020304),
1399   };
1400   ip4_address_t rmt_ip = {
1401     .as_u32 = clib_host_to_net_u32 (0x05060708),
1402   };
1403   fib_prefix_t rmt_pref = {
1404     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1405     .fp_len = 16,
1406     .fp_proto = FIB_PROTOCOL_IP4,
1407   };
1408   session_endpoint_t sep = {
1409     .ip = rmt_pref.fp_addr,
1410     .is_ip4 = 1,
1411     .port = rmt_port,
1412     .transport_proto = TRANSPORT_PROTO_TCP,
1413   };
1414
1415   /*
1416    * Create loopback interface
1417    */
1418   session_create_lookpback (0, &sw_if_index, &lcl_ip);
1419
1420   app_ns = app_namespace_get_default ();
1421   app_ns->sw_if_index = sw_if_index;
1422
1423   memset (options, 0, sizeof (options));
1424   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
1425   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
1426   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
1427   options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
1428   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1429   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1430   vnet_app_attach_args_t attach_args = {
1431     .api_client_index = ~0,
1432     .options = options,
1433     .namespace_id = 0,
1434     .session_cb_vft = &dummy_session_cbs,
1435     .name = format (0, "session_test"),
1436   };
1437
1438   attach_args.api_client_index = dummy_server_api_index;
1439   error = vnet_application_attach (&attach_args);
1440   SESSION_TEST ((error == 0), "server attachment should work");
1441   server_index = attach_args.app_index;
1442
1443   if (verbose)
1444     {
1445       unformat_init_string (&tmp_input, show_listeners,
1446                             strlen (show_listeners));
1447       vlib_cli_input (vm, &tmp_input, 0, 0);
1448       unformat_init_string (&tmp_input, show_local_listeners,
1449                             strlen (show_local_listeners));
1450       vlib_cli_input (vm, &tmp_input, 0, 0);
1451     }
1452
1453   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
1454                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
1455   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
1456                 "successful");
1457   sst = session_type_from_proto_and_ip (TRANSPORT_PROTO_TCP, 1);
1458   s = listen_session_get (sst, tc->s_index);
1459   SESSION_TEST ((s->app_index == server_index), "lookup should return the"
1460                 " server");
1461
1462   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
1463                                       TRANSPORT_PROTO_TCP, 0, &is_filtered);
1464   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
1465                 " not work");
1466
1467   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1468   SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
1469                 " should work");
1470
1471   vnet_app_detach_args_t detach_args = {
1472     .app_index = server_index,
1473   };
1474   vnet_application_detach (&detach_args);
1475
1476   if (verbose)
1477     {
1478       unformat_init_string (&tmp_input, show_listeners,
1479                             strlen (show_listeners));
1480       vlib_cli_input (vm, &tmp_input, 0, 0);
1481       unformat_init_string (&tmp_input, show_local_listeners,
1482                             strlen (show_local_listeners));
1483       vlib_cli_input (vm, &tmp_input, 0, 0);
1484     }
1485
1486   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1487   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
1488                 "local session endpoint lookup should not work after detach");
1489   if (verbose)
1490     unformat_free (&tmp_input);
1491   vec_free (attach_args.name);
1492   return 0;
1493 }
1494
1495 static clib_error_t *
1496 session_test (vlib_main_t * vm,
1497               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1498 {
1499   int res = 0;
1500
1501   vnet_session_enable_disable (vm, 1);
1502
1503   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1504     {
1505       if (unformat (input, "basic"))
1506         res = session_test_basic (vm, input);
1507       else if (unformat (input, "namespace"))
1508         res = session_test_namespace (vm, input);
1509       else if (unformat (input, "rules-table"))
1510         res = session_test_rule_table (vm, input);
1511       else if (unformat (input, "rules"))
1512         res = session_test_rules (vm, input);
1513       else if (unformat (input, "proxy"))
1514         res = session_test_proxy (vm, input);
1515       else if (unformat (input, "all"))
1516         {
1517           if ((res = session_test_basic (vm, input)))
1518             goto done;
1519           if ((res = session_test_namespace (vm, input)))
1520             goto done;
1521           if ((res = session_test_rule_table (vm, input)))
1522             goto done;
1523           if ((res = session_test_rules (vm, input)))
1524             goto done;
1525           if ((res = session_test_proxy (vm, input)))
1526             goto done;
1527         }
1528       else
1529         break;
1530     }
1531
1532 done:
1533   if (res)
1534     return clib_error_return (0, "Session unit test failed");
1535   return 0;
1536 }
1537
1538 /* *INDENT-OFF* */
1539 VLIB_CLI_COMMAND (tcp_test_command, static) =
1540 {
1541   .path = "test session",
1542   .short_help = "internal session unit tests",
1543   .function = session_test,
1544 };
1545 /* *INDENT-ON* */
1546
1547 /*
1548  * fd.io coding-style-patch-verification: ON
1549  *
1550  * Local Variables:
1551  * eval: (c-set-style "gnu")
1552  * End:
1553  */