session: lookup/rules table improvements and cleanup
[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[SESSION_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[SESSION_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   vnet_delete_loopback_interface (sw_if_index);
500   return 0;
501 }
502
503 static int
504 session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
505 {
506   session_rules_table_t _srt, *srt = &_srt;
507   u16 lcl_port = 1234, rmt_port = 4321;
508   u32 action_index = 1, res;
509   ip4_address_t lcl_lkup, rmt_lkup;
510   clib_error_t *error;
511   int verbose = 0;
512
513   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
514     {
515       if (unformat (input, "verbose"))
516         verbose = 1;
517       else
518         {
519           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
520                            input);
521           return -1;
522         }
523     }
524
525   memset (srt, 0, sizeof (*srt));
526   session_rules_table_init (srt);
527
528   ip4_address_t lcl_ip = {
529     .as_u32 = clib_host_to_net_u32 (0x01020304),
530   };
531   ip4_address_t rmt_ip = {
532     .as_u32 = clib_host_to_net_u32 (0x05060708),
533   };
534   ip4_address_t lcl_ip2 = {
535     .as_u32 = clib_host_to_net_u32 (0x02020202),
536   };
537   ip4_address_t rmt_ip2 = {
538     .as_u32 = clib_host_to_net_u32 (0x06060606),
539   };
540   ip4_address_t lcl_ip3 = {
541     .as_u32 = clib_host_to_net_u32 (0x03030303),
542   };
543   ip4_address_t rmt_ip3 = {
544     .as_u32 = clib_host_to_net_u32 (0x07070707),
545   };
546   fib_prefix_t lcl_pref = {
547     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
548     .fp_len = 16,
549     .fp_proto = FIB_PROTOCOL_IP4,
550   };
551   fib_prefix_t rmt_pref = {
552     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
553     .fp_len = 16,
554     .fp_proto = FIB_PROTOCOL_IP4,
555   };
556
557   session_rule_table_add_del_args_t args = {
558     .lcl = lcl_pref,
559     .rmt = rmt_pref,
560     .lcl_port = lcl_port,
561     .rmt_port = rmt_port,
562     .action_index = action_index++,
563     .is_add = 1,
564   };
565   error = session_rules_table_add_del (srt, &args);
566   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
567                 action_index - 1);
568
569   res =
570     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
571   SESSION_TEST ((res == 1),
572                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
573                 res);
574
575   /*
576    * 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
577    */
578   args.lcl.fp_addr.ip4 = lcl_ip;
579   args.lcl.fp_len = 24;
580   args.action_index = action_index++;
581   error = session_rules_table_add_del (srt, &args);
582   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
583                 action_index - 1);
584   args.rmt.fp_addr.ip4 = rmt_ip;
585   args.rmt.fp_len = 24;
586   args.action_index = action_index++;
587   error = session_rules_table_add_del (srt, &args);
588   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
589                 action_index - 1);
590
591   /*
592    * 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
593    */
594   args.lcl.fp_addr.ip4 = lcl_ip2;
595   args.lcl.fp_len = 24;
596   args.rmt.fp_addr.ip4 = rmt_ip2;
597   args.rmt.fp_len = 16;
598   args.action_index = action_index++;
599   error = session_rules_table_add_del (srt, &args);
600   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
601                 action_index - 1);
602   args.lcl.fp_addr.ip4 = lcl_ip3;
603   args.rmt.fp_addr.ip4 = rmt_ip3;
604   args.action_index = action_index++;
605   error = session_rules_table_add_del (srt, &args);
606   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
607                 action_index - 1);
608
609   /*
610    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
611    */
612   args.lcl.fp_addr.ip4 = lcl_ip3;
613   args.rmt.fp_addr.ip4 = rmt_ip3;
614   args.action_index = action_index++;
615   error = session_rules_table_add_del (srt, &args);
616   SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
617                 "action %d", action_index - 1);
618
619   /*
620    * 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
621    * and  3.3.3.3 1234 7.7.7.7 4321
622    */
623   res =
624     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
625   SESSION_TEST ((res == 3),
626                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
627                 res);
628
629   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
630   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
631   res =
632     session_rules_table_lookup4 (srt, &lcl_lkup,
633                                  &rmt_lkup, lcl_port, rmt_port);
634   SESSION_TEST ((res == 1),
635                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
636                 res);
637
638   res =
639     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
640   SESSION_TEST ((res == 6),
641                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
642                 "should be 6 (updated): %d", res);
643
644   /*
645    * Add 1.2.3.4/24 * 5.6.7.8/24 *
646    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
647    */
648   args.lcl.fp_addr.ip4 = lcl_ip;
649   args.rmt.fp_addr.ip4 = rmt_ip;
650   args.lcl.fp_len = 24;
651   args.rmt.fp_len = 24;
652   args.lcl_port = 0;
653   args.rmt_port = 0;
654   args.action_index = action_index++;
655   error = session_rules_table_add_del (srt, &args);
656   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
657                 action_index - 1);
658   res =
659     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
660   SESSION_TEST ((res == 7),
661                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
662                 " be 7 (lpm dst): %d", res);
663   res =
664     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
665                                  lcl_port + 1, rmt_port);
666   SESSION_TEST ((res == 7),
667                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
668                 res);
669
670   /*
671    * Del 1.2.3.4/24 * 5.6.7.8/24 *
672    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
673    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
674    * 1.2.3.4 1235 5.6.7.8 4322
675    */
676   args.is_add = 0;
677   error = session_rules_table_add_del (srt, &args);
678   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
679
680   args.lcl.fp_addr.ip4 = lcl_ip;
681   args.rmt.fp_addr.ip4 = rmt_ip;
682   args.lcl.fp_len = 16;
683   args.rmt.fp_len = 16;
684   args.lcl_port = 0;
685   args.rmt_port = 0;
686   args.action_index = action_index++;
687   args.is_add = 1;
688   error = session_rules_table_add_del (srt, &args);
689   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
690                 action_index - 1);
691
692   args.lcl.fp_addr.ip4 = lcl_ip;
693   args.rmt.fp_addr.ip4 = rmt_ip;
694   args.lcl.fp_len = 24;
695   args.rmt.fp_len = 24;
696   args.lcl_port = lcl_port + 1;
697   args.rmt_port = rmt_port;
698   args.action_index = action_index++;
699   args.is_add = 1;
700   error = session_rules_table_add_del (srt, &args);
701   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
702                 action_index - 1);
703
704   if (verbose)
705     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
706
707   res =
708     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
709   SESSION_TEST ((res == 3),
710                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
711                 res);
712   res =
713     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
714                                  lcl_port + 1, rmt_port);
715   SESSION_TEST ((res == 9),
716                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
717                 res);
718   res =
719     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
720                                  lcl_port + 1, rmt_port + 1);
721   SESSION_TEST ((res == 8),
722                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
723                 res);
724
725   /*
726    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
727    * Lookup 1.2.3.4 1234 5.6.7.8 4321
728    */
729   args.lcl_port = 1234;
730   args.rmt_port = 4321;
731   args.lcl.fp_len = 16;
732   args.rmt.fp_len = 16;
733   args.is_add = 0;
734   error = session_rules_table_add_del (srt, &args);
735   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
736   res =
737     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
738   SESSION_TEST ((res == 3),
739                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
740                 res);
741
742   args.lcl_port = 0;
743   args.rmt_port = 0;
744   args.is_add = 0;
745   error = session_rules_table_add_del (srt, &args);
746   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
747   res =
748     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
749   SESSION_TEST ((res == 3),
750                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
751                 res);
752
753   /*
754    * Delete 1.2.3.4/24 1234 5.6.7.5/24
755    */
756   args.lcl.fp_addr.ip4 = lcl_ip;
757   args.rmt.fp_addr.ip4 = rmt_ip;
758   args.lcl.fp_len = 24;
759   args.rmt.fp_len = 24;
760   args.lcl_port = 1234;
761   args.rmt_port = 4321;
762   args.is_add = 0;
763   error = session_rules_table_add_del (srt, &args);
764   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
765   res =
766     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
767   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
768
769   return 0;
770 }
771
772 static int
773 session_test_rules (vlib_main_t * vm, unformat_input_t * input)
774 {
775   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
776   u64 options[SESSION_OPTIONS_N_OPTIONS];
777   u16 lcl_port = 1234, rmt_port = 4321;
778   u32 server_index, app_index;
779   u32 dummy_server_api_index = ~0;
780   transport_connection_t *tc;
781   u32 dummy_port = 1111;
782   clib_error_t *error = 0;
783   u8 segment_name[128];
784   stream_session_t *listener, *s;
785   app_namespace_t *default_ns = app_namespace_get_default ();
786   u32 local_ns_index = default_ns->local_table_index;
787   int verbose = 0;
788
789   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
790     {
791       if (unformat (input, "verbose"))
792         verbose = 1;
793       else
794         {
795           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
796                            input);
797           return -1;
798         }
799     }
800
801   server_sep.is_ip4 = 1;
802   server_sep.port = dummy_port;
803   memset (options, 0, sizeof (options));
804
805   vnet_app_attach_args_t attach_args = {
806     .api_client_index = ~0,
807     .options = options,
808     .namespace_id = 0,
809     .session_cb_vft = &dummy_session_cbs,
810     .segment_name = segment_name,
811   };
812
813   vnet_bind_args_t bind_args = {
814     .sep = server_sep,
815     .app_index = 0,
816   };
817
818   /*
819    * Attach server with global and local default scope
820    */
821   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
822   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
823   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
824   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
825   attach_args.namespace_id = 0;
826   attach_args.api_client_index = dummy_server_api_index;
827   error = vnet_application_attach (&attach_args);
828   SESSION_TEST ((error == 0), "server attached");
829   server_index = attach_args.app_index;
830
831   bind_args.app_index = server_index;
832   error = vnet_bind (&bind_args);
833   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
834                 &server_sep.ip, 1, server_sep.port);
835   listener = listen_session_get_from_handle (bind_args.handle);
836   ip4_address_t lcl_ip = {
837     .as_u32 = clib_host_to_net_u32 (0x01020304),
838   };
839   ip4_address_t rmt_ip = {
840     .as_u32 = clib_host_to_net_u32 (0x05060708),
841   };
842   fib_prefix_t lcl_pref = {
843     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
844     .fp_len = 16,
845     .fp_proto = FIB_PROTOCOL_IP4,
846   };
847   fib_prefix_t rmt_pref = {
848     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
849     .fp_len = 16,
850     .fp_proto = FIB_PROTOCOL_IP4,
851   };
852
853   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
854                                       &rmt_pref.fp_addr.ip4, lcl_port,
855                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
856   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
857
858   /*
859    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
860    */
861   session_rule_add_del_args_t args = {
862     .table_args.lcl = lcl_pref,
863     .table_args.rmt = rmt_pref,
864     .table_args.lcl_port = lcl_port,
865     .table_args.rmt_port = rmt_port,
866     .table_args.action_index = server_index,
867     .table_args.is_add = 1,
868     .appns_index = 0,
869   };
870   error = vnet_session_rule_add_del (&args);
871   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
872                 args.table_args.action_index);
873
874   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
875                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
876                                    TRANSPORT_PROTO_TCP);
877   SESSION_TEST ((tc->c_index == listener->connection_index),
878                 "optimized lookup should return the listener");
879   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
880                                       &rmt_pref.fp_addr.ip4, lcl_port,
881                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
882   SESSION_TEST ((tc->c_index == listener->connection_index),
883                 "lookup should return the listener");
884   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
885                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
886   SESSION_TEST ((s->connection_index == listener->connection_index),
887                 "safe lookup should return the listener");
888   session_endpoint_t sep = {
889     .ip = rmt_pref.fp_addr,
890     .is_ip4 = 1,
891     .port = rmt_port,
892     .transport_proto = TRANSPORT_PROTO_TCP,
893   };
894   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
895   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
896                 "should not work (global scope)");
897
898   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
899                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
900                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
901   SESSION_TEST ((tc == 0),
902                 "optimized lookup for wrong lcl port + 1 should not work");
903
904   /*
905    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
906    */
907   args.table_args.lcl_port = 0;
908   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
909   error = vnet_session_rule_add_del (&args);
910   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
911                 args.table_args.action_index);
912   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
913                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
914                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
915   SESSION_TEST ((tc->c_index == listener->connection_index),
916                 "optimized lookup for lcl port + 1 should work");
917   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
918   SESSION_TEST ((app_index == server_index), "local session endpoint lookup "
919                 "should work (lcl ip was zeroed)");
920
921   /*
922    * Add deny rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
923    */
924   args.table_args.lcl_port = 1234;
925   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
926   args.table_args.lcl.fp_len = 32;
927   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
928   args.table_args.rmt.fp_len = 32;
929   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
930   error = vnet_session_rule_add_del (&args);
931   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
932                 args.table_args.action_index);
933
934   if (verbose)
935     {
936       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
937                                        TRANSPORT_PROTO_TCP);
938       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
939                                              TRANSPORT_PROTO_TCP);
940     }
941
942   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
943                                       &rmt_pref.fp_addr.ip4, lcl_port,
944                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
945   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
946                 "should fail (deny rule)");
947   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
948   SESSION_TEST ((app_index == APP_DROP_INDEX), "lookup for 1.2.3.4/32 1234 "
949                 "5.6.7.8/16 4321 in local table should return deny");
950   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
951                                       &rmt_pref.fp_addr.ip4, lcl_port,
952                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
953   SESSION_TEST ((tc == 0),
954                 "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 should not work");
955   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
956                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
957                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
958   SESSION_TEST ((tc->c_index == listener->connection_index),
959                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should work");
960
961   /*
962    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
963    */
964   args.table_args.lcl_port = 0;
965   args.table_args.lcl.fp_len = 0;
966   args.table_args.rmt.fp_len = 16;
967   args.table_args.action_index = -1;
968   error = vnet_session_rule_add_del (&args);
969   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
970                 args.table_args.action_index);
971
972   if (verbose)
973     {
974       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
975                                        TRANSPORT_PROTO_TCP);
976       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
977                                              TRANSPORT_PROTO_TCP);
978     }
979
980   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
981   SESSION_TEST ((app_index == APP_DROP_INDEX),
982                 "local session endpoint lookup " "should return deny");
983
984   /*
985    * Delete 1.2.3.4/32 1234 5.6.7.8/32 4321 deny
986    */
987   args.table_args.is_add = 0;
988   args.table_args.lcl_port = 1234;
989   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
990   args.table_args.lcl.fp_len = 32;
991   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
992   args.table_args.rmt.fp_len = 32;
993   error = vnet_session_rule_add_del (&args);
994   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
995
996   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
997   SESSION_TEST ((app_index == APP_INVALID_INDEX),
998                 "local session endpoint lookup should return invalid");
999
1000   /*
1001    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
1002    * 1.2.3.4/16 1234 5.6.7.8/16 4321
1003    */
1004   args.table_args.is_add = 0;
1005   args.table_args.lcl_port = 0;
1006   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1007   args.table_args.lcl.fp_len = 0;
1008   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1009   args.table_args.rmt.fp_len = 16;
1010   args.table_args.rmt_port = 4321;
1011   error = vnet_session_rule_add_del (&args);
1012   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
1013   app_index = session_lookup_local_endpoint (local_ns_index, &sep);
1014   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
1015                 "should not work (removed)");
1016
1017   args.table_args.is_add = 0;
1018   args.table_args.lcl = lcl_pref;
1019
1020   args.table_args.is_add = 0;
1021   args.table_args.lcl_port = 0;
1022   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1023   args.table_args.lcl.fp_len = 16;
1024   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1025   args.table_args.rmt.fp_len = 16;
1026   args.table_args.rmt_port = 4321;
1027   error = vnet_session_rule_add_del (&args);
1028   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
1029   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1030                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
1031                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1032   SESSION_TEST ((tc == 0),
1033                 "lookup 1.2.3.4/32 123*5* 5.6.7.8/16 4321 should not "
1034                 "work (del)");
1035
1036   args.table_args.is_add = 0;
1037   args.table_args.lcl_port = 1234;
1038   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1039   args.table_args.lcl.fp_len = 16;
1040   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1041   args.table_args.rmt.fp_len = 16;
1042   args.table_args.rmt_port = 4321;
1043   error = vnet_session_rule_add_del (&args);
1044   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
1045   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1046                                       &rmt_pref.fp_addr.ip4, lcl_port,
1047                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1048   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should "
1049                 "not work (del + deny)");
1050
1051   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny");
1052   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1053                                       &rmt_pref.fp_addr.ip4, lcl_port,
1054                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1055   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should"
1056                 " not work (no-rule)");
1057
1058   /*
1059    * Test tags. Add/del rule with tag
1060    */
1061   args.table_args.is_add = 1;
1062   args.table_args.lcl_port = 1234;
1063   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1064   args.table_args.lcl.fp_len = 16;
1065   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1066   args.table_args.rmt.fp_len = 16;
1067   args.table_args.rmt_port = 4321;
1068   args.table_args.tag = format (0, "test_rule");
1069   args.table_args.action_index = server_index;
1070   error = vnet_session_rule_add_del (&args);
1071   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 deny "
1072                 "tag test_rule");
1073   if (verbose)
1074     {
1075       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1076                                        TRANSPORT_PROTO_TCP);
1077       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1078                                              TRANSPORT_PROTO_TCP);
1079     }
1080   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1081                                       &rmt_pref.fp_addr.ip4, lcl_port,
1082                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1083   SESSION_TEST ((tc->c_index == listener->connection_index),
1084                 "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should work");
1085
1086   args.table_args.is_add = 0;
1087   args.table_args.lcl_port += 1;
1088   error = vnet_session_rule_add_del (&args);
1089   if (verbose)
1090     {
1091       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1092                                        TRANSPORT_PROTO_TCP);
1093       session_lookup_dump_local_rules_table (local_ns_index, FIB_PROTOCOL_IP4,
1094                                              TRANSPORT_PROTO_TCP);
1095     }
1096   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 deny "
1097                 "tag test_rule");
1098   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1099                                       &rmt_pref.fp_addr.ip4, lcl_port,
1100                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1101   SESSION_TEST ((tc == 0), "lookup 1.2.3.4/32 1234 5.6.7.8/16 4321 should not"
1102                 " work (del)");
1103   vec_free (args.table_args.tag);
1104   vnet_app_detach_args_t detach_args = {
1105     .app_index = server_index,
1106   };
1107   vnet_application_detach (&detach_args);
1108   return 0;
1109 }
1110
1111 static int
1112 session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
1113 {
1114   u64 options[SESSION_OPTIONS_N_OPTIONS];
1115   u32 server_index, app_index;
1116   u32 dummy_server_api_index = ~0, sw_if_index = 0;
1117   clib_error_t *error = 0;
1118   u8 segment_name[128], intf_mac[6], sst;
1119   stream_session_t *s;
1120   transport_connection_t *tc;
1121   u16 lcl_port = 1234, rmt_port = 4321;
1122   app_namespace_t *app_ns;
1123   int verbose = 0;
1124
1125   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1126     {
1127       if (unformat (input, "verbose"))
1128         verbose = 1;
1129       else
1130         {
1131           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1132                            input);
1133           return -1;
1134         }
1135     }
1136
1137   ip4_address_t lcl_ip = {
1138     .as_u32 = clib_host_to_net_u32 (0x01020304),
1139   };
1140   ip4_address_t rmt_ip = {
1141     .as_u32 = clib_host_to_net_u32 (0x05060708),
1142   };
1143   fib_prefix_t rmt_pref = {
1144     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1145     .fp_len = 16,
1146     .fp_proto = FIB_PROTOCOL_IP4,
1147   };
1148   session_endpoint_t sep = {
1149     .ip = rmt_pref.fp_addr,
1150     .is_ip4 = 1,
1151     .port = rmt_port,
1152     .transport_proto = TRANSPORT_PROTO_TCP,
1153   };
1154
1155   /*
1156    * Create loopback interface
1157    */
1158   memset (intf_mac, 0, sizeof (intf_mac));
1159   if (vnet_create_loopback_interface (&sw_if_index, intf_mac, 0, 0))
1160     {
1161       clib_warning ("couldn't create loopback. stopping the test!");
1162       return 0;
1163     }
1164   vnet_sw_interface_set_flags (vnet_get_main (), sw_if_index,
1165                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1166   ip4_add_del_interface_address (vlib_get_main (), sw_if_index, &lcl_ip,
1167                                  24, 0);
1168
1169   app_ns = app_namespace_get_default ();
1170   app_ns->sw_if_index = sw_if_index;
1171
1172   memset (options, 0, sizeof (options));
1173   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
1174   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
1175   options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
1176   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1177   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1178   vnet_app_attach_args_t attach_args = {
1179     .api_client_index = ~0,
1180     .options = options,
1181     .namespace_id = 0,
1182     .session_cb_vft = &dummy_session_cbs,
1183     .segment_name = segment_name,
1184   };
1185
1186   attach_args.api_client_index = dummy_server_api_index;
1187   error = vnet_application_attach (&attach_args);
1188   SESSION_TEST ((error == 0), "server attachment should work");
1189   server_index = attach_args.app_index;
1190
1191   if (verbose)
1192     session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1193                                      TRANSPORT_PROTO_TCP);
1194
1195   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
1196                                       TRANSPORT_PROTO_TCP, 0);
1197   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
1198                 "successful");
1199   sst = session_type_from_proto_and_ip (TRANSPORT_PROTO_TCP, 1);
1200   s = listen_session_get (sst, tc->s_index);
1201   SESSION_TEST ((s->app_index == server_index), "lookup should return the"
1202                 " server");
1203
1204   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
1205                                       TRANSPORT_PROTO_TCP, 0);
1206   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
1207                 " not work");
1208
1209   if (verbose)
1210     session_lookup_dump_local_rules_table (app_ns->local_table_index,
1211                                            FIB_PROTOCOL_IP4,
1212                                            TRANSPORT_PROTO_TCP);
1213   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1214   SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
1215                 " should work");
1216
1217   vnet_app_detach_args_t detach_args = {
1218     .app_index = server_index,
1219   };
1220   vnet_application_detach (&detach_args);
1221
1222   if (verbose)
1223     session_lookup_dump_local_rules_table (app_ns->local_table_index,
1224                                            FIB_PROTOCOL_IP4,
1225                                            TRANSPORT_PROTO_TCP);
1226
1227   app_index = session_lookup_local_endpoint (app_ns->local_table_index, &sep);
1228   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
1229                 "local session endpoint lookup should not work after detach");
1230
1231   return 0;
1232 }
1233
1234 static clib_error_t *
1235 session_test (vlib_main_t * vm,
1236               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1237 {
1238   int res = 0;
1239
1240   vnet_session_enable_disable (vm, 1);
1241
1242   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1243     {
1244       if (unformat (input, "basic"))
1245         res = session_test_basic (vm, input);
1246       else if (unformat (input, "namespace"))
1247         res = session_test_namespace (vm, input);
1248       else if (unformat (input, "rules-table"))
1249         res = session_test_rule_table (vm, input);
1250       else if (unformat (input, "rules"))
1251         res = session_test_rules (vm, input);
1252       else if (unformat (input, "proxy"))
1253         res = session_test_proxy (vm, input);
1254       else if (unformat (input, "all"))
1255         {
1256           if ((res = session_test_basic (vm, input)))
1257             goto done;
1258           if ((res = session_test_namespace (vm, input)))
1259             goto done;
1260           if ((res = session_test_rule_table (vm, input)))
1261             goto done;
1262           if ((res = session_test_rules (vm, input)))
1263             goto done;
1264           if ((res = session_test_proxy (vm, input)))
1265             goto done;
1266         }
1267       else
1268         break;
1269     }
1270
1271 done:
1272   if (res)
1273     return clib_error_return (0, "Session unit test failed");
1274   return 0;
1275 }
1276
1277 /* *INDENT-OFF* */
1278 VLIB_CLI_COMMAND (tcp_test_command, static) =
1279 {
1280   .path = "test session",
1281   .short_help = "internal session unit tests",
1282   .function = session_test,
1283 };
1284 /* *INDENT-ON* */
1285
1286 /*
1287  * fd.io coding-style-patch-verification: ON
1288  *
1289  * Local Variables:
1290  * eval: (c-set-style "gnu")
1291  * End:
1292  */