From 561af9b441c7392cf391dd46399b0b16b876a08a Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Sat, 9 Dec 2017 10:19:43 -0800 Subject: [PATCH] session: generalize handling of network transports - compute session type out of transport and network protos - make session, session lookup and session queue code network protocol agnostic This does not update the session layer to support non-ip network layer protocols Change-Id: Ifc2f92845e158b649d59462eb7d51c12af536691 Signed-off-by: Florin Coras --- src/vnet/session/application.c | 30 ++++++---- src/vnet/session/session.c | 97 ++++++++++++++++++------------ src/vnet/session/session.h | 57 ++++++++++-------- src/vnet/session/session_api.c | 2 +- src/vnet/session/session_cli.c | 2 +- src/vnet/session/session_lookup.c | 106 +++++++++++++++------------------ src/vnet/session/session_node.c | 29 +++------ src/vnet/session/stream_session.h | 16 +---- src/vnet/session/transport.c | 67 ++++++++++++++++----- src/vnet/session/transport.h | 1 + src/vnet/session/transport_interface.h | 19 +++++- src/vnet/tcp/tcp.c | 21 +++++-- src/vnet/tcp/tcp.h | 9 --- src/vnet/tcp/tcp_output.c | 1 + src/vnet/udp/udp.c | 7 ++- 15 files changed, 263 insertions(+), 201 deletions(-) diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c index 9a540f6b78c..4523d5da4e2 100644 --- a/src/vnet/session/application.c +++ b/src/vnet/session/application.c @@ -573,8 +573,8 @@ application_start_stop_proxy_fib_proto (application_t * app, u8 fib_proto, } void -application_start_stop_proxy (application_t * app, u8 transport_proto, - u8 is_start) +application_start_stop_proxy (application_t * app, + transport_proto_t transport_proto, u8 is_start) { if (application_has_local_scope (app)) { @@ -605,24 +605,34 @@ void application_setup_proxy (application_t * app) { u16 transports = app->proxied_transports; + transport_proto_t tp; + ASSERT (application_is_proxy (app)); if (application_is_builtin (app)) return; - if (transports & (1 << TRANSPORT_PROTO_TCP)) - application_start_stop_proxy (app, TRANSPORT_PROTO_TCP, 1); - if (transports & (1 << TRANSPORT_PROTO_UDP)) - application_start_stop_proxy (app, TRANSPORT_PROTO_UDP, 1); + + /* *INDENT-OFF* */ + transport_proto_foreach (tp, ({ + if (transports & (1 << tp)) + application_start_stop_proxy (app, tp, 1); + })); + /* *INDENT-ON* */ } void application_remove_proxy (application_t * app) { u16 transports = app->proxied_transports; + transport_proto_t tp; + ASSERT (application_is_proxy (app)); - if (transports & (1 << TRANSPORT_PROTO_TCP)) - application_start_stop_proxy (app, TRANSPORT_PROTO_TCP, 0); - if (transports & (1 << TRANSPORT_PROTO_UDP)) - application_start_stop_proxy (app, TRANSPORT_PROTO_UDP, 0); + + /* *INDENT-OFF* */ + transport_proto_foreach (tp, ({ + if (transports & (1 << tp)) + application_start_stop_proxy (app, tp, 0); + })); + /* *INDENT-ON* */ } u8 * diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index 616bfc9f150..408a1f5caf0 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -23,7 +23,6 @@ #include #include #include -#include session_manager_main_t session_manager_main; extern transport_proto_vft_t *tp_vfts; @@ -623,12 +622,14 @@ static void session_switch_pool (void *cb_args) { session_switch_pool_args_t *args = (session_switch_pool_args_t *) cb_args; + transport_proto_t tp; stream_session_t *s; ASSERT (args->thread_index == vlib_get_thread_index ()); s = session_get (args->session_index, args->thread_index); s->server_tx_fifo->master_session_index = args->new_session_index; s->server_tx_fifo->master_thread_index = args->new_thread_index; - tp_vfts[s->session_type].cleanup (s->connection_index, s->thread_index); + tp = session_get_transport_proto (s); + tp_vfts[tp].cleanup (s->connection_index, s->thread_index); session_free (s); clib_mem_free (cb_args); } @@ -806,22 +807,22 @@ int session_open (u32 app_index, session_endpoint_t * rmt, u32 opaque) { transport_connection_t *tc; - session_type_t sst; + transport_endpoint_t *tep; segment_manager_t *sm; stream_session_t *s; application_t *app; int rv; u64 handle; - sst = session_type_from_proto_and_ip (rmt->transport_proto, rmt->is_ip4); - rv = tp_vfts[sst].open (session_endpoint_to_transport (rmt)); + tep = session_endpoint_to_transport (rmt); + rv = tp_vfts[rmt->transport_proto].open (tep); if (rv < 0) { SESSION_DBG ("Transport failed to open connection."); return VNET_API_ERROR_SESSION_CONNECT; } - tc = tp_vfts[sst].get_half_open ((u32) rv); + tc = tp_vfts[rmt->transport_proto].get_half_open ((u32) rv); /* If transport offers a stream service, only allocate session once the * connection has been established. @@ -874,15 +875,16 @@ stream_session_listen (stream_session_t * s, session_endpoint_t * sep) u32 tci; /* Transport bind/listen */ - tci = tp_vfts[s->session_type].bind (s->session_index, - session_endpoint_to_transport (sep)); + tci = tp_vfts[sep->transport_proto].bind (s->session_index, + session_endpoint_to_transport + (sep)); if (tci == (u32) ~ 0) return -1; /* Attach transport to session */ s->connection_index = tci; - tc = tp_vfts[s->session_type].get_listener (tci); + tc = tp_vfts[sep->transport_proto].get_listener (tci); /* Weird but handle it ... */ if (tc == 0) @@ -901,15 +903,15 @@ stream_session_listen (stream_session_t * s, session_endpoint_t * sep) int stream_session_stop_listen (stream_session_t * s) { + transport_proto_t tp = session_get_transport_proto (s); transport_connection_t *tc; - if (s->session_state != SESSION_STATE_LISTENING) { clib_warning ("not a listening session"); return -1; } - tc = tp_vfts[s->session_type].get_listener (s->connection_index); + tc = tp_vfts[tp].get_listener (s->connection_index); if (!tc) { clib_warning ("no transport"); @@ -917,7 +919,7 @@ stream_session_stop_listen (stream_session_t * s) } session_lookup_del_connection (tc); - tp_vfts[s->session_type].unbind (s->connection_index); + tp_vfts[tp].unbind (s->connection_index); return 0; } @@ -932,7 +934,8 @@ void stream_session_disconnect (stream_session_t * s) { s->session_state = SESSION_STATE_CLOSED; - tp_vfts[s->session_type].close (s->connection_index, s->thread_index); + tp_vfts[session_get_transport_proto (s)].close (s->connection_index, + s->thread_index); } /** @@ -953,7 +956,8 @@ stream_session_cleanup (stream_session_t * s) if (rv) clib_warning ("hash delete error, rv %d", rv); - tp_vfts[s->session_type].cleanup (s->connection_index, s->thread_index); + tp_vfts[session_get_transport_proto (s)].cleanup (s->connection_index, + s->thread_index); } /** @@ -985,49 +989,66 @@ session_vpp_event_queue_allocate (session_manager_main_t * smm, } } -session_type_t -session_type_from_proto_and_ip (transport_proto_t proto, u8 is_ip4) +/** + * Initialize session layer for given transport proto and ip version + * + * Allocates per session type (transport proto + ip version) data structures + * and adds arc from session queue node to session type output node. + */ +void +session_register_transport (transport_proto_t transport_proto, + const transport_proto_vft_t * vft, u8 is_ip4, + u32 output_node) { - if (proto == TRANSPORT_PROTO_TCP) - { - if (is_ip4) - return SESSION_TYPE_IP4_TCP; - else - return SESSION_TYPE_IP6_TCP; - } - else - { - if (is_ip4) - return SESSION_TYPE_IP4_UDP; - else - return SESSION_TYPE_IP6_UDP; - } + session_manager_main_t *smm = &session_manager_main; + session_type_t session_type; + u32 next_index = ~0; + + session_type = session_type_from_proto_and_ip (transport_proto, is_ip4); + + vec_validate (smm->session_type_to_next, session_type); + vec_validate (smm->listen_sessions, session_type); + vec_validate (smm->session_tx_fns, session_type); + + /* *INDENT-OFF* */ + foreach_vlib_main (({ + next_index = vlib_node_add_next (this_vlib_main, session_queue_node.index, + output_node); + })); + /* *INDENT-ON* */ - return SESSION_N_TYPES; + smm->session_type_to_next[session_type] = next_index; + session_manager_set_transport_rx_fn (session_type, + vft->tx_fifo_offset != 0); } transport_connection_t * session_get_transport (stream_session_t * s) { + transport_proto_t tp; if (s->session_state != SESSION_STATE_LISTENING) - return tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + { + tp = session_get_transport_proto (s); + return tp_vfts[tp].get_connection (s->connection_index, + s->thread_index); + } return 0; } transport_connection_t * listen_session_get_transport (stream_session_t * s) { - return tp_vfts[s->session_type].get_listener (s->connection_index); + transport_proto_t tp = session_get_transport_proto (s); + return tp_vfts[tp].get_listener (s->connection_index); } int listen_session_get_local_session_endpoint (stream_session_t * listener, session_endpoint_t * sep) { + transport_proto_t tp = session_get_transport_proto (listener); transport_connection_t *tc; - tc = - tp_vfts[listener->session_type].get_listener (listener->connection_index); + tc = tp_vfts[tp].get_listener (listener->connection_index); if (!tc) { clib_warning ("no transport"); @@ -1128,8 +1149,8 @@ session_manager_main_enable (vlib_main_t * vm) smm->is_enabled = 1; - /* Enable TCP transport */ - vnet_tcp_enable_disable (vm, 1); + /* Enable transports */ + transport_enable_disable (vm, 1); return 0; } diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h index d7bb18e4127..b76e56de50b 100644 --- a/src/vnet/session/session.h +++ b/src/vnet/session/session.h @@ -80,17 +80,6 @@ typedef enum SESSION_N_ERROR, } session_error_t; -/* Event queue input node static next indices */ -typedef enum -{ - SESSION_QUEUE_NEXT_DROP, - SESSION_QUEUE_NEXT_TCP_IP4_OUTPUT, - SESSION_QUEUE_NEXT_IP4_LOOKUP, - SESSION_QUEUE_NEXT_TCP_IP6_OUTPUT, - SESSION_QUEUE_NEXT_IP6_LOOKUP, - SESSION_QUEUE_N_NEXT, -} session_queue_next_t; - typedef struct { void *fp; @@ -137,7 +126,7 @@ struct _session_manager_main clib_spinlock_t *peekers_write_locks; /** Pool of listen sessions. Same type as stream sessions to ease lookups */ - stream_session_t *listen_sessions[SESSION_N_TYPES]; + stream_session_t **listen_sessions; /** Per-proto, per-worker enqueue epoch counters */ u32 *current_enqueue_epoch[TRANSPORT_N_PROTO]; @@ -164,7 +153,12 @@ struct _session_manager_main u32 unique_segment_name_counter; /** Per transport rx function that can either dequeue or peek */ - session_fifo_rx_fn *session_tx_fns[SESSION_N_TYPES]; + session_fifo_rx_fn **session_tx_fns; + + /** Per session type output nodes. Could optimize to group nodes by + * fib but lookup would then require session type parsing in session node. + * Trade memory for speed, for now */ + u32 *session_type_to_next; /** Session manager is enabled */ u8 is_enabled; @@ -285,6 +279,18 @@ session_get_from_handle (u64 handle) session_index_from_handle (handle)); } +always_inline transport_proto_t +session_get_transport_proto (stream_session_t * s) +{ + return (s->session_type >> 1); +} + +always_inline session_type_t +session_type_from_proto_and_ip (transport_proto_t proto, u8 is_ip4) +{ + return (proto << 1 | is_ip4); +} + /** * Acquires a lock that blocks a session pool from expanding. * @@ -443,10 +449,9 @@ uword unformat_stream_session (unformat_input_t * input, va_list * args); uword unformat_transport_connection (unformat_input_t * input, va_list * args); -int -send_session_connected_callback (u32 app_index, u32 api_context, - stream_session_t * s, u8 is_fail); - +void session_register_transport (transport_proto_t transport_proto, + const transport_proto_vft_t * vft, u8 is_ip4, + u32 output_node); clib_error_t *vnet_session_enable_disable (vlib_main_t * vm, u8 is_en); @@ -517,23 +522,25 @@ listen_session_get_local_session_endpoint (stream_session_t * listener, session_endpoint_t * sep); always_inline stream_session_t * -session_manager_get_listener (u8 type, u32 index) +session_manager_get_listener (u8 session_type, u32 index) { - return pool_elt_at_index (session_manager_main.listen_sessions[type], - index); + return + pool_elt_at_index (session_manager_main.listen_sessions[session_type], + index); } +/** + * Set peek or dequeue function for given session type + * + * Reliable transport protocols will probably want to use a peek function + */ always_inline void -session_manager_set_transport_rx_fn (u8 type, u8 is_peek) +session_manager_set_transport_rx_fn (session_type_t type, u8 is_peek) { - /* If an offset function is provided, then peek instead of dequeue */ session_manager_main.session_tx_fns[type] = (is_peek) ? session_tx_fifo_peek_and_snd : session_tx_fifo_dequeue_and_snd; } -session_type_t -session_type_from_proto_and_ip (transport_proto_t proto, u8 is_ip4); - always_inline u8 session_manager_is_enabled () { diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c index 7f1e69b058e..57f55eb0db8 100755 --- a/src/vnet/session/session_api.c +++ b/src/vnet/session/session_api.c @@ -103,7 +103,7 @@ send_session_accept_callback (stream_session_t * s) mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_ACCEPT_SESSION); mp->context = server->index; listener = listen_session_get (s->session_type, s->listener_index); - tp_vft = transport_protocol_get_vft (s->session_type); + tp_vft = transport_protocol_get_vft (session_get_transport_proto (s)); tc = tp_vft->get_connection (s->connection_index, s->thread_index); mp->listener_handle = listen_session_get_handle (listener); diff --git a/src/vnet/session/session_cli.c b/src/vnet/session/session_cli.c index 3423026147c..929e604b01e 100755 --- a/src/vnet/session/session_cli.c +++ b/src/vnet/session/session_cli.c @@ -55,7 +55,7 @@ format_stream_session (u8 * s, va_list * args) int verbose = va_arg (*args, int); transport_proto_vft_t *tp_vft; u8 *str = 0; - tp_vft = transport_protocol_get_vft (ss->session_type); + tp_vft = transport_protocol_get_vft (session_get_transport_proto (ss)); if (verbose == 1 && ss->session_state >= SESSION_STATE_ACCEPTING) str = format (0, "%-10u%-10u%-10lld", diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c index 2e4e96a4dea..68886a09456 100644 --- a/src/vnet/session/session_lookup.c +++ b/src/vnet/session/session_lookup.c @@ -127,10 +127,10 @@ make_v4_proxy_kv (session_kv4_t * kv, ip4_address_t * lcl, u8 proto) } always_inline void -make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * t) +make_v4_ss_kv_from_tc (session_kv4_t * kv, transport_connection_t * tc) { - make_v4_ss_kv (kv, &t->lcl_ip.ip4, &t->rmt_ip.ip4, t->lcl_port, t->rmt_port, - session_type_from_proto_and_ip (t->proto, 1)); + make_v4_ss_kv (kv, &tc->lcl_ip.ip4, &tc->rmt_ip.ip4, tc->lcl_port, + tc->rmt_port, tc->proto); } always_inline void @@ -187,10 +187,10 @@ make_v6_proxy_kv (session_kv6_t * kv, ip6_address_t * lcl, u8 proto) } always_inline void -make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * t) +make_v6_ss_kv_from_tc (session_kv6_t * kv, transport_connection_t * tc) { - make_v6_ss_kv (kv, &t->lcl_ip.ip6, &t->rmt_ip.ip6, t->lcl_port, t->rmt_port, - session_type_from_proto_and_ip (t->proto, 0)); + make_v6_ss_kv (kv, &tc->lcl_ip.ip6, &tc->rmt_ip.ip6, tc->lcl_port, + tc->rmt_port, tc->proto); } static session_table_t * @@ -372,9 +372,9 @@ session_lookup_del_connection (transport_connection_t * tc) int session_lookup_del_session (stream_session_t * s) { + transport_proto_t tp = session_get_transport_proto (s); transport_connection_t *ts; - ts = tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + ts = tp_vfts[tp].get_connection (s->connection_index, s->thread_index); return session_lookup_del_connection (ts); } @@ -472,9 +472,7 @@ session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep, session_table_t *st; u32 ai; int rv; - u8 sst; - sst = session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4); st = session_table_get (table_index); if (!st) return SESSION_INVALID_HANDLE; @@ -483,7 +481,8 @@ session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep, session_kv4_t kv4; ip4_address_t lcl4; - make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port, sst); + make_v4_listener_kv (&kv4, &sep->ip.ip4, sep->port, + sep->transport_proto); rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) return kv4.value; @@ -502,7 +501,8 @@ session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep, session_kv6_t kv6; ip6_address_t lcl6; - make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port, sst); + make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port, + sep->transport_proto); rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) return kv6.value; @@ -633,14 +633,16 @@ session_lookup_listener4_i (session_table_t * st, ip4_address_t * lcl, { session_kv4_t kv4; int rv; + session_type_t session_type; /* * First, try a fully formed listener */ + session_type = session_type_from_proto_and_ip (proto, 1); make_v4_listener_kv (&kv4, lcl, lcl_port, proto); rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv4.value); + return session_manager_get_listener (session_type, (u32) kv4.value); /* * Zero out the lcl ip and check if any 0/0 port binds have been done @@ -648,7 +650,7 @@ session_lookup_listener4_i (session_table_t * st, ip4_address_t * lcl, kv4.key[0] = 0; rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv4.value); + return session_manager_get_listener (session_type, (u32) kv4.value); /* * Zero out port and check if we have a proxy set up for our ip @@ -656,7 +658,7 @@ session_lookup_listener4_i (session_table_t * st, ip4_address_t * lcl, make_v4_proxy_kv (&kv4, lcl, proto); rv = clib_bihash_search_inline_16_8 (&st->v4_session_hash, &kv4); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv4.value); + return session_manager_get_listener (session_type, (u32) kv4.value); return 0; } @@ -678,22 +680,24 @@ session_lookup_listener6_i (session_table_t * st, ip6_address_t * lcl, { session_kv6_t kv6; int rv; + session_type_t session_type; + session_type = session_type_from_proto_and_ip (proto, 0); make_v6_listener_kv (&kv6, lcl, lcl_port, proto); rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv6.value); + return session_manager_get_listener (session_type, (u32) kv6.value); /* Zero out the lcl ip */ kv6.key[0] = kv6.key[1] = 0; rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv6.value); + return session_manager_get_listener (session_type, (u32) kv6.value); make_v6_proxy_kv (&kv6, lcl, proto); rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) - return session_manager_get_listener (proto, (u32) kv6.value); + return session_manager_get_listener (session_type, (u32) kv6.value); return 0; } @@ -869,8 +873,8 @@ session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl, { ASSERT ((u32) (kv4.value >> 32) == thread_index); s = session_get (kv4.value & 0xFFFFFFFFULL, thread_index); - return tp_vfts[s->session_type].get_connection (s->connection_index, - thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + thread_index); } /* @@ -878,10 +882,7 @@ session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl, */ rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4); if (rv == 0) - { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF); - } + return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF); /* * Check the session rules table @@ -894,7 +895,7 @@ session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl, return 0; if ((s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4, proto))) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } @@ -903,7 +904,7 @@ session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl, */ s = session_lookup_listener4_i (st, lcl, lcl_port, proto); if (s) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } @@ -947,8 +948,8 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl, if (rv == 0) { s = session_get_from_handle (kv4.value); - return tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + s->thread_index); } /* @@ -956,10 +957,7 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl, */ rv = clib_bihash_search_inline_16_8 (&st->v4_half_open_hash, &kv4); if (rv == 0) - { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv4.value & 0xFFFFFFFF); - } + return tp_vfts[proto].get_half_open (kv4.value & 0xFFFFFFFF); /* * Check the session rules table @@ -972,7 +970,7 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl, return 0; if ((s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4, proto))) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } @@ -981,7 +979,7 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl, */ s = session_lookup_listener4_i (st, lcl, lcl_port, proto); if (s) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } @@ -1090,17 +1088,14 @@ session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl, { ASSERT ((u32) (kv6.value >> 32) == thread_index); s = session_get (kv6.value & 0xFFFFFFFFULL, thread_index); - return tp_vfts[s->session_type].get_connection (s->connection_index, - thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + thread_index); } /* Try half-open connections */ rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6); if (rv == 0) - { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF); - } + return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF); /* Check the session rules table */ action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl, @@ -1111,14 +1106,14 @@ session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl, return 0; if ((s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6, proto))) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } /* If nothing is found, check if any listener is available */ s = session_lookup_listener6_i (st, lcl, lcl_port, proto); if (s) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } @@ -1159,17 +1154,14 @@ session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl, if (rv == 0) { s = session_get_from_handle (kv6.value); - return tp_vfts[s->session_type].get_connection (s->connection_index, - s->thread_index); + return tp_vfts[proto].get_connection (s->connection_index, + s->thread_index); } /* Try half-open connections */ rv = clib_bihash_search_inline_48_8 (&st->v6_half_open_hash, &kv6); if (rv == 0) - { - u32 sst = session_type_from_proto_and_ip (proto, 1); - return tp_vfts[sst].get_half_open (kv6.value & 0xFFFFFFFF); - } + return tp_vfts[proto].get_half_open (kv6.value & 0xFFFFFFFF); /* Check the session rules table */ action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl, @@ -1180,14 +1172,14 @@ session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl, return 0; if ((s = session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6, proto))) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } /* If nothing is found, check if any listener is available */ s = session_lookup_listener6 (fib_index, lcl, lcl_port, proto); if (s) - return tp_vfts[s->session_type].get_listener (s->connection_index); + return tp_vfts[proto].get_listener (s->connection_index); return 0; } @@ -1344,22 +1336,22 @@ format_ip4_session_lookup_kvp (u8 * s, va_list * args) stream_session_t *session; v4_connection_key_t *key = (v4_connection_key_t *) kvp->key; - char *proto = key->proto == TRANSPORT_PROTO_TCP ? "T" : "U"; if (!is_local) { session = session_get_from_handle (kvp->value); app_name = application_name_from_index (session->app_index); - str = format (0, "[%s] %U:%d->%U:%d", proto, format_ip4_address, - &key->src, clib_net_to_host_u16 (key->src_port), - format_ip4_address, &key->dst, - clib_net_to_host_u16 (key->dst_port)); + str = format (0, "[%U] %U:%d->%U:%d", format_transport_proto_short, + key->proto, format_ip4_address, &key->src, + clib_net_to_host_u16 (key->src_port), format_ip4_address, + &key->dst, clib_net_to_host_u16 (key->dst_port)); s = format (s, "%-40v%-30v", str, app_name); } else { app_name = application_name_from_index (kvp->value); - str = format (0, "[%s] %U:%d", proto, format_ip4_address, - &key->src, clib_net_to_host_u16 (key->src_port)); + str = format (0, "[%U] %U:%d", format_transport_proto_short, key->proto, + format_ip4_address, &key->src, + clib_net_to_host_u16 (key->src_port)); s = format (s, "%-30v%-30v", str, app_name); } vec_free (app_name); diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index 08baa447864..e9cfc7be8aa 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -16,8 +16,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -64,13 +64,6 @@ static char *session_queue_error_strings[] = { #undef _ }; -static u32 session_type_to_next[] = { - SESSION_QUEUE_NEXT_TCP_IP4_OUTPUT, - SESSION_QUEUE_NEXT_IP4_LOOKUP, - SESSION_QUEUE_NEXT_TCP_IP6_OUTPUT, - SESSION_QUEUE_NEXT_IP6_LOOKUP, -}; - always_inline void session_tx_fifo_chain_tail (session_manager_main_t * smm, vlib_main_t * vm, u8 thread_index, svm_fifo_t * fifo, @@ -143,6 +136,7 @@ session_tx_fifo_read_and_snd_i (vlib_main_t * vm, vlib_node_runtime_t * node, u32 n_bufs_per_evt, n_frames_per_evt, n_bufs_per_frame; transport_connection_t *tc0; transport_proto_vft_t *transport_vft; + transport_proto_t tp; u32 next_index, next0, *to_next, n_left_to_next, bi0; vlib_buffer_t *b0; u32 tx_offset = 0, max_dequeue0, n_bytes_per_seg, left_for_seg; @@ -152,9 +146,10 @@ session_tx_fifo_read_and_snd_i (vlib_main_t * vm, vlib_node_runtime_t * node, u32 n_bytes_per_buf, deq_per_buf, deq_per_first_buf; u32 buffers_allocated, buffers_allocated_this_call; - next_index = next0 = session_type_to_next[s0->session_type]; + next_index = next0 = smm->session_type_to_next[s0->session_type]; - transport_vft = transport_protocol_get_vft (s0->session_type); + tp = session_get_transport_proto (s0); + transport_vft = transport_protocol_get_vft (tp); tc0 = transport_vft->get_connection (s0->connection_index, thread_index); /* Make sure we have space to send and there's something to dequeue */ @@ -325,7 +320,6 @@ session_tx_fifo_read_and_snd_i (vlib_main_t * vm, vlib_node_runtime_t * node, /* *INDENT-ON* */ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - tcp_trajectory_add_start (b0, 3); if (PREDICT_FALSE (n_trace > 0)) { @@ -550,9 +544,9 @@ session_queue_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, SESSION_EVT_DBG (SESSION_EVT_POLL_GAP_TRACK, smm, my_thread_index); /* - * Update TCP time + * Update transport time */ - tcp_update_time (now, my_thread_index); + transport_update_time (now, my_thread_index); /* * Get vpp queue events @@ -695,16 +689,7 @@ VLIB_REGISTER_NODE (session_queue_node) = .type = VLIB_NODE_TYPE_INPUT, .n_errors = ARRAY_LEN (session_queue_error_strings), .error_strings = session_queue_error_strings, - .n_next_nodes = SESSION_QUEUE_N_NEXT, .state = VLIB_NODE_STATE_DISABLED, - .next_nodes = - { - [SESSION_QUEUE_NEXT_DROP] = "error-drop", - [SESSION_QUEUE_NEXT_IP4_LOOKUP] = "ip4-lookup", - [SESSION_QUEUE_NEXT_IP6_LOOKUP] = "ip6-lookup", - [SESSION_QUEUE_NEXT_TCP_IP4_OUTPUT] = "tcp4-output", - [SESSION_QUEUE_NEXT_TCP_IP6_OUTPUT] = "tcp6-output", - }, }; /* *INDENT-ON* */ diff --git a/src/vnet/session/stream_session.h b/src/vnet/session/stream_session.h index 51d5065059b..b484efefa01 100644 --- a/src/vnet/session/stream_session.h +++ b/src/vnet/session/stream_session.h @@ -20,19 +20,7 @@ #include #include -#define foreach_session_type \ - _(IP4_TCP, ip4_tcp) \ - _(IP4_UDP, ip4_udp) \ - _(IP6_TCP, ip6_tcp) \ - _(IP6_UDP, ip6_udp) - -typedef enum -{ -#define _(A, a) SESSION_TYPE_##A, - foreach_session_type -#undef _ - SESSION_N_TYPES, -} session_type_t; +typedef u8 session_type_t; /* * Application session state @@ -55,7 +43,7 @@ typedef struct _stream_session_t svm_fifo_t *server_tx_fifo; /** Type */ - u8 session_type; + session_type_t session_type; /** State */ volatile u8 session_state; diff --git a/src/vnet/session/transport.c b/src/vnet/session/transport.c index b0a5906383d..2f01ac6c092 100644 --- a/src/vnet/session/transport.c +++ b/src/vnet/session/transport.c @@ -58,6 +58,22 @@ format_transport_proto (u8 * s, va_list * args) return s; } +u8 * +format_transport_proto_short (u8 * s, va_list * args) +{ + u32 transport_proto = va_arg (*args, u32); + switch (transport_proto) + { + case TRANSPORT_PROTO_TCP: + s = format (s, "T"); + break; + case TRANSPORT_PROTO_UDP: + s = format (s, "U"); + break; + } + return s; +} + uword unformat_transport_proto (unformat_input_t * input, va_list * args) { @@ -123,22 +139,23 @@ transport_endpoint_table_del (transport_endpoint_table_t * ht, u8 proto, /** * Register transport virtual function table. * - * @param type - session type (not protocol type) - * @param vft - virtual function table + * @param transport_proto - transport protocol type (i.e., TCP, UDP ..) + * @param vft - virtual function table for transport proto + * @param fib_proto - network layer protocol + * @param output_node - output node index that session layer will hand off + * buffers to, for requested fib proto */ void -transport_register_protocol (transport_proto_t transport_proto, u8 is_ip4, - const transport_proto_vft_t * vft) +transport_register_protocol (transport_proto_t transport_proto, + const transport_proto_vft_t * vft, + fib_protocol_t fib_proto, u32 output_node) { - u8 session_type; - session_type = session_type_from_proto_and_ip (transport_proto, is_ip4); + u8 is_ip4 = fib_proto == FIB_PROTOCOL_IP4; - vec_validate (tp_vfts, session_type); - tp_vfts[session_type] = *vft; + vec_validate (tp_vfts, transport_proto); + tp_vfts[transport_proto] = *vft; - /* If an offset function is provided, then peek instead of dequeue */ - session_manager_set_transport_rx_fn (session_type, - vft->tx_fifo_offset != 0); + session_register_transport (transport_proto, vft, is_ip4, output_node); } /** @@ -147,11 +164,11 @@ transport_register_protocol (transport_proto_t transport_proto, u8 is_ip4, * @param type - session type (not protocol type) */ transport_proto_vft_t * -transport_protocol_get_vft (u8 session_type) +transport_protocol_get_vft (transport_proto_t transport_proto) { - if (session_type >= vec_len (tp_vfts)) + if (transport_proto >= vec_len (tp_vfts)) return 0; - return &tp_vfts[session_type]; + return &tp_vfts[transport_proto]; } #define PORT_MASK ((1 << 16)- 1) @@ -310,6 +327,28 @@ transport_alloc_local_endpoint (u8 proto, transport_endpoint_t * rmt, return 0; } +void +transport_update_time (f64 time_now, u8 thread_index) +{ + transport_proto_vft_t *vft; + vec_foreach (vft, tp_vfts) + { + if (vft->update_time) + (vft->update_time) (time_now, thread_index); + } +} + +void +transport_enable_disable (vlib_main_t * vm, u8 is_en) +{ + transport_proto_vft_t *vft; + vec_foreach (vft, tp_vfts) + { + if (vft->enable) + (vft->enable) (vm, is_en); + } +} + void transport_init (void) { diff --git a/src/vnet/session/transport.h b/src/vnet/session/transport.h index 822dc8317f1..61a2b7b8aa6 100644 --- a/src/vnet/session/transport.h +++ b/src/vnet/session/transport.h @@ -74,6 +74,7 @@ typedef enum _transport_proto } transport_proto_t; u8 *format_transport_proto (u8 * s, va_list * args); +u8 *format_transport_proto_short (u8 * s, va_list * args); uword unformat_transport_proto (unformat_input_t * input, va_list * args); #define foreach_transport_connection_fields \ diff --git a/src/vnet/session/transport_interface.h b/src/vnet/session/transport_interface.h index 079e6464268..09542e6a6aa 100644 --- a/src/vnet/session/transport_interface.h +++ b/src/vnet/session/transport_interface.h @@ -32,6 +32,7 @@ typedef struct _transport_proto_vft int (*open) (transport_endpoint_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); /* * Transmission @@ -40,6 +41,7 @@ typedef struct _transport_proto_vft u16 (*send_mss) (transport_connection_t * tc); u32 (*send_space) (transport_connection_t * tc); u32 (*tx_fifo_offset) (transport_connection_t * tc); + void (*update_time) (f64 time_now, u8 thread_index); /* * Connection retrieval @@ -56,10 +58,21 @@ typedef struct _transport_proto_vft u8 *(*format_half_open) (u8 * s, va_list * args); } transport_proto_vft_t; +extern transport_proto_vft_t *tp_vfts; + +#define transport_proto_foreach(VAR, BODY) \ +do { \ + for (VAR = 0; VAR < vec_len (tp_vfts); VAR++) \ + if (tp_vfts[VAR].push_header != 0) \ + do { BODY; } while (0); \ +} while (0) + void transport_register_protocol (transport_proto_t transport_proto, - u8 is_ip4, - const transport_proto_vft_t * vft); -transport_proto_vft_t *transport_protocol_get_vft (u8 session_type); + const transport_proto_vft_t * vft, + fib_protocol_t fib_proto, u32 output_node); +transport_proto_vft_t *transport_protocol_get_vft (transport_proto_t tp); +void transport_update_time (f64 time_now, u8 thread_index); +void transport_enable_disable (vlib_main_t * vm, u8 is_en); #endif /* SRC_VNET_SESSION_TRANSPORT_INTERFACE_H_ */ diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index aee18d997e0..8d222e3c684 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -1009,8 +1009,18 @@ tcp_session_tx_fifo_offset (transport_connection_t * trans_conn) return (tc->snd_nxt - tc->snd_una); } +void +tcp_update_time (f64 now, u8 thread_index) +{ + tcp_set_time_now (thread_index); + tw_timer_expire_timers_16t_2w_512sl (&tcp_main.timer_wheels[thread_index], + now); + tcp_flush_frames_to_output (thread_index); +} + /* *INDENT-OFF* */ const static transport_proto_vft_t tcp_proto = { + .enable = vnet_tcp_enable_disable, .bind = tcp_session_bind, .unbind = tcp_session_unbind, .push_header = tcp_push_header, @@ -1022,6 +1032,7 @@ const static transport_proto_vft_t tcp_proto = { .cleanup = tcp_session_cleanup, .send_mss = tcp_session_send_mss, .send_space = tcp_session_send_space, + .update_time = tcp_update_time, .tx_fifo_offset = tcp_session_tx_fifo_offset, .format_connection = format_tcp_session, .format_listener = format_tcp_listener_session, @@ -1173,10 +1184,6 @@ tcp_main_enable (vlib_main_t * vm) ip4_register_protocol (IP_PROTOCOL_TCP, tcp4_input_node.index); ip6_register_protocol (IP_PROTOCOL_TCP, tcp6_input_node.index); - /* Register as transport with session layer */ - transport_register_protocol (TRANSPORT_PROTO_TCP, 1, &tcp_proto); - transport_register_protocol (TRANSPORT_PROTO_TCP, 0, &tcp_proto); - /* * Initialize data structures */ @@ -1287,6 +1294,12 @@ tcp_init (vlib_main_t * vm) pi->format_header = format_tcp_header; pi->unformat_pg_edit = unformat_pg_tcp_header; + /* Register as transport with session layer */ + transport_register_protocol (TRANSPORT_PROTO_TCP, &tcp_proto, + FIB_PROTOCOL_IP4, tcp4_output_node.index); + transport_register_protocol (TRANSPORT_PROTO_TCP, &tcp_proto, + FIB_PROTOCOL_IP6, tcp6_output_node.index); + tcp_api_reference (); return 0; } diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h index a7ae74e06ed..9606a0e1d15 100644 --- a/src/vnet/tcp/tcp.h +++ b/src/vnet/tcp/tcp.h @@ -665,15 +665,6 @@ tcp_set_time_now (u32 thread_index) return tcp_main.time_now[thread_index]; } -always_inline void -tcp_update_time (f64 now, u32 thread_index) -{ - tcp_set_time_now (thread_index); - tw_timer_expire_timers_16t_2w_512sl (&tcp_main.timer_wheels[thread_index], - now); - tcp_flush_frames_to_output (thread_index); -} - u32 tcp_push_header (transport_connection_t * tconn, vlib_buffer_t * b); u32 diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index dd5b384b0c9..0eef942da83 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -1973,6 +1973,7 @@ tcp_push_header (transport_connection_t * tconn, vlib_buffer_t * b) tc->rtt_ts = tcp_time_now (); tc->rtt_seq = tc->snd_nxt; } + tcp_trajectory_add_start (b0, 3); return 0; } diff --git a/src/vnet/udp/udp.c b/src/vnet/udp/udp.c index 70091655211..9284cd7b269 100644 --- a/src/vnet/udp/udp.c +++ b/src/vnet/udp/udp.c @@ -354,10 +354,11 @@ udp_init (vlib_main_t * vm) pi->format_header = format_udp_header; pi->unformat_pg_edit = unformat_pg_udp_header; - /* Register as transport with URI */ - transport_register_protocol (TRANSPORT_PROTO_UDP, 1, &udp_proto); - transport_register_protocol (TRANSPORT_PROTO_UDP, 0, &udp_proto); + transport_register_protocol (TRANSPORT_PROTO_UDP, &udp_proto, + FIB_PROTOCOL_IP4, ip4_lookup_node.index); + transport_register_protocol (TRANSPORT_PROTO_UDP, &udp_proto, + FIB_PROTOCOL_IP6, ip6_lookup_node.index); /* * Initialize data structures -- 2.16.6