From 5665cedf57165c05d00f28de06b627047902ffce Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Thu, 25 Oct 2018 18:03:45 -0700 Subject: session: extend connect api for internal apps Change-Id: Ie4c5cfc4c97acb321a46b4df589dc44de1b616ba Signed-off-by: Florin Coras --- src/vnet/session/application.c | 6 +- src/vnet/session/application.h | 4 +- src/vnet/session/application_interface.c | 51 +++++--- src/vnet/session/application_interface.h | 4 +- src/vnet/session/session.c | 16 +-- src/vnet/session/session.h | 2 +- src/vnet/session/session_api.c | 4 +- src/vnet/session/session_test.c | 206 ++++++++++++++++++++++++++++++- src/vnet/session/stream_session.h | 23 +++- src/vnet/session/transport.c | 173 ++++++++++++++++---------- src/vnet/session/transport.h | 25 ++-- src/vnet/session/transport_interface.h | 2 +- 12 files changed, 397 insertions(+), 119 deletions(-) (limited to 'src/vnet/session') diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 90c067d6d31..1d7b3ad1125 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -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; diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h index e2f2279d77f..3888cf7f463 100644 --- a/src/vnet/session/application.h +++ b/src/vnet/session/application.h @@ -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); diff --git a/src/vnet/session/application_interface.c b/src/vnet/session/application_interface.c index d35a8293723..1f5c6ff5a31 100644 --- a/src/vnet/session/application_interface.c +++ b/src/vnet/session/application_interface.c @@ -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 */ diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h index c8ceb4e07a5..2da69fcab92 100644 --- a/src/vnet/session/application_interface.h +++ b/src/vnet/session/application_interface.h @@ -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; }; diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index 1d421b978c1..9c246a1ad87 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -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; diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h index f0aa36cc1bc..4d46596813f 100644 --- a/src/vnet/session/session.h +++ b/src/vnet/session/session.h @@ -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); diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c index f0273641e7f..eb33db03f33 100755 --- a/src/vnet/session/session_api.c +++ b/src/vnet/session/session_api.c @@ -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); diff --git a/src/vnet/session/session_test.c b/src/vnet/session/session_test.c index 8fe1b0d36e0..5c2993e3322 100644 --- a/src/vnet/session/session_test.c +++ b/src/vnet/session/session_test.c @@ -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; diff --git a/src/vnet/session/stream_session.h b/src/vnet/session/stream_session.h index 287a8927339..c335c5b833e 100644 --- a/src/vnet/session/stream_session.h +++ b/src/vnet/session/stream_session.h @@ -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) diff --git a/src/vnet/session/transport.c b/src/vnet/session/transport.c index 8cbad0d397f..fefedcae8f2 100644 --- a/src/vnet/session/transport.c +++ b/src/vnet/session/transport.c @@ -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; } diff --git a/src/vnet/session/transport.h b/src/vnet/session/transport.h index a4f26a45a6a..952f97d9ac3 100644 --- a/src/vnet/session/transport.h +++ b/src/vnet/session/transport.h @@ -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); diff --git a/src/vnet/session/transport_interface.h b/src/vnet/session/transport_interface.h index a96c5e12d7a..ce3bb7fab7c 100644 --- a/src/vnet/session/transport_interface.h +++ b/src/vnet/session/transport_interface.h @@ -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); -- cgit 1.2.3-korg