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