summaryrefslogtreecommitdiffstats
path: root/src/vnet/session
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/session')
-rw-r--r--src/vnet/session/application.c6
-rw-r--r--src/vnet/session/application.h4
-rw-r--r--src/vnet/session/application_interface.c51
-rw-r--r--src/vnet/session/application_interface.h4
-rw-r--r--src/vnet/session/session.c16
-rw-r--r--src/vnet/session/session.h2
-rwxr-xr-xsrc/vnet/session/session_api.c4
-rw-r--r--src/vnet/session/session_test.c206
-rw-r--r--src/vnet/session/stream_session.h23
-rw-r--r--src/vnet/session/transport.c173
-rw-r--r--src/vnet/session/transport.h25
-rw-r--r--src/vnet/session/transport_interface.h2
12 files changed, 397 insertions, 119 deletions
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);