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