session: extend connect api for internal apps 46/15546/11
authorFlorin Coras <fcoras@cisco.com>
Fri, 26 Oct 2018 01:03:45 +0000 (18:03 -0700)
committerDamjan Marion <dmarion@me.com>
Sun, 28 Oct 2018 14:57:26 +0000 (14:57 +0000)
Change-Id: Ie4c5cfc4c97acb321a46b4df589dc44de1b616ba
Signed-off-by: Florin Coras <fcoras@cisco.com>
18 files changed:
src/tests/vnet/session/udp_echo.c
src/vnet/sctp/sctp.c
src/vnet/session/application.c
src/vnet/session/application.h
src/vnet/session/application_interface.c
src/vnet/session/application_interface.h
src/vnet/session/session.c
src/vnet/session/session.h
src/vnet/session/session_api.c
src/vnet/session/session_test.c
src/vnet/session/stream_session.h
src/vnet/session/transport.c
src/vnet/session/transport.h
src/vnet/session/transport_interface.h
src/vnet/tcp/tcp.c
src/vnet/tls/tls.c
src/vnet/udp/udp.c
test/test_session.py

index 9ab7751..887150c 100644 (file)
@@ -275,8 +275,7 @@ unformat_ip6_address (unformat_input_t * input, va_list * args)
 uword
 unformat_uri (unformat_input_t * input, va_list * args)
 {
-  session_endpoint_extended_t *sep = va_arg (*args,
-                                            session_endpoint_extended_t *);
+  session_endpoint_cfg_t *sep = va_arg (*args, session_endpoint_cfg_t *);
   u32 port;
   char *tmp;
 
@@ -606,7 +605,7 @@ session_connected_handler (session_connected_msg_t * mp)
 {
   udp_echo_main_t *utm = &udp_echo_main;
   unformat_input_t _input, *input = &_input;
-  session_endpoint_extended_t _sep, *sep = &_sep;
+  session_endpoint_cfg_t _sep, *sep = &_sep;
   app_session_t *session;
 
   ASSERT (utm->i_am_server == 0);
index f2de34d..41548bc 100644 (file)
@@ -451,7 +451,7 @@ sctp_half_open_connection_new (u8 thread_index)
 }
 
 static inline int
-sctp_connection_open (transport_endpoint_t * rmt)
+sctp_connection_open (transport_endpoint_cfg_t * rmt)
 {
   sctp_main_t *tm = vnet_get_sctp_main ();
   sctp_connection_t *sctp_conn;
@@ -485,9 +485,9 @@ sctp_connection_open (transport_endpoint_t * rmt)
   clib_spinlock_lock_if_init (&tm->half_open_lock);
   sctp_conn = sctp_half_open_connection_new (thread_id);
   u32 mtu = rmt->is_ip4 ? vnet_sw_interface_get_mtu (vnet_get_main (),
-                                                    rmt->sw_if_index,
+                                                    rmt->peer.sw_if_index,
                                                     VNET_MTU_IP4) :
-    vnet_sw_interface_get_mtu (vnet_get_main (), rmt->sw_if_index,
+    vnet_sw_interface_get_mtu (vnet_get_main (), rmt->peer.sw_if_index,
                               VNET_MTU_IP6);
   sctp_conn->sub_conn[idx].PMTU = mtu;
 
@@ -542,7 +542,7 @@ sctp_connection_cleanup (sctp_connection_t * sctp_conn)
 }
 
 int
-sctp_session_open (transport_endpoint_t * tep)
+sctp_session_open (transport_endpoint_cfg_t * tep)
 {
   return sctp_connection_open (tep);
 }
index 90c067d..1d7b3ad 100644 (file)
@@ -715,7 +715,7 @@ app_worker_stop_listen (app_worker_t * app_wrk, session_handle_t handle)
  */
 int
 application_start_listen (application_t * app,
-                         session_endpoint_extended_t * sep_ext,
+                         session_endpoint_cfg_t * sep_ext,
                          session_handle_t * res)
 {
   app_listener_t *app_listener;
@@ -1055,7 +1055,7 @@ application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto,
 {
   app_namespace_t *app_ns = app_namespace_get (app->ns_index);
   u8 is_ip4 = (fib_proto == FIB_PROTOCOL_IP4);
-  session_endpoint_extended_t sep = SESSION_ENDPOINT_EXT_NULL;
+  session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
   transport_connection_t *tc;
   app_worker_t *app_wrk;
   stream_session_t *s;
@@ -1408,7 +1408,7 @@ application_local_listen_session_free (application_t * app,
 
 int
 application_start_local_listen (application_t * app,
-                               session_endpoint_extended_t * sep_ext,
+                               session_endpoint_cfg_t * sep_ext,
                                session_handle_t * handle)
 {
   app_listener_t *app_listener;
index e2f2279..3888cf7 100644 (file)
@@ -243,7 +243,7 @@ int app_worker_lock_and_send_event (app_worker_t * app, stream_session_t * s,
 clib_error_t *vnet_app_worker_add_del (vnet_app_worker_add_del_args_t * a);
 
 int application_start_listen (application_t * app,
-                             session_endpoint_extended_t * tep,
+                             session_endpoint_cfg_t * tep,
                              session_handle_t * handle);
 int application_stop_listen (u32 app_index, u32 app_or_wrk,
                             session_handle_t handle);
@@ -295,7 +295,7 @@ local_session_t *application_get_local_session_from_handle (session_handle_t
 local_session_t
   * application_get_local_listen_session_from_handle (session_handle_t lh);
 int application_start_local_listen (application_t * server,
-                                   session_endpoint_extended_t * sep,
+                                   session_endpoint_cfg_t * sep,
                                    session_handle_t * handle);
 int application_stop_local_listen (u32 app_index, u32 app_or_wrk,
                                   session_handle_t lh);
index d35a829..1f5c6ff 100644 (file)
@@ -137,11 +137,11 @@ api_parse_session_handle (u64 handle, u32 * session_index, u32 * thread_index)
 }
 
 static void
-session_endpoint_update_for_app (session_endpoint_extended_t * sep,
-                                application_t * app)
+session_endpoint_update_for_app (session_endpoint_cfg_t * sep,
+                                application_t * app, u8 is_connect)
 {
   app_namespace_t *app_ns;
-  u32 ns_index;
+  u32 ns_index, fib_index;
 
   ns_index = app->ns_index;
 
@@ -156,15 +156,29 @@ session_endpoint_update_for_app (session_endpoint_extended_t * sep,
       ns_index = owner_app->ns_index;
     }
   app_ns = app_namespace_get (ns_index);
-  if (app_ns)
+  if (!app_ns)
+    return;
+
+  /* Ask transport and network to bind to/connect using local interface
+   * that "supports" app's namespace. This will fix our local connection
+   * endpoint.
+   */
+  fib_index = sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
+  sep->peer.fib_index = fib_index;
+  sep->fib_index = fib_index;
+
+  if (!is_connect)
     {
-      /* Ask transport and network to bind to/connect using local interface
-       * that "supports" app's namespace. This will fix our local connection
-       * endpoint.
-       */
       sep->sw_if_index = app_ns->sw_if_index;
-      sep->fib_index =
-       sep->is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
+    }
+  else
+    {
+      if (app_ns->sw_if_index != APP_NAMESPACE_INVALID_INDEX
+         && sep->peer.sw_if_index != ENDPOINT_INVALID_INDEX
+         && sep->peer.sw_if_index != app_ns->sw_if_index)
+       clib_warning ("Local sw_if_index different from app ns sw_if_index");
+
+      sep->peer.sw_if_index = app_ns->sw_if_index;
     }
 }
 
@@ -185,7 +199,7 @@ vnet_bind_inline (vnet_bind_args_t * a)
   app_wrk = application_get_worker (app, a->wrk_map_index);
   a->sep_ext.app_wrk_index = app_wrk->wrk_index;
 
-  session_endpoint_update_for_app (&a->sep_ext, app);
+  session_endpoint_update_for_app (&a->sep_ext, app, 0 /* is_connect */ );
   if (!session_endpoint_in_ns (&a->sep))
     return VNET_API_ERROR_INVALID_VALUE_2;
 
@@ -278,7 +292,7 @@ application_connect (vnet_connect_args_t * a)
     return VNET_API_ERROR_INVALID_VALUE;
 
   client = application_get (a->app_index);
-  session_endpoint_update_for_app (&a->sep_ext, client);
+  session_endpoint_update_for_app (&a->sep_ext, client, 1 /* is_connect */ );
   client_wrk = application_get_worker (client, a->wrk_map_index);
 
   /*
@@ -368,8 +382,7 @@ global_scope:
 uword
 unformat_vnet_uri (unformat_input_t * input, va_list * args)
 {
-  session_endpoint_extended_t *sep = va_arg (*args,
-                                            session_endpoint_extended_t *);
+  session_endpoint_cfg_t *sep = va_arg (*args, session_endpoint_cfg_t *);
   u32 transport_proto = 0, port;
 
   if (unformat (input, "%U://%U/%d", unformat_transport_proto,
@@ -411,10 +424,10 @@ unformat_vnet_uri (unformat_input_t * input, va_list * args)
 }
 
 static u8 *cache_uri;
-static session_endpoint_extended_t *cache_sep;
+static session_endpoint_cfg_t *cache_sep;
 
 int
-parse_uri (char *uri, session_endpoint_extended_t * sep)
+parse_uri (char *uri, session_endpoint_cfg_t * sep)
 {
   unformat_input_t _input, *input = &_input;
 
@@ -548,7 +561,7 @@ vnet_application_detach (vnet_app_detach_args_t * a)
 int
 vnet_bind_uri (vnet_bind_args_t * a)
 {
-  session_endpoint_extended_t sep = SESSION_ENDPOINT_EXT_NULL;
+  session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
   int rv;
 
   rv = parse_uri (a->uri, &sep);
@@ -562,7 +575,7 @@ vnet_bind_uri (vnet_bind_args_t * a)
 int
 vnet_unbind_uri (vnet_unbind_args_t * a)
 {
-  session_endpoint_extended_t sep = SESSION_ENDPOINT_EXT_NULL;
+  session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
   stream_session_t *listener;
   u32 table_index;
   int rv;
@@ -585,7 +598,7 @@ vnet_unbind_uri (vnet_unbind_args_t * a)
 clib_error_t *
 vnet_connect_uri (vnet_connect_args_t * a)
 {
-  session_endpoint_extended_t sep = SESSION_ENDPOINT_EXT_NULL;
+  session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
   int rv;
 
   /* Parse uri */
index c8ceb4e..2da69fc 100644 (file)
@@ -39,7 +39,7 @@ typedef struct _vnet_bind_args_t
 {
   union
   {
-    session_endpoint_extended_t sep_ext;
+    session_endpoint_cfg_t sep_ext;
     session_endpoint_t sep;
     char *uri;
   };
@@ -71,7 +71,7 @@ typedef struct _vnet_connect_args
 {
   union
   {
-    session_endpoint_extended_t sep_ext;
+    session_endpoint_cfg_t sep_ext;
     session_endpoint_t sep;
     char *uri;
   };
index 1d421b9..9c246a1 100644 (file)
@@ -886,14 +886,14 @@ int
 session_open_cl (u32 app_wrk_index, session_endpoint_t * rmt, u32 opaque)
 {
   transport_connection_t *tc;
-  transport_endpoint_t *tep;
+  transport_endpoint_cfg_t *tep;
   segment_manager_t *sm;
   app_worker_t *app_wrk;
   stream_session_t *s;
   application_t *app;
   int rv;
 
-  tep = session_endpoint_to_transport (rmt);
+  tep = session_endpoint_to_transport_cfg (rmt);
   rv = tp_vfts[rmt->transport_proto].open (tep);
   if (rv < 0)
     {
@@ -924,11 +924,11 @@ int
 session_open_vc (u32 app_wrk_index, session_endpoint_t * rmt, u32 opaque)
 {
   transport_connection_t *tc;
-  transport_endpoint_t *tep;
+  transport_endpoint_cfg_t *tep;
   u64 handle;
   int rv;
 
-  tep = session_endpoint_to_transport (rmt);
+  tep = session_endpoint_to_transport_cfg (rmt);
   rv = tp_vfts[rmt->transport_proto].open (tep);
   if (rv < 0)
     {
@@ -958,11 +958,13 @@ session_open_vc (u32 app_wrk_index, session_endpoint_t * rmt, u32 opaque)
 int
 session_open_app (u32 app_wrk_index, session_endpoint_t * rmt, u32 opaque)
 {
-  session_endpoint_extended_t *sep = (session_endpoint_extended_t *) rmt;
+  session_endpoint_cfg_t *sep = (session_endpoint_cfg_t *) rmt;
+  transport_endpoint_cfg_t *tep_cfg = session_endpoint_to_transport_cfg (sep);
+
   sep->app_wrk_index = app_wrk_index;
   sep->opaque = opaque;
 
-  return tp_vfts[rmt->transport_proto].open ((transport_endpoint_t *) sep);
+  return tp_vfts[rmt->transport_proto].open (tep_cfg);
 }
 
 typedef int (*session_open_service_fn) (u32, session_endpoint_t *, u32);
@@ -1004,7 +1006,7 @@ session_open (u32 app_wrk_index, session_endpoint_t * rmt, u32 opaque)
  * @param sep Local endpoint to be listened on.
  */
 int
-session_listen (stream_session_t * ls, session_endpoint_extended_t * sep)
+session_listen (stream_session_t * ls, session_endpoint_cfg_t * sep)
 {
   transport_connection_t *tc;
   transport_endpoint_t *tep;
index f0aa36c..4d46596 100644 (file)
@@ -570,7 +570,7 @@ void stream_session_reset_notify (transport_connection_t * tc);
 int stream_session_accept (transport_connection_t * tc, u32 listener_index,
                           u8 notify);
 int session_open (u32 app_index, session_endpoint_t * tep, u32 opaque);
-int session_listen (stream_session_t * s, session_endpoint_extended_t * sep);
+int session_listen (stream_session_t * s, session_endpoint_cfg_t * sep);
 int session_stop_listen (stream_session_t * s);
 void stream_session_disconnect (stream_session_t * s);
 void stream_session_disconnect_transport (stream_session_t * s);
index f027364..eb33db0 100755 (executable)
@@ -1290,8 +1290,8 @@ vl_api_connect_sock_t_handler (vl_api_connect_sock_t * mp)
       a->sep.ip = *ip46;
       a->sep.port = mp->port;
       a->sep.transport_proto = mp->proto;
-      a->sep.fib_index = mp->vrf;
-      a->sep.sw_if_index = ENDPOINT_INVALID_INDEX;
+      a->sep.peer.fib_index = mp->vrf;
+      a->sep.peer.sw_if_index = ENDPOINT_INVALID_INDEX;
       if (mp->hostname_len)
        {
          vec_validate (a->sep_ext.hostname, mp->hostname_len - 1);
index 8fe1b0d..5c2993e 100644 (file)
@@ -45,12 +45,18 @@ dummy_session_reset_callback (stream_session_t * s)
   clib_warning ("called...");
 }
 
+volatile u32 connected_session_index = ~0;
+volatile u32 connected_session_thread = ~0;
 int
 dummy_session_connected_callback (u32 app_index, u32 api_context,
                                  stream_session_t * s, u8 is_fail)
 {
-  clib_warning ("called...");
-  return -1;
+  if (s)
+    {
+      connected_session_index = s->session_index;
+      connected_session_thread = s->thread_index;
+    }
+  return 0;
 }
 
 static u32 dummy_segment_count;
@@ -76,11 +82,15 @@ dummy_session_disconnect_callback (stream_session_t * s)
 }
 
 static u32 dummy_accept;
+volatile u32 accepted_session_index;
+volatile u32 accepted_session_thread;
 
 int
 dummy_session_accept_callback (stream_session_t * s)
 {
   dummy_accept = 1;
+  accepted_session_index = s->session_index;
+  accepted_session_thread = s->thread_index;
   s->session_state = SESSION_STATE_READY;
   return 0;
 }
@@ -119,7 +129,10 @@ session_create_lookpback (u32 table_id, u32 * sw_if_index,
     }
 
   if (table_id != 0)
-    ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id, 0);
+    {
+      ip_table_create (FIB_PROTOCOL_IP4, table_id, 0, 0);
+      ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id, 0);
+    }
 
   vnet_sw_interface_set_flags (vnet_get_main (), *sw_if_index,
                               VNET_SW_INTERFACE_FLAG_ADMIN_UP);
@@ -207,6 +220,189 @@ session_test_basic (vlib_main_t * vm, unformat_input_t * input)
   return 0;
 }
 
+static void
+session_add_del_route_via_lookup_in_table (u32 in_table_id, u32 via_table_id,
+                                          ip4_address_t * ip, u8 mask,
+                                          u8 is_add)
+{
+  fib_route_path_t *rpaths = 0, *rpath;
+  u32 in_fib_index, via_fib_index;
+
+  fib_prefix_t prefix = {
+    .fp_addr.ip4.as_u32 = ip->as_u32,
+    .fp_len = mask,
+    .fp_proto = FIB_PROTOCOL_IP4,
+  };
+
+  via_fib_index = fib_table_find (FIB_PROTOCOL_IP4, via_table_id);
+  if (via_fib_index == ~0)
+    {
+      clib_warning ("couldn't resolve via table id to index");
+      return;
+    }
+  in_fib_index = fib_table_find (FIB_PROTOCOL_IP4, in_table_id);
+  if (in_fib_index == ~0)
+    {
+      clib_warning ("couldn't resolve in table id to index");
+      return;
+    }
+
+  vec_add2 (rpaths, rpath, 1);
+  clib_memset (rpath, 0, sizeof (*rpath));
+  rpath->frp_weight = 1;
+  rpath->frp_fib_index = via_fib_index;
+  rpath->frp_proto = DPO_PROTO_IP4;
+  rpath->frp_sw_if_index = ~0;
+  rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
+
+  if (is_add)
+    fib_table_entry_path_add2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
+                              FIB_ENTRY_FLAG_NONE, rpath);
+  else
+    fib_table_entry_path_remove2 (in_fib_index, &prefix, FIB_SOURCE_CLI,
+                                 rpath);
+  vec_free (rpaths);
+}
+
+static int
+session_test_endpoint_cfg (vlib_main_t * vm, unformat_input_t * input)
+{
+  session_endpoint_cfg_t client_sep = SESSION_ENDPOINT_CFG_NULL;
+  u64 options[APP_OPTIONS_N_OPTIONS], dummy_secret = 1234;
+  u16 dummy_server_port = 1234, dummy_client_port = 5678;
+  session_endpoint_t server_sep = SESSION_ENDPOINT_NULL;
+  u32 server_index, client_index, sw_if_index[2];
+  ip4_address_t intf_addr[3];
+  transport_connection_t *tc;
+  stream_session_t *s;
+  clib_error_t *error;
+  u8 *appns_id;
+
+  /*
+   * Create the loopbacks
+   */
+  intf_addr[0].as_u32 = clib_host_to_net_u32 (0x01010101),
+    session_create_lookpback (0, &sw_if_index[0], &intf_addr[0]);
+
+  intf_addr[1].as_u32 = clib_host_to_net_u32 (0x02020202),
+    session_create_lookpback (1, &sw_if_index[1], &intf_addr[1]);
+
+  session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
+                                            1 /* is_add */ );
+  session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
+                                            1 /* is_add */ );
+
+  /*
+   * Insert namespace
+   */
+  appns_id = format (0, "appns1");
+  vnet_app_namespace_add_del_args_t ns_args = {
+    .ns_id = appns_id,
+    .secret = dummy_secret,
+    .sw_if_index = sw_if_index[1],
+    .ip4_fib_id = 0,
+    .is_add = 1
+  };
+  error = vnet_app_namespace_add_del (&ns_args);
+  SESSION_TEST ((error == 0), "app ns insertion should succeed: %d",
+               clib_error_get_code (error));
+
+  /*
+   * Attach client/server
+   */
+  clib_memset (options, 0, sizeof (options));
+  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+  options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+
+  vnet_app_attach_args_t attach_args = {
+    .api_client_index = ~0,
+    .options = options,
+    .namespace_id = 0,
+    .session_cb_vft = &dummy_session_cbs,
+    .name = format (0, "session_test_client"),
+  };
+
+  error = vnet_application_attach (&attach_args);
+  SESSION_TEST ((error == 0), "client app attached");
+  client_index = attach_args.app_index;
+  vec_free (attach_args.name);
+
+  attach_args.name = format (0, "session_test_server");
+  attach_args.namespace_id = appns_id;
+  attach_args.options[APP_OPTIONS_NAMESPACE_SECRET] = dummy_secret;
+  error = vnet_application_attach (&attach_args);
+  SESSION_TEST ((error == 0), "server app attached: %U", format_clib_error,
+               error);
+  vec_free (attach_args.name);
+  server_index = attach_args.app_index;
+
+  server_sep.is_ip4 = 1;
+  server_sep.port = dummy_server_port;
+  vnet_bind_args_t bind_args = {
+    .sep = server_sep,
+    .app_index = server_index,
+  };
+  error = vnet_bind (&bind_args);
+  SESSION_TEST ((error == 0), "server bind should work");
+
+  /*
+   * Connect and force lcl ip
+   */
+  client_sep.is_ip4 = 1;
+  client_sep.ip.ip4.as_u32 = clib_host_to_net_u32 (0x02020202);
+  client_sep.port = dummy_server_port;
+  client_sep.peer.is_ip4 = 1;
+  client_sep.peer.ip.ip4.as_u32 = clib_host_to_net_u32 (0x01010101);
+  client_sep.peer.port = dummy_client_port;
+  client_sep.transport_proto = TRANSPORT_PROTO_TCP;
+
+  vnet_connect_args_t connect_args = {
+    .sep_ext = client_sep,
+    .app_index = client_index,
+  };
+
+  error = vnet_connect (&connect_args);
+  SESSION_TEST ((error == 0), "connect should work");
+
+  /* wait for stuff to happen */
+  vlib_process_suspend (vm, 10e-3);
+
+  SESSION_TEST ((connected_session_index != ~0), "session should exist");
+  s = session_get (connected_session_index, connected_session_thread);
+  tc = session_get_transport (s);
+  SESSION_TEST ((tc != 0), "transport should exist");
+  SESSION_TEST ((memcmp (&tc->lcl_ip, &client_sep.peer.ip,
+                        sizeof (tc->lcl_ip)) == 0), "ips should be equal");
+  SESSION_TEST ((tc->lcl_port == dummy_client_port), "ports should be equal");
+
+  /* These sessions, because of the way they're established are pinned to
+   * main thread, even when we have workers and we avoid polling main thread,
+   * i.e., we can't cleanup pending disconnects, so force cleanup for both
+   */
+  stream_session_cleanup (s);
+  s = session_get (accepted_session_index, accepted_session_thread);
+  stream_session_cleanup (s);
+
+  vnet_app_detach_args_t detach_args = {
+    .app_index = server_index,
+  };
+  vnet_application_detach (&detach_args);
+  detach_args.app_index = client_index;
+  vnet_application_detach (&detach_args);
+
+  /* Allow the disconnects to finish before removing the routes. */
+  vlib_process_suspend (vm, 10e-3);
+
+  session_add_del_route_via_lookup_in_table (0, 1, &intf_addr[1], 32,
+                                            0 /* is_add */ );
+  session_add_del_route_via_lookup_in_table (1, 0, &intf_addr[0], 32,
+                                            0 /* is_add */ );
+
+  session_delete_loopback (sw_if_index[0]);
+  session_delete_loopback (sw_if_index[1]);
+  return 0;
+}
+
 static int
 session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
 {
@@ -1515,6 +1711,8 @@ session_test (vlib_main_t * vm,
        res = session_test_rules (vm, input);
       else if (unformat (input, "proxy"))
        res = session_test_proxy (vm, input);
+      else if (unformat (input, "endpt-cfg"))
+       res = session_test_endpoint_cfg (vm, input);
       else if (unformat (input, "all"))
        {
          if ((res = session_test_basic (vm, input)))
@@ -1527,6 +1725,8 @@ session_test (vlib_main_t * vm,
            goto done;
          if ((res = session_test_proxy (vm, input)))
            goto done;
+         if ((res = session_test_endpoint_cfg (vm, input)))
+           goto done;
        }
       else
        break;
index 287a892..c335c5b 100644 (file)
@@ -153,8 +153,8 @@ typedef struct local_session_
 } local_session_t;
 
 #define foreach_session_endpoint_fields                                \
-    foreach_transport_connection_fields                                \
-    _(u8, transport_proto)                                     \
+  foreach_transport_endpoint_cfg_fields                                \
+  _(u8, transport_proto)                                       \
 
 typedef struct _session_endpoint
 {
@@ -163,7 +163,7 @@ typedef struct _session_endpoint
 #undef _
 } session_endpoint_t;
 
-typedef struct _session_endpoint_extended
+typedef struct _session_endpoint_cfg
 {
 #define _(type, name) type name;
   foreach_session_endpoint_fields
@@ -171,7 +171,7 @@ typedef struct _session_endpoint_extended
   u32 app_wrk_index;
   u32 opaque;
   u8 *hostname;
-} session_endpoint_extended_t;
+} session_endpoint_cfg_t;
 
 #define SESSION_IP46_ZERO                      \
 {                                              \
@@ -179,6 +179,15 @@ typedef struct _session_endpoint_extended
        { 0, 0, },                              \
     },                                         \
 }
+
+#define TRANSPORT_ENDPOINT_NULL                        \
+{                                              \
+  .sw_if_index = ENDPOINT_INVALID_INDEX,       \
+  .ip = SESSION_IP46_ZERO,                     \
+  .fib_index = ENDPOINT_INVALID_INDEX,         \
+  .is_ip4 = 0,                                 \
+  .port = 0,                                   \
+}
 #define SESSION_ENDPOINT_NULL                  \
 {                                              \
   .sw_if_index = ENDPOINT_INVALID_INDEX,       \
@@ -186,15 +195,17 @@ typedef struct _session_endpoint_extended
   .fib_index = ENDPOINT_INVALID_INDEX,         \
   .is_ip4 = 0,                                 \
   .port = 0,                                   \
+  .peer = TRANSPORT_ENDPOINT_NULL,             \
   .transport_proto = 0,                                \
 }
-#define SESSION_ENDPOINT_EXT_NULL              \
+#define SESSION_ENDPOINT_CFG_NULL              \
 {                                              \
   .sw_if_index = ENDPOINT_INVALID_INDEX,       \
   .ip = SESSION_IP46_ZERO,                     \
   .fib_index = ENDPOINT_INVALID_INDEX,         \
   .is_ip4 = 0,                                 \
   .port = 0,                                   \
+  .peer = TRANSPORT_ENDPOINT_NULL,             \
   .transport_proto = 0,                                \
   .app_wrk_index = ENDPOINT_INVALID_INDEX,     \
   .opaque = ENDPOINT_INVALID_INDEX,            \
@@ -202,6 +213,8 @@ typedef struct _session_endpoint_extended
 }
 
 #define session_endpoint_to_transport(_sep) ((transport_endpoint_t *)_sep)
+#define session_endpoint_to_transport_cfg(_sep)                \
+  ((transport_endpoint_cfg_t *)_sep)
 
 always_inline u8
 session_endpoint_fib_proto (session_endpoint_t * sep)
index 8cbad0d..fefedca 100644 (file)
@@ -291,7 +291,7 @@ always_inline transport_endpoint_t *
 transport_endpoint_new (void)
 {
   transport_endpoint_t *tep;
-  pool_get (local_endpoints, tep);
+  pool_get_zero (local_endpoints, tep);
   return tep;
 }
 
@@ -312,6 +312,19 @@ transport_endpoint_cleanup (u8 proto, ip46_address_t * lcl_ip, u16 port)
     }
 }
 
+static void
+transport_endpoint_mark_used (u8 proto, ip46_address_t * ip, u16 port)
+{
+  transport_endpoint_t *tep;
+  clib_spinlock_lock_if_init (&local_endpoints_lock);
+  tep = transport_endpoint_new ();
+  clib_memcpy (&tep->ip, ip, sizeof (*ip));
+  tep->port = port;
+  transport_endpoint_table_add (&local_endpoints_table, proto, tep,
+                               tep - local_endpoints);
+  clib_spinlock_unlock_if_init (&local_endpoints_lock);
+}
+
 /**
  * Allocate local port and add if successful add entry to local endpoint
  * table to mark the pair as used.
@@ -319,10 +332,9 @@ transport_endpoint_cleanup (u8 proto, ip46_address_t * lcl_ip, u16 port)
 int
 transport_alloc_local_port (u8 proto, ip46_address_t * ip)
 {
-  transport_endpoint_t *tep;
-  u32 tei;
   u16 min = 1024, max = 65535; /* XXX configurable ? */
   int tries, limit;
+  u32 tei;
 
   limit = max - min;
 
@@ -347,96 +359,123 @@ transport_alloc_local_port (u8 proto, ip46_address_t * ip)
                                       port);
       if (tei == ENDPOINT_INVALID_INDEX)
        {
-         clib_spinlock_lock_if_init (&local_endpoints_lock);
-         tep = transport_endpoint_new ();
-         clib_memcpy (&tep->ip, ip, sizeof (*ip));
-         tep->port = port;
-         transport_endpoint_table_add (&local_endpoints_table, proto, tep,
-                                       tep - local_endpoints);
-         clib_spinlock_unlock_if_init (&local_endpoints_lock);
-
-         return tep->port;
+         transport_endpoint_mark_used (proto, ip, port);
+         return port;
        }
     }
   return -1;
 }
 
-int
-transport_alloc_local_endpoint (u8 proto, transport_endpoint_t * rmt,
-                               ip46_address_t * lcl_addr, u16 * lcl_port)
+static clib_error_t *
+transport_get_interface_ip (u32 sw_if_index, u8 is_ip4, ip46_address_t * addr)
 {
-  fib_prefix_t prefix;
-  fib_node_index_t fei;
-  u32 sw_if_index;
-  int port;
-
-  /*
-   * Find the local address and allocate port
-   */
-
-  /* Find a FIB path to the destination */
-  clib_memcpy (&prefix.fp_addr, &rmt->ip, sizeof (rmt->ip));
-  prefix.fp_proto = rmt->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
-  prefix.fp_len = rmt->is_ip4 ? 32 : 128;
-
-  ASSERT (rmt->fib_index != ENDPOINT_INVALID_INDEX);
-  fei = fib_table_lookup (rmt->fib_index, &prefix);
-
-  /* Couldn't find route to destination. Bail out. */
-  if (fei == FIB_NODE_INDEX_INVALID)
+  if (is_ip4)
     {
-      clib_warning ("no route to destination");
-      return -1;
+      ip4_address_t *ip4;
+      ip4 = ip_interface_get_first_ip (sw_if_index, 1);
+      if (!ip4)
+       return clib_error_return (0, "no routable ip4 address on %U",
+                                 format_vnet_sw_if_index_name,
+                                 vnet_get_main (), sw_if_index);
+      addr->ip4.as_u32 = ip4->as_u32;
     }
+  else
+    {
+      ip6_address_t *ip6;
+      ip6 = ip_interface_get_first_ip (sw_if_index, 0);
+      if (ip6 == 0)
+       return clib_error_return (0, "no routable ip6 addresses on %U",
+                                 format_vnet_sw_if_index_name,
+                                 vnet_get_main (), sw_if_index);
+      clib_memcpy (&addr->ip6, ip6, sizeof (*ip6));
+    }
+  return 0;
+}
 
-  sw_if_index = rmt->sw_if_index;
-  if (sw_if_index == ENDPOINT_INVALID_INDEX)
-    sw_if_index = fib_entry_get_resolving_interface (fei);
+static clib_error_t *
+transport_find_local_ip_for_remote (u32 sw_if_index,
+                                   transport_endpoint_t * rmt,
+                                   ip46_address_t * lcl_addr)
+{
+  fib_node_index_t fei;
+  fib_prefix_t prefix;
 
   if (sw_if_index == ENDPOINT_INVALID_INDEX)
     {
-      clib_warning ("no resolving interface for %U", format_ip46_address,
-                   &rmt->ip, (rmt->is_ip4 == 0) + 1);
-      return -1;
+      /* Find a FIB path to the destination */
+      clib_memcpy (&prefix.fp_addr, &rmt->ip, sizeof (rmt->ip));
+      prefix.fp_proto = rmt->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
+      prefix.fp_len = rmt->is_ip4 ? 32 : 128;
+
+      ASSERT (rmt->fib_index != ENDPOINT_INVALID_INDEX);
+      fei = fib_table_lookup (rmt->fib_index, &prefix);
+
+      /* Couldn't find route to destination. Bail out. */
+      if (fei == FIB_NODE_INDEX_INVALID)
+       return clib_error_return (0, "no route to %U", format_ip46_address,
+                                 &rmt->ip, (rmt->is_ip4 == 0) + 1);
+
+      sw_if_index = fib_entry_get_resolving_interface (fei);
+      if (sw_if_index == ENDPOINT_INVALID_INDEX)
+       return clib_error_return (0, "no resolving interface for %U",
+                                 format_ip46_address, &rmt->ip,
+                                 (rmt->is_ip4 == 0) + 1);
     }
 
   clib_memset (lcl_addr, 0, sizeof (*lcl_addr));
+  return transport_get_interface_ip (sw_if_index, rmt->is_ip4, lcl_addr);
+}
 
-  if (rmt->is_ip4)
+int
+transport_alloc_local_endpoint (u8 proto, transport_endpoint_cfg_t * rmt_cfg,
+                               ip46_address_t * lcl_addr, u16 * lcl_port)
+{
+  transport_endpoint_t *rmt = (transport_endpoint_t *) rmt_cfg;
+  clib_error_t *error;
+  int port;
+  u32 tei;
+
+  /*
+   * Find the local address
+   */
+  if (ip_is_zero (&rmt_cfg->peer.ip, rmt_cfg->peer.is_ip4))
     {
-      ip4_address_t *ip4;
-      ip4 = ip_interface_get_first_ip (sw_if_index, 1);
-      if (!ip4)
-       {
-         clib_warning ("no routable ip4 address on %U",
-                       format_vnet_sw_if_index_name, vnet_get_main (),
-                       sw_if_index);
-         return -1;
-       }
-      lcl_addr->ip4.as_u32 = ip4->as_u32;
+      error = transport_find_local_ip_for_remote (rmt_cfg->peer.sw_if_index,
+                                                 rmt, lcl_addr);
+      if (error)
+       return -1;
     }
   else
     {
-      ip6_address_t *ip6;
-      ip6 = ip_interface_get_first_ip (sw_if_index, 0);
-      if (ip6 == 0)
+      /* Assume session layer vetted this address */
+      clib_memcpy (lcl_addr, &rmt_cfg->peer.ip, sizeof (rmt_cfg->peer.ip));
+    }
+
+  /*
+   * Allocate source port
+   */
+  if (rmt_cfg->peer.port == 0)
+    {
+      port = transport_alloc_local_port (proto, lcl_addr);
+      if (port < 1)
        {
-         clib_warning ("no routable ip6 addresses on %U",
-                       format_vnet_sw_if_index_name, vnet_get_main (),
-                       sw_if_index);
+         clib_warning ("Failed to allocate src port");
          return -1;
        }
-      clib_memcpy (&lcl_addr->ip6, ip6, sizeof (*ip6));
+      *lcl_port = port;
     }
-
-  /* Allocate source port */
-  port = transport_alloc_local_port (proto, lcl_addr);
-  if (port < 1)
+  else
     {
-      clib_warning ("Failed to allocate src port");
-      return -1;
+      port = clib_net_to_host_u16 (rmt_cfg->peer.port);
+      tei = transport_endpoint_lookup (&local_endpoints_table, proto,
+                                      lcl_addr, port);
+      if (tei != ENDPOINT_INVALID_INDEX)
+       return -1;
+
+      transport_endpoint_mark_used (proto, lcl_addr, port);
+      *lcl_port = port;
     }
-  *lcl_port = port;
+
   return 0;
 }
 
index a4f26a4..952f97d 100644 (file)
@@ -122,20 +122,31 @@ u8 *format_transport_half_open_connection (u8 * s, va_list * args);
 
 uword unformat_transport_proto (unformat_input_t * input, va_list * args);
 
-#define foreach_transport_connection_fields                            \
+#define foreach_transport_endpoint_fields                              \
+  _(ip46_address_t, ip) /**< ip address in net order */                        \
+  _(u16, port)         /**< port in net order */                       \
+  _(u8, is_ip4)                /**< set if ip4 */                              \
   _(u32, sw_if_index)  /**< interface endpoint is associated with  */  \
-  _(ip46_address_t, ip) /**< ip address */                             \
   _(u32, fib_index)    /**< fib table endpoint is associated with */   \
-  _(u8, is_ip4)                /**< set if ip4 */                              \
-  _(u16, port)         /**< port in net order */                       \
 
-typedef struct _transport_endpoint
+typedef struct transport_endpoint_
 {
 #define _(type, name) type name;
-  foreach_transport_connection_fields
+  foreach_transport_endpoint_fields
 #undef _
 } transport_endpoint_t;
 
+#define foreach_transport_endpoint_cfg_fields                          \
+  foreach_transport_endpoint_fields                                    \
+  _(transport_endpoint_t, peer)                                                \
+
+typedef struct transport_endpoint_pair_
+{
+#define _(type, name) type name;
+  foreach_transport_endpoint_cfg_fields
+#undef _
+} transport_endpoint_cfg_t;
+
 typedef clib_bihash_24_8_t transport_endpoint_table_t;
 
 #define ENDPOINT_INVALID_INDEX ((u32)~0)
@@ -153,7 +164,7 @@ transport_endpoint_fib_proto (transport_endpoint_t * tep)
 }
 
 int transport_alloc_local_port (u8 proto, ip46_address_t * ip);
-int transport_alloc_local_endpoint (u8 proto, transport_endpoint_t * rmt,
+int transport_alloc_local_endpoint (u8 proto, transport_endpoint_cfg_t * rmt,
                                    ip46_address_t * lcl_addr,
                                    u16 * lcl_port);
 void transport_endpoint_cleanup (u8 proto, ip46_address_t * lcl_ip, u16 port);
index a96c5e1..ce3bb7f 100644 (file)
@@ -47,7 +47,7 @@ typedef struct _transport_proto_vft
    */
   u32 (*bind) (u32 session_index, transport_endpoint_t * lcl);
   u32 (*unbind) (u32);
-  int (*open) (transport_endpoint_t * rmt);
+  int (*open) (transport_endpoint_cfg_t * rmt);
   void (*close) (u32 conn_index, u32 thread_index);
   void (*cleanup) (u32 conn_index, u32 thread_index);
   clib_error_t *(*enable) (vlib_main_t * vm, u8 is_en);
index 5fadef0..8c0c5da 100644 (file)
@@ -620,7 +620,7 @@ tcp_alloc_custom_local_endpoint (tcp_main_t * tm, ip46_address_t * lcl_addr,
 }
 
 static int
-tcp_connection_open (transport_endpoint_t * rmt)
+tcp_session_open (transport_endpoint_cfg_t * rmt)
 {
   tcp_main_t *tm = vnet_get_tcp_main ();
   tcp_connection_t *tc;
@@ -666,12 +666,6 @@ tcp_connection_open (transport_endpoint_t * rmt)
   return tc->c_c_index;
 }
 
-static int
-tcp_session_open (transport_endpoint_t * tep)
-{
-  return tcp_connection_open (tep);
-}
-
 const char *tcp_dbg_evt_str[] = {
 #define _(sym, str) str,
   foreach_tcp_dbg_evt
index 3eecfe9..109280b 100644 (file)
@@ -511,10 +511,10 @@ static session_cb_vft_t tls_app_cb_vft = {
 /* *INDENT-ON* */
 
 int
-tls_connect (transport_endpoint_t * tep)
+tls_connect (transport_endpoint_cfg_t * tep)
 {
   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
-  session_endpoint_extended_t *sep;
+  session_endpoint_cfg_t *sep;
   tls_engine_type_t engine_type;
   tls_main_t *tm = &tls_main;
   app_worker_t *app_wrk;
@@ -523,7 +523,7 @@ tls_connect (transport_endpoint_t * tep)
   tls_ctx_t *ctx;
   u32 ctx_index;
 
-  sep = (session_endpoint_extended_t *) tep;
+  sep = (session_endpoint_cfg_t *) tep;
   app_wrk = app_worker_get (sep->app_wrk_index);
   app = application_get (app_wrk->app_index);
   engine_type = tls_get_engine_type (app->tls_engine);
@@ -579,7 +579,7 @@ tls_start_listen (u32 app_listener_index, transport_endpoint_t * tep)
   app_worker_t *app_wrk;
   tls_main_t *tm = &tls_main;
   session_handle_t tls_handle;
-  session_endpoint_extended_t *sep;
+  session_endpoint_cfg_t *sep;
   stream_session_t *tls_listener;
   stream_session_t *app_listener;
   tls_engine_type_t engine_type;
@@ -587,7 +587,7 @@ tls_start_listen (u32 app_listener_index, transport_endpoint_t * tep)
   tls_ctx_t *lctx;
   u32 lctx_index;
 
-  sep = (session_endpoint_extended_t *) tep;
+  sep = (session_endpoint_cfg_t *) tep;
   app_wrk = app_worker_get (sep->app_wrk_index);
   app = application_get (app_wrk->app_index);
   engine_type = tls_get_engine_type (app->tls_engine);
index 85a22a9..ccac921 100644 (file)
@@ -261,7 +261,7 @@ udp_send_space (transport_connection_t * t)
 }
 
 int
-udp_open_connection (transport_endpoint_t * rmt)
+udp_open_connection (transport_endpoint_cfg_t * rmt)
 {
   udp_main_t *um = vnet_get_udp_main ();
   vlib_main_t *vm = vlib_get_main ();
@@ -339,7 +339,7 @@ const static transport_proto_vft_t udp_proto = {
 
 
 int
-udpc_connection_open (transport_endpoint_t * rmt)
+udpc_connection_open (transport_endpoint_cfg_t * rmt)
 {
   udp_connection_t *uc;
   u32 uc_index;
index 55541b7..3336f4d 100644 (file)
@@ -47,14 +47,6 @@ class TestSession(VppTestCase):
         super(TestSession, self).tearDown()
         self.vapi.session_enable_disable(is_enabled=1)
 
-    def test_session(self):
-        """ Session Unit Tests """
-        error = self.vapi.cli("test session all")
-
-        if error:
-            self.logger.critical(error)
-        self.assertEqual(error.find("failed"), -1)
-
     def test_segment_manager_alloc(self):
         """ Session Segment Manager Multiple Segment Allocation """
 
@@ -92,5 +84,25 @@ class TestSession(VppTestCase):
         ip_t01.remove_vpp_config()
         ip_t10.remove_vpp_config()
 
+
+class TestSessionUnitTests(VppTestCase):
+    """ Session Unit Tests Case """
+
+    def setUp(self):
+        super(TestSessionUnitTests, self).setUp()
+        self.vapi.session_enable_disable(is_enabled=1)
+
+    def test_session(self):
+        """ Session Unit Tests """
+        error = self.vapi.cli("test session all")
+
+        if error:
+            self.logger.critical(error)
+        self.assertEqual(error.find("failed"), -1)
+
+    def tearDown(self):
+        super(TestSessionUnitTests, self).tearDown()
+        self.vapi.session_enable_disable(is_enabled=0)
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)