56d40b81ef8deb463e96fc199bf0fbba31132eaa
[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_session_endpoint (server_local_st_index,
333                                            &server_sep);
334   SESSION_TEST ((local_listener != SESSION_INVALID_INDEX),
335                 "listener should exist in local table");
336
337   /*
338    * Try client connect with 1) local scope 2) global scope
339    */
340   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
341   attach_args.api_client_index = dummy_client_api_index;
342   error = vnet_application_attach (&attach_args);
343   SESSION_TEST ((error == 0), "client attachment should work");
344   client_index = attach_args.app_index;
345   connect_args.api_context = dummy_api_context;
346   connect_args.app_index = client_index;
347   error = vnet_connect (&connect_args);
348   SESSION_TEST ((error != 0), "client connect should return error code");
349   code = clib_error_get_code (error);
350   SESSION_TEST ((code == VNET_API_ERROR_INVALID_VALUE),
351                 "error code should be invalid value (zero ip)");
352   connect_args.sep.ip.ip4.as_u8[0] = 127;
353   error = vnet_connect (&connect_args);
354   SESSION_TEST ((error != 0), "client connect should return error code");
355   code = clib_error_get_code (error);
356   SESSION_TEST ((code == VNET_API_ERROR_SESSION_REDIRECT),
357                 "error code should be redirect");
358   detach_args.app_index = client_index;
359   vnet_application_detach (&detach_args);
360
361   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
362   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
363   attach_args.api_client_index = dummy_client_api_index;
364   error = vnet_application_attach (&attach_args);
365   SESSION_TEST ((error == 0), "client attachment should work");
366   error = vnet_connect (&connect_args);
367   SESSION_TEST ((error != 0), "client connect should return error code");
368   code = clib_error_get_code (error);
369   SESSION_TEST ((code == VNET_API_ERROR_SESSION_CONNECT),
370                 "error code should be connect (nothing in local scope)");
371   detach_args.app_index = client_index;
372   vnet_application_detach (&detach_args);
373
374   /*
375    * Unbind and detach server and then re-attach with local scope only
376    */
377   unbind_args.handle = bind_args.handle;
378   unbind_args.app_index = server_index;
379   error = vnet_unbind (&unbind_args);
380   SESSION_TEST ((error == 0), "unbind should work");
381
382   s = session_lookup_listener (server_st_index, &server_sep);
383   SESSION_TEST ((s == 0), "listener should not exist in global table");
384   local_listener =
385     session_lookup_local_session_endpoint (server_local_st_index,
386                                            &server_sep);
387   SESSION_TEST ((s == 0), "listener should not exist in local table");
388
389   detach_args.app_index = server_index;
390   vnet_application_detach (&detach_args);
391
392   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
393   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
394   attach_args.api_client_index = dummy_server_api_index;
395   error = vnet_application_attach (&attach_args);
396   SESSION_TEST ((error == 0), "app attachment should work");
397   server_index = attach_args.app_index;
398   server = application_get (server_index);
399   SESSION_TEST ((server->ns_index == app_namespace_index (app_ns)),
400                 "app should be in the right ns");
401
402   bind_args.app_index = server_index;
403   error = vnet_bind (&bind_args);
404   SESSION_TEST ((error == 0), "bind should work");
405
406   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
407   s = session_lookup_listener (server_st_index, &server_sep);
408   SESSION_TEST ((s == 0), "listener should not exist in global table");
409   server_local_st_index = application_local_session_table (server);
410   local_listener =
411     session_lookup_local_session_endpoint (server_local_st_index,
412                                            &server_sep);
413   SESSION_TEST ((local_listener != SESSION_INVALID_INDEX),
414                 "listener should exist in local table");
415
416   unbind_args.handle = bind_args.handle;
417   error = vnet_unbind (&unbind_args);
418   SESSION_TEST ((error == 0), "unbind should work");
419
420   local_listener =
421     session_lookup_local_session_endpoint (server_local_st_index,
422                                            &server_sep);
423   SESSION_TEST ((local_listener == SESSION_INVALID_INDEX),
424                 "listener should not exist in local table");
425
426   /*
427    * Client attach + connect in default ns with local scope
428    */
429   options[APP_OPTIONS_FLAGS] &= ~APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
430   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
431   attach_args.namespace_id = 0;
432   attach_args.api_client_index = dummy_client_api_index;
433   vnet_application_attach (&attach_args);
434   error = vnet_connect (&connect_args);
435   SESSION_TEST ((error != 0), "client connect should return error code");
436   code = clib_error_get_code (error);
437   SESSION_TEST ((code == VNET_API_ERROR_SESSION_CONNECT),
438                 "error code should be connect (not in same ns)");
439   detach_args.app_index = client_index;
440   vnet_application_detach (&detach_args);
441
442   /*
443    * Detach server
444    */
445   detach_args.app_index = server_index;
446   vnet_application_detach (&detach_args);
447
448   /*
449    * Create loopback interface
450    */
451   if (vnet_create_loopback_interface (&sw_if_index, intf_mac, 0, 0))
452     {
453       clib_warning ("couldn't create loopback. stopping the test!");
454       return 0;
455     }
456   vnet_sw_interface_set_flags (vnet_get_main (), sw_if_index,
457                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
458   ip4_add_del_interface_address (vlib_get_main (), sw_if_index, &intf_addr,
459                                  24, 0);
460
461   /*
462    * Update namespace
463    */
464   ns_args.sw_if_index = sw_if_index;
465   error = vnet_app_namespace_add_del (&ns_args);
466   SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
467                 clib_error_get_code (error));
468
469   /*
470    * Attach server with local and global scope
471    */
472   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
473   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
474   options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
475   attach_args.namespace_id = ns_id;
476   attach_args.api_client_index = dummy_server_api_index;
477   error = vnet_application_attach (&attach_args);
478   SESSION_TEST ((error == 0), "server attachment should work");
479   server_index = attach_args.app_index;
480
481   bind_args.app_index = server_index;
482   error = vnet_bind (&bind_args);
483   server_st_index = application_session_table (server, FIB_PROTOCOL_IP4);
484   s = session_lookup_listener (server_st_index, &server_sep);
485   SESSION_TEST ((s == 0), "zero listener should not exist in global table");
486
487   s = session_lookup_listener (server_st_index, &intf_sep);
488   SESSION_TEST ((s != 0), "intf listener should exist in global table");
489   SESSION_TEST ((s->app_index == server_index), "app_index should be that of "
490                 "the server");
491   server_local_st_index = application_local_session_table (server);
492   local_listener =
493     session_lookup_local_session_endpoint (server_local_st_index,
494                                            &server_sep);
495   SESSION_TEST ((local_listener != SESSION_INVALID_INDEX),
496                 "zero listener should exist in local table");
497   detach_args.app_index = server_index;
498   vnet_application_detach (&detach_args);
499
500   /*
501    * Cleanup
502    */
503   vec_free (ns_id);
504   vnet_delete_loopback_interface (sw_if_index);
505   return 0;
506 }
507
508 static int
509 session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
510 {
511   session_rules_table_t _srt, *srt = &_srt;
512   u16 lcl_port = 1234, rmt_port = 4321;
513   u32 action_index = 1, res;
514   ip4_address_t lcl_lkup, rmt_lkup;
515   clib_error_t *error;
516   int verbose = 0;
517
518   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
519     {
520       if (unformat (input, "verbose"))
521         verbose = 1;
522       else
523         {
524           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
525                            input);
526           return -1;
527         }
528     }
529
530   memset (srt, 0, sizeof (*srt));
531   session_rules_table_init (srt);
532
533   ip4_address_t lcl_ip = {
534     .as_u32 = clib_host_to_net_u32 (0x01020304),
535   };
536   ip4_address_t rmt_ip = {
537     .as_u32 = clib_host_to_net_u32 (0x05060708),
538   };
539   ip4_address_t lcl_ip2 = {
540     .as_u32 = clib_host_to_net_u32 (0x02020202),
541   };
542   ip4_address_t rmt_ip2 = {
543     .as_u32 = clib_host_to_net_u32 (0x06060606),
544   };
545   ip4_address_t lcl_ip3 = {
546     .as_u32 = clib_host_to_net_u32 (0x03030303),
547   };
548   ip4_address_t rmt_ip3 = {
549     .as_u32 = clib_host_to_net_u32 (0x07070707),
550   };
551   fib_prefix_t lcl_pref = {
552     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
553     .fp_len = 16,
554     .fp_proto = FIB_PROTOCOL_IP4,
555   };
556   fib_prefix_t rmt_pref = {
557     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
558     .fp_len = 16,
559     .fp_proto = FIB_PROTOCOL_IP4,
560   };
561
562   session_rule_table_add_del_args_t args = {
563     .lcl = lcl_pref,
564     .rmt = rmt_pref,
565     .lcl_port = lcl_port,
566     .rmt_port = rmt_port,
567     .action_index = action_index++,
568     .is_add = 1,
569   };
570   error = session_rules_table_add_del (srt, &args);
571   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
572                 action_index - 1);
573
574   res =
575     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
576   SESSION_TEST ((res == 1),
577                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
578                 res);
579
580   /*
581    * 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
582    */
583   args.lcl.fp_addr.ip4 = lcl_ip;
584   args.lcl.fp_len = 24;
585   args.action_index = action_index++;
586   error = session_rules_table_add_del (srt, &args);
587   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
588                 action_index - 1);
589   args.rmt.fp_addr.ip4 = rmt_ip;
590   args.rmt.fp_len = 24;
591   args.action_index = action_index++;
592   error = session_rules_table_add_del (srt, &args);
593   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
594                 action_index - 1);
595
596   /*
597    * 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
598    */
599   args.lcl.fp_addr.ip4 = lcl_ip2;
600   args.lcl.fp_len = 24;
601   args.rmt.fp_addr.ip4 = rmt_ip2;
602   args.rmt.fp_len = 16;
603   args.action_index = action_index++;
604   error = session_rules_table_add_del (srt, &args);
605   SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
606                 action_index - 1);
607   args.lcl.fp_addr.ip4 = lcl_ip3;
608   args.rmt.fp_addr.ip4 = rmt_ip3;
609   args.action_index = action_index++;
610   error = session_rules_table_add_del (srt, &args);
611   SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
612                 action_index - 1);
613
614   /*
615    * Add again 3.3.3.3/24 1234 7.7.7.7/16 4321
616    */
617   args.lcl.fp_addr.ip4 = lcl_ip3;
618   args.rmt.fp_addr.ip4 = rmt_ip3;
619   args.action_index = action_index++;
620   error = session_rules_table_add_del (srt, &args);
621   SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
622                 "action %d", action_index - 1);
623
624   /*
625    * 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
626    * and  3.3.3.3 1234 7.7.7.7 4321
627    */
628   res =
629     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
630   SESSION_TEST ((res == 3),
631                 "Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
632                 res);
633
634   lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
635   rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
636   res =
637     session_rules_table_lookup4 (srt, &lcl_lkup,
638                                  &rmt_lkup, lcl_port, rmt_port);
639   SESSION_TEST ((res == 1),
640                 "Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
641                 res);
642
643   res =
644     session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
645   SESSION_TEST ((res == 6),
646                 "Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
647                 "should be 6 (updated): %d", res);
648
649   /*
650    * Add 1.2.3.4/24 * 5.6.7.8/24 *
651    * Lookup 1.2.3.4 1234 5.6.7.8 4321 and 1.2.3.4 1235 5.6.7.8 4321
652    */
653   args.lcl.fp_addr.ip4 = lcl_ip;
654   args.rmt.fp_addr.ip4 = rmt_ip;
655   args.lcl.fp_len = 24;
656   args.rmt.fp_len = 24;
657   args.lcl_port = 0;
658   args.rmt_port = 0;
659   args.action_index = action_index++;
660   error = session_rules_table_add_del (srt, &args);
661   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
662                 action_index - 1);
663   res =
664     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
665   SESSION_TEST ((res == 7),
666                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
667                 " be 7 (lpm dst): %d", res);
668   res =
669     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
670                                  lcl_port + 1, rmt_port);
671   SESSION_TEST ((res == 7),
672                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
673                 res);
674
675   /*
676    * Del 1.2.3.4/24 * 5.6.7.8/24 *
677    * Add 1.2.3.4/16 * 5.6.7.8/16 * and 1.2.3.4/24 1235 5.6.7.8/24 4321
678    * Lookup 1.2.3.4 1234 5.6.7.8 4321, 1.2.3.4 1235 5.6.7.8 4321 and
679    * 1.2.3.4 1235 5.6.7.8 4322
680    */
681   args.is_add = 0;
682   error = session_rules_table_add_del (srt, &args);
683   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
684
685   args.lcl.fp_addr.ip4 = lcl_ip;
686   args.rmt.fp_addr.ip4 = rmt_ip;
687   args.lcl.fp_len = 16;
688   args.rmt.fp_len = 16;
689   args.lcl_port = 0;
690   args.rmt_port = 0;
691   args.action_index = action_index++;
692   args.is_add = 1;
693   error = session_rules_table_add_del (srt, &args);
694   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
695                 action_index - 1);
696
697   args.lcl.fp_addr.ip4 = lcl_ip;
698   args.rmt.fp_addr.ip4 = rmt_ip;
699   args.lcl.fp_len = 24;
700   args.rmt.fp_len = 24;
701   args.lcl_port = lcl_port + 1;
702   args.rmt_port = rmt_port;
703   args.action_index = action_index++;
704   args.is_add = 1;
705   error = session_rules_table_add_del (srt, &args);
706   SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
707                 action_index - 1);
708
709   if (verbose)
710     session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
711
712   res =
713     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
714   SESSION_TEST ((res == 3),
715                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
716                 res);
717   res =
718     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
719                                  lcl_port + 1, rmt_port);
720   SESSION_TEST ((res == 9),
721                 "Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
722                 res);
723   res =
724     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
725                                  lcl_port + 1, rmt_port + 1);
726   SESSION_TEST ((res == 8),
727                 "Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
728                 res);
729
730   /*
731    * Delete 1.2.0.0/16 1234 5.6.0.0/16 4321 and 1.2.0.0/16 * 5.6.0.0/16 *
732    * Lookup 1.2.3.4 1234 5.6.7.8 4321
733    */
734   args.lcl_port = 1234;
735   args.rmt_port = 4321;
736   args.lcl.fp_len = 16;
737   args.rmt.fp_len = 16;
738   args.is_add = 0;
739   error = session_rules_table_add_del (srt, &args);
740   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
741   res =
742     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
743   SESSION_TEST ((res == 3),
744                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
745                 res);
746
747   args.lcl_port = 0;
748   args.rmt_port = 0;
749   args.is_add = 0;
750   error = session_rules_table_add_del (srt, &args);
751   SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
752   res =
753     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
754   SESSION_TEST ((res == 3),
755                 "Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
756                 res);
757
758   /*
759    * Delete 1.2.3.4/24 1234 5.6.7.5/24
760    */
761   args.lcl.fp_addr.ip4 = lcl_ip;
762   args.rmt.fp_addr.ip4 = rmt_ip;
763   args.lcl.fp_len = 24;
764   args.rmt.fp_len = 24;
765   args.lcl_port = 1234;
766   args.rmt_port = 4321;
767   args.is_add = 0;
768   error = session_rules_table_add_del (srt, &args);
769   SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
770   res =
771     session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
772   SESSION_TEST ((res == 2), "Action should be 2: %d", res);
773
774   return 0;
775 }
776
777 static int
778 session_test_rules (vlib_main_t * vm, unformat_input_t * input)
779 {
780   session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
781   u64 options[SESSION_OPTIONS_N_OPTIONS];
782   u16 lcl_port = 1234, rmt_port = 4321;
783   u32 server_index, app_index;
784   u32 dummy_server_api_index = ~0;
785   transport_connection_t *tc;
786   u32 dummy_port = 1111;
787   clib_error_t *error = 0;
788   u8 segment_name[128];
789   stream_session_t *listener, *s;
790   app_namespace_t *default_ns = app_namespace_get_default ();
791   u32 local_ns_index = default_ns->local_table_index;
792   int verbose = 0;
793
794   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
795     {
796       if (unformat (input, "verbose"))
797         verbose = 1;
798       else
799         {
800           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
801                            input);
802           return -1;
803         }
804     }
805
806   server_sep.is_ip4 = 1;
807   server_sep.port = dummy_port;
808   memset (options, 0, sizeof (options));
809
810   vnet_app_attach_args_t attach_args = {
811     .api_client_index = ~0,
812     .options = options,
813     .namespace_id = 0,
814     .session_cb_vft = &dummy_session_cbs,
815     .segment_name = segment_name,
816   };
817
818   vnet_bind_args_t bind_args = {
819     .sep = server_sep,
820     .app_index = 0,
821   };
822
823   /*
824    * Attach server with global and local default scope
825    */
826   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
827   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
828   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
829   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
830   attach_args.namespace_id = 0;
831   attach_args.api_client_index = dummy_server_api_index;
832   error = vnet_application_attach (&attach_args);
833   SESSION_TEST ((error == 0), "server attached");
834   server_index = attach_args.app_index;
835
836   bind_args.app_index = server_index;
837   error = vnet_bind (&bind_args);
838   SESSION_TEST ((error == 0), "server bound to %U/%d", format_ip46_address,
839                 &server_sep.ip, 1, server_sep.port);
840   listener = listen_session_get_from_handle (bind_args.handle);
841   ip4_address_t lcl_ip = {
842     .as_u32 = clib_host_to_net_u32 (0x01020304),
843   };
844   ip4_address_t rmt_ip = {
845     .as_u32 = clib_host_to_net_u32 (0x05060708),
846   };
847   fib_prefix_t lcl_pref = {
848     .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
849     .fp_len = 16,
850     .fp_proto = FIB_PROTOCOL_IP4,
851   };
852   fib_prefix_t rmt_pref = {
853     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
854     .fp_len = 16,
855     .fp_proto = FIB_PROTOCOL_IP4,
856   };
857
858   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
859                                       &rmt_pref.fp_addr.ip4, lcl_port,
860                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
861   SESSION_TEST ((tc == 0), "optimized lookup should not work (port)");
862
863   /*
864    * Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action server_index
865    */
866   session_rule_add_del_args_t args = {
867     .table_args.lcl = lcl_pref,
868     .table_args.rmt = rmt_pref,
869     .table_args.lcl_port = lcl_port,
870     .table_args.rmt_port = rmt_port,
871     .table_args.action_index = server_index,
872     .table_args.is_add = 1,
873     .appns_index = 0,
874   };
875   error = vnet_session_rule_add_del (&args);
876   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
877                 args.table_args.action_index);
878
879   tc = session_lookup_connection4 (0, &lcl_pref.fp_addr.ip4,
880                                    &rmt_pref.fp_addr.ip4, lcl_port, rmt_port,
881                                    TRANSPORT_PROTO_TCP);
882   SESSION_TEST ((tc->c_index == listener->connection_index),
883                 "optimized lookup should return the listener");
884   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
885                                       &rmt_pref.fp_addr.ip4, lcl_port,
886                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
887   SESSION_TEST ((tc->c_index == listener->connection_index),
888                 "lookup should return the listener");
889   s = session_lookup_safe4 (0, &lcl_pref.fp_addr.ip4, &rmt_pref.fp_addr.ip4,
890                             lcl_port, rmt_port, TRANSPORT_PROTO_TCP);
891   SESSION_TEST ((s->connection_index == listener->connection_index),
892                 "safe lookup should return the listener");
893   session_endpoint_t sep = {
894     .ip = rmt_pref.fp_addr,
895     .is_ip4 = 1,
896     .port = rmt_port,
897     .transport_proto = TRANSPORT_PROTO_TCP,
898   };
899   app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
900   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
901                 "should not work (global scope)");
902
903   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
904                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
905                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
906   SESSION_TEST ((tc == 0),
907                 "optimized lookup for wrong lcl port + 1 should not work");
908
909   /*
910    * Add 1.2.3.4/16 * 5.6.7.8/16 4321
911    */
912   args.table_args.lcl_port = 0;
913   args.scope = SESSION_RULE_SCOPE_LOCAL | SESSION_RULE_SCOPE_GLOBAL;
914   error = vnet_session_rule_add_del (&args);
915   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 4321 action %d",
916                 args.table_args.action_index);
917   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
918                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
919                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
920   SESSION_TEST ((tc->c_index == listener->connection_index),
921                 "optimized lookup for lcl port + 1 should work");
922   app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
923   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
924                 "should not work (constrained lcl ip)");
925
926   /*
927    * Add drop rule 1.2.3.4/32 1234 5.6.7.8/32 4321 action -2 (drop)
928    */
929   args.table_args.lcl_port = 1234;
930   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
931   args.table_args.lcl.fp_len = 32;
932   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
933   args.table_args.rmt.fp_len = 32;
934   args.table_args.action_index = SESSION_RULES_TABLE_ACTION_DROP;
935   error = vnet_session_rule_add_del (&args);
936   SESSION_TEST ((error == 0), "Add 1.2.3.4/32 1234 5.6.7.8/32 4321 action %d",
937                 args.table_args.action_index);
938
939   if (verbose)
940     {
941       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
942                                        TRANSPORT_PROTO_TCP);
943       session_lookup_dump_local_rules_table (0, FIB_PROTOCOL_IP4,
944                                              TRANSPORT_PROTO_TCP);
945     }
946
947   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
948                                       &rmt_pref.fp_addr.ip4, lcl_port,
949                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
950   SESSION_TEST ((tc == 0), "lookup for 1.2.3.4/32 1234 5.6.7.8/16 4321 "
951                 "should fail (drop rule)");
952
953   /*
954    * Add local scope rule for 0/0 * 5.6.7.8/16 4321 action server_index
955    */
956   args.table_args.lcl_port = 0;
957   args.table_args.lcl.fp_len = 0;
958   args.table_args.rmt.fp_len = 16;
959   args.table_args.action_index = server_index;
960   error = vnet_session_rule_add_del (&args);
961   SESSION_TEST ((error == 0), "Add * * 5.6.7.8/16 4321 action %d",
962                 args.table_args.action_index);
963
964   if (verbose)
965     {
966       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
967                                        TRANSPORT_PROTO_TCP);
968       session_lookup_dump_local_rules_table (0, FIB_PROTOCOL_IP4,
969                                              TRANSPORT_PROTO_TCP);
970     }
971
972   app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
973   SESSION_TEST ((app_index == server_index), "local session endpoint lookup "
974                 "should work");
975
976   /*
977    * Delete 0/0 * 5.6.7.8/16 4321, 1.2.3.4/16 * 5.6.7.8/16 4321 and
978    * 1.2.3.4/16 1234 5.6.7.8/16 4321
979    */
980   args.table_args.is_add = 0;
981   error = vnet_session_rule_add_del (&args);
982   SESSION_TEST ((error == 0), "Del 0/0 * 5.6.7.8/16 4321");
983   app_index = session_lookup_local_session_endpoint (local_ns_index, &sep);
984   SESSION_TEST ((app_index != server_index), "local session endpoint lookup "
985                 "should not work (removed)");
986
987   args.table_args.is_add = 0;
988   args.table_args.lcl = lcl_pref;
989   error = vnet_session_rule_add_del (&args);
990   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 * 5.6.7.8/16 4321");
991   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
992                                       &rmt_pref.fp_addr.ip4, lcl_port + 1,
993                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
994   SESSION_TEST ((tc == 0), "optimized lookup for lcl port + 1 should not "
995                 "work (del)");
996
997   args.table_args.is_add = 0;
998   args.table_args.lcl_port = 1234;
999   error = vnet_session_rule_add_del (&args);
1000   SESSION_TEST ((error == 0), "Del 1.2.3.4/16 1234 5.6.7.8/16 4321");
1001   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1002                                       &rmt_pref.fp_addr.ip4, lcl_port,
1003                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1004   SESSION_TEST ((tc == 0),
1005                 "optimized lookup should not work (del + negative)");
1006
1007   args.table_args.is_add = 0;
1008   args.table_args.lcl_port = 1234;
1009   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1010   args.table_args.lcl.fp_len = 32;
1011   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1012   args.table_args.rmt.fp_len = 32;
1013   error = vnet_session_rule_add_del (&args);
1014   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 drop");
1015   tc = session_lookup_connection_wt4 (0, &lcl_pref.fp_addr.ip4,
1016                                       &rmt_pref.fp_addr.ip4, lcl_port,
1017                                       rmt_port, TRANSPORT_PROTO_TCP, 0);
1018   SESSION_TEST ((tc == 0), "optimized lookup should not work (no-rule)");
1019
1020   /*
1021    * Test tags. Add/del rule with tag
1022    */
1023   args.table_args.is_add = 1;
1024   args.table_args.lcl_port = 1234;
1025   args.table_args.lcl.fp_addr.ip4 = lcl_ip;
1026   args.table_args.lcl.fp_len = 16;
1027   args.table_args.rmt.fp_addr.ip4 = rmt_ip;
1028   args.table_args.rmt.fp_len = 16;
1029   args.table_args.tag = format (0, "test_rule");
1030   error = vnet_session_rule_add_del (&args);
1031   SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 drop "
1032                 "tag test_rule");
1033   if (verbose)
1034     {
1035       session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1036                                        TRANSPORT_PROTO_TCP);
1037       session_lookup_dump_local_rules_table (0, FIB_PROTOCOL_IP4,
1038                                              TRANSPORT_PROTO_TCP);
1039     }
1040   args.table_args.is_add = 0;
1041   args.table_args.lcl_port += 1;
1042   SESSION_TEST ((error == 0), "Del 1.2.3.4/32 1234 5.6.7.8/32 4321 drop "
1043                 "tag test_rule");
1044
1045   vnet_app_detach_args_t detach_args = {
1046     .app_index = server_index,
1047   };
1048   vnet_application_detach (&detach_args);
1049   return 0;
1050 }
1051
1052 static int
1053 session_test_proxy (vlib_main_t * vm, unformat_input_t * input)
1054 {
1055   u64 options[SESSION_OPTIONS_N_OPTIONS];
1056   u32 server_index, app_index;
1057   u32 dummy_server_api_index = ~0, sw_if_index = 0;
1058   clib_error_t *error = 0;
1059   u8 segment_name[128], intf_mac[6], sst;
1060   stream_session_t *s;
1061   transport_connection_t *tc;
1062   u16 lcl_port = 1234, rmt_port = 4321;
1063   app_namespace_t *app_ns;
1064   int verbose = 0;
1065
1066   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1067     {
1068       if (unformat (input, "verbose"))
1069         verbose = 1;
1070       else
1071         {
1072           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
1073                            input);
1074           return -1;
1075         }
1076     }
1077
1078   ip4_address_t lcl_ip = {
1079     .as_u32 = clib_host_to_net_u32 (0x01020304),
1080   };
1081   ip4_address_t rmt_ip = {
1082     .as_u32 = clib_host_to_net_u32 (0x05060708),
1083   };
1084   fib_prefix_t rmt_pref = {
1085     .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
1086     .fp_len = 16,
1087     .fp_proto = FIB_PROTOCOL_IP4,
1088   };
1089   session_endpoint_t sep = {
1090     .ip = rmt_pref.fp_addr,
1091     .is_ip4 = 1,
1092     .port = rmt_port,
1093     .transport_proto = TRANSPORT_PROTO_TCP,
1094   };
1095
1096   /*
1097    * Create loopback interface
1098    */
1099   memset (intf_mac, 0, sizeof (intf_mac));
1100   if (vnet_create_loopback_interface (&sw_if_index, intf_mac, 0, 0))
1101     {
1102       clib_warning ("couldn't create loopback. stopping the test!");
1103       return 0;
1104     }
1105   vnet_sw_interface_set_flags (vnet_get_main (), sw_if_index,
1106                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1107   ip4_add_del_interface_address (vlib_get_main (), sw_if_index, &lcl_ip,
1108                                  24, 0);
1109
1110   app_ns = app_namespace_get_default ();
1111   app_ns->sw_if_index = sw_if_index;
1112
1113   memset (options, 0, sizeof (options));
1114   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_ACCEPT_REDIRECT;
1115   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_PROXY;
1116   options[APP_OPTIONS_PROXY_TRANSPORT] = 1 << TRANSPORT_PROTO_TCP;
1117   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
1118   options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
1119   vnet_app_attach_args_t attach_args = {
1120     .api_client_index = ~0,
1121     .options = options,
1122     .namespace_id = 0,
1123     .session_cb_vft = &dummy_session_cbs,
1124     .segment_name = segment_name,
1125   };
1126
1127   attach_args.api_client_index = dummy_server_api_index;
1128   error = vnet_application_attach (&attach_args);
1129   SESSION_TEST ((error == 0), "server attachment should work");
1130   server_index = attach_args.app_index;
1131
1132   if (verbose)
1133     session_lookup_dump_rules_table (0, FIB_PROTOCOL_IP4,
1134                                      TRANSPORT_PROTO_TCP);
1135
1136   tc = session_lookup_connection_wt4 (0, &lcl_ip, &rmt_ip, lcl_port, rmt_port,
1137                                       TRANSPORT_PROTO_TCP, 0);
1138   SESSION_TEST ((tc != 0), "lookup 1.2.3.4 1234 5.6.7.8 4321 should be "
1139                 "successful");
1140   sst = session_type_from_proto_and_ip (TRANSPORT_PROTO_TCP, 1);
1141   s = listen_session_get (sst, tc->s_index);
1142   SESSION_TEST ((s->app_index == server_index), "lookup should return the"
1143                 " server");
1144
1145   tc = session_lookup_connection_wt4 (0, &rmt_ip, &rmt_ip, lcl_port, rmt_port,
1146                                       TRANSPORT_PROTO_TCP, 0);
1147   SESSION_TEST ((tc == 0), "lookup 5.6.7.8 1234 5.6.7.8 4321 should"
1148                 " not work");
1149
1150   if (verbose)
1151     session_lookup_dump_local_rules_table (app_ns->local_table_index,
1152                                            FIB_PROTOCOL_IP4,
1153                                            TRANSPORT_PROTO_TCP);
1154   app_index =
1155     session_lookup_local_session_endpoint (app_ns->local_table_index, &sep);
1156   SESSION_TEST ((app_index == server_index), "local session endpoint lookup"
1157                 " should work");
1158
1159   vnet_app_detach_args_t detach_args = {
1160     .app_index = server_index,
1161   };
1162   vnet_application_detach (&detach_args);
1163
1164   if (verbose)
1165     session_lookup_dump_local_rules_table (app_ns->local_table_index,
1166                                            FIB_PROTOCOL_IP4,
1167                                            TRANSPORT_PROTO_TCP);
1168
1169   app_index =
1170     session_lookup_local_session_endpoint (app_ns->local_table_index, &sep);
1171   SESSION_TEST ((app_index == SESSION_RULES_TABLE_INVALID_INDEX),
1172                 "local session endpoint lookup should not work after detach");
1173
1174   return 0;
1175 }
1176
1177 static clib_error_t *
1178 session_test (vlib_main_t * vm,
1179               unformat_input_t * input, vlib_cli_command_t * cmd_arg)
1180 {
1181   int res = 0;
1182
1183   vnet_session_enable_disable (vm, 1);
1184
1185   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1186     {
1187       if (unformat (input, "basic"))
1188         res = session_test_basic (vm, input);
1189       else if (unformat (input, "namespace"))
1190         res = session_test_namespace (vm, input);
1191       else if (unformat (input, "rules-table"))
1192         res = session_test_rule_table (vm, input);
1193       else if (unformat (input, "rules"))
1194         res = session_test_rules (vm, input);
1195       else if (unformat (input, "proxy"))
1196         res = session_test_proxy (vm, input);
1197       else if (unformat (input, "all"))
1198         {
1199           if ((res = session_test_basic (vm, input)))
1200             goto done;
1201           if ((res = session_test_namespace (vm, input)))
1202             goto done;
1203           if ((res = session_test_rule_table (vm, input)))
1204             goto done;
1205           if ((res = session_test_rules (vm, input)))
1206             goto done;
1207           if ((res = session_test_proxy (vm, input)))
1208             goto done;
1209         }
1210       else
1211         break;
1212     }
1213
1214 done:
1215   if (res)
1216     return clib_error_return (0, "Session unit test failed");
1217   return 0;
1218 }
1219
1220 /* *INDENT-OFF* */
1221 VLIB_CLI_COMMAND (tcp_test_command, static) =
1222 {
1223   .path = "test session",
1224   .short_help = "internal session unit tests",
1225   .function = session_test,
1226 };
1227 /* *INDENT-ON* */
1228
1229 /*
1230  * fd.io coding-style-patch-verification: ON
1231  *
1232  * Local Variables:
1233  * eval: (c-set-style "gnu")
1234  * End:
1235  */