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