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