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