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